Merge "Expose FUSED_PROVIDER to test API."
diff --git a/Android.bp b/Android.bp
index c74b458..e50161c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -225,7 +225,6 @@
         ":framework-mca-filterfw-sources",
         ":framework-mca-filterpacks-sources",
         ":framework-media-sources",
-        ":framework-mime-sources",
         ":framework-mms-sources",
         ":framework-opengl-sources",
         ":framework-rs-sources",
@@ -254,6 +253,8 @@
         ":libcamera_client_aidl",
         ":libcamera_client_framework_aidl",
         ":libupdate_engine_aidl",
+        // TODO: this needs to be removed when statsd-framework.jar is separated out
+        ":statsd_aidl",
         ":storaged_aidl",
         ":vold_aidl",
 
@@ -267,10 +268,19 @@
 }
 
 filegroup {
+    name: "framework-updatable-sources",
+    srcs: [
+        ":framework-sdkext-sources",
+        ":updatable-media-srcs",
+    ]
+}
+
+filegroup {
     name: "framework-all-sources",
     srcs: [
+        ":framework-mime-sources",
         ":framework-non-updatable-sources",
-        ":updatable-media-srcs",
+        ":framework-updatable-sources",
     ],
 }
 
@@ -319,12 +329,14 @@
         "android.hardware.cas-V1.1-java",
         "android.hardware.cas-V1.0-java",
         "android.hardware.contexthub-V1.0-java",
+        "android.hardware.gnss-V1.0-java",
         "android.hardware.health-V1.0-java-constants",
         "android.hardware.radio-V1.0-java",
         "android.hardware.radio-V1.1-java",
         "android.hardware.radio-V1.2-java",
         "android.hardware.radio-V1.3-java",
         "android.hardware.radio-V1.4-java",
+        "android.hardware.radio-V1.5-java",
         "android.hardware.thermal-V1.0-java-constants",
         "android.hardware.thermal-V1.0-java",
         "android.hardware.thermal-V1.1-java",
@@ -362,7 +374,7 @@
 
     exclude_srcs: [
         // See comment on framework-atb-backward-compatibility module below
-        "core/java/android/content/pm/AndroidTestBaseUpdater.java",
+        "core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java",
     ],
 
     sdk_version: "core_platform",
@@ -375,7 +387,6 @@
 
     static_libs: [
         "framework-internal-utils",
-        "mimemap",
     ],
 
     dxflags: [
@@ -404,18 +415,6 @@
 }
 
 filegroup {
-    name: "statsd_aidl",
-    srcs: [
-        "core/java/android/os/IPullAtomCallback.aidl",
-        "core/java/android/os/IPullAtomResultReceiver.aidl",
-        "core/java/android/os/IStatsCompanionService.aidl",
-        "core/java/android/os/IStatsManager.aidl",
-        "core/java/android/os/IStatsPullerCallback.aidl",
-    ],
-    path: "core/java",
-}
-
-filegroup {
     name: "libvibrator_aidl",
     srcs: [
         "core/java/android/os/IExternalVibrationController.aidl",
@@ -437,6 +436,12 @@
         "services-platform-compat-config",
         "media-provider-platform-compat-config",
         "services-devicepolicy-platform-compat-config",
+        "services-core-platform-compat-config",
+    ],
+    static_libs: [
+        // If MimeMap ever becomes its own APEX, then this dependency would need to be removed
+        // in favor of an API stubs dependency in java_library "framework" below.
+        "mimemap",
     ],
     // For backwards compatibility.
     stem: "framework",
@@ -521,7 +526,7 @@
     installable: true,
     libs: ["app-compat-annotations"],
     srcs: [
-        "core/java/android/content/pm/AndroidTestBaseUpdater.java",
+        "core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java",
     ],
 }
 
@@ -566,12 +571,19 @@
         "core/java/android/annotation/Nullable.java",
         "core/java/android/annotation/IntDef.java",
         "core/java/android/annotation/IntRange.java",
+        "core/java/android/annotation/SystemApi.java",
         "core/java/android/annotation/UnsupportedAppUsage.java",
         "core/java/com/android/internal/annotations/GuardedBy.java",
         "core/java/com/android/internal/annotations/VisibleForTesting.java",
     ],
 }
 
+java_library {
+    name: "framework-annotations-lib",
+    srcs: [ ":framework-annotations" ],
+    sdk_version: "current",
+}
+
 filegroup {
     name: "framework-networkstack-shared-srcs",
     srcs: [
@@ -772,7 +784,7 @@
 filegroup {
     name: "incremental_aidl",
     srcs: [
-        "core/java/android/os/incremental/IIncrementalService.aidl",
+        "core/java/android/os/incremental/IIncrementalManager.aidl",
         "core/java/android/os/incremental/IIncrementalServiceProxy.aidl",
         "core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl",
         "core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl",
@@ -782,10 +794,9 @@
 }
 
 filegroup {
-    name: "incremental_data_loader_aidl",
+    name: "dataloader_aidl",
     srcs: [
-        "core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl",
-        "core/java/android/service/incremental/IIncrementalDataLoaderService.aidl",
+        "core/java/android/content/pm/IDataLoaderStatusListener.aidl",
     ],
     path: "core/java",
 }
@@ -794,7 +805,27 @@
     name: "libincremental_aidl",
     srcs: [
         ":incremental_aidl",
-        ":incremental_data_loader_aidl",
+    ],
+    imports: [
+        "libdataloader_aidl",
+    ],
+    backend: {
+        java: {
+            sdk_version: "28",
+        },
+        cpp: {
+            enabled: true,
+        },
+        ndk: {
+            enabled: true,
+        },
+    },
+}
+
+aidl_interface {
+    name: "libdataloader_aidl",
+    srcs: [
+        ":dataloader_aidl",
     ],
     backend: {
         java: {
@@ -1015,14 +1046,15 @@
 stubs_defaults {
     name: "framework-doc-stubs-default",
     srcs: [
+        ":framework-mime-sources",
         ":framework-non-updatable-sources",
+        ":framework-updatable-sources",
         "core/java/**/*.logtags",
         "test-base/src/**/*.java",
         ":opt-telephony-srcs",
         ":opt-net-voip-srcs",
         ":core-current-stubs-source",
         ":core_public_api_files",
-        ":updatable-media-srcs",
         "test-mock/src/**/*.java",
         "test-runner/src/**/*.java",
     ],
@@ -1034,7 +1066,7 @@
         "sdk-dir",
         "api-versions-jars-dir",
     ],
-    previous_api: ":last-released-public-api-for-metalava-annotations",
+    previous_api: ":last-released-public-api",
     merge_annotations_dirs: [
         "metalava-manual",
     ],
@@ -1080,18 +1112,18 @@
     name: "metalava-api-stubs-default",
     srcs: [
         ":framework-non-updatable-sources",
+        ":framework-updatable-sources",
         "core/java/**/*.logtags",
         ":opt-telephony-srcs",
         ":opt-net-voip-srcs",
         ":core-current-stubs-source",
         ":core_public_api_files",
-        ":updatable-media-srcs",
         ":ike-api-srcs",
     ],
     libs: ["framework-internal-utils"],
     installable: false,
     annotations_enabled: true,
-    previous_api: ":last-released-public-api-for-metalava-annotations",
+    previous_api: ":last-released-public-api",
     merge_annotations_dirs: [
         "metalava-manual",
     ],
@@ -1427,7 +1459,7 @@
     installable: false,
     sdk_version: "core_platform",
     annotations_enabled: true,
-    previous_api: ":last-released-public-api-for-metalava-annotations",
+    previous_api: ":last-released-public-api",
     merge_annotations_dirs: [
         "metalava-manual",
     ],
@@ -1611,18 +1643,16 @@
         "core/java/android/os/RegistrantList.java",
         "core/java/android/os/Registrant.java",
         "core/java/android/util/LocalLog.java",
-        "core/java/android/util/Slog.java",
         "core/java/android/util/TimeUtils.java",
         "core/java/com/android/internal/os/SomeArgs.java",
-        "core/java/com/android/internal/util/DumpUtils.java",
         "core/java/com/android/internal/util/FastXmlSerializer.java",
         "core/java/com/android/internal/util/HexDump.java",
+        "core/java/com/android/internal/util/IState.java",
         "core/java/com/android/internal/util/IndentingPrintWriter.java",
         "core/java/com/android/internal/util/Preconditions.java",
         "core/java/com/android/internal/util/State.java",
         "core/java/com/android/internal/util/StateMachine.java",
         "core/java/com/android/internal/util/UserIcons.java",
-        "core/java/com/android/internal/util/XmlUtils.java",
     ],
 }
 
@@ -1631,8 +1661,10 @@
 filegroup {
     name: "framework-cellbroadcast-shared-srcs",
     srcs: [
+        "core/java/android/os/HandlerExecutor.java",
         "core/java/android/util/LocalLog.java",
-        "core/java/android/util/Slog.java",
+        "core/java/com/android/internal/util/IState.java",
+        "core/java/com/android/internal/util/Preconditions.java",
         "core/java/com/android/internal/util/State.java",
         "core/java/com/android/internal/util/StateMachine.java",
     ],
@@ -1649,15 +1681,13 @@
 }
 
 filegroup {
-    name: "framework-wifistack-shared-srcs",
+    name: "framework-wifi-service-shared-srcs",
     srcs: [
         ":framework-annotations",
 	"core/java/android/os/HandlerExecutor.java",
-        "core/java/android/util/KeyValueListParser.java",
+        "core/java/android/util/BackupUtils.java",
         "core/java/android/util/LocalLog.java",
         "core/java/android/util/Rational.java",
-        "core/java/android/util/proto/ProtoStream.java",
-        "core/java/android/util/proto/ProtoOutputStream.java",
         "core/java/com/android/internal/util/FastXmlSerializer.java",
         "core/java/com/android/internal/util/HexDump.java",
         "core/java/com/android/internal/util/IState.java",
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..2b12da2
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,61 @@
+{
+  "presubmit": [
+    {
+      "name": "FrameworksUiServicesTests",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
+      "name": "ExtServicesUnitTests",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
+      "name": "TestablesTests",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
+      "name": "FrameworksCoreTests",
+      "options": [
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        }
+      ]
+    },
+    {
+      "name": "FrameworksServicesTests",
+      "options": [
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        }
+      ]
+    }
+  ],
+  "postsubmit-managedprofile-stress": [
+    {
+      "name": "ManagedProfileLifecycleStressTest"
+    }
+  ]
+}
diff --git a/apex/appsearch/Android.bp b/apex/appsearch/Android.bp
new file mode 100644
index 0000000..bcdcc7d
--- /dev/null
+++ b/apex/appsearch/Android.bp
@@ -0,0 +1,35 @@
+// 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",
+
+    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
new file mode 100644
index 0000000..273b867
--- /dev/null
+++ b/apex/appsearch/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+  "name": "com.android.appsearch",
+  "version": 1
+}
diff --git a/apex/appsearch/com.android.appsearch.avbpubkey b/apex/appsearch/com.android.appsearch.avbpubkey
new file mode 100644
index 0000000..4e5acae
--- /dev/null
+++ b/apex/appsearch/com.android.appsearch.avbpubkey
Binary files differ
diff --git a/apex/appsearch/com.android.appsearch.pem b/apex/appsearch/com.android.appsearch.pem
new file mode 100644
index 0000000..4ed5945
--- /dev/null
+++ b/apex/appsearch/com.android.appsearch.pem
@@ -0,0 +1,51 @@
+-----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
new file mode 100644
index 0000000..77e98b2
--- /dev/null
+++ b/apex/appsearch/com.android.appsearch.pk8
Binary files differ
diff --git a/apex/appsearch/com.android.appsearch.x509.pem b/apex/appsearch/com.android.appsearch.x509.pem
new file mode 100644
index 0000000..e37c4b9
--- /dev/null
+++ b/apex/appsearch/com.android.appsearch.x509.pem
@@ -0,0 +1,35 @@
+-----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/java/android/app/TEST_MAPPING b/apex/appsearch/framework/java/android/app/TEST_MAPPING
new file mode 100644
index 0000000..12188f8
--- /dev/null
+++ b/apex/appsearch/framework/java/android/app/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "imports": [
+    {
+      "path": "frameworks/base/apex/appsearch/service/java/com/android/server/appsearch"
+    }
+  ]
+}
diff --git a/apex/appsearch/service/Android.bp b/apex/appsearch/service/Android.bp
index 2cd7aa0..4ebafce8 100644
--- a/apex/appsearch/service/Android.bp
+++ b/apex/appsearch/service/Android.bp
@@ -21,4 +21,7 @@
     "framework",
     "services.core",
   ],
+  static_libs: [
+    "icing-java-proto-lite",
+  ]
 }
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/TEST_MAPPING b/apex/appsearch/service/java/com/android/server/appsearch/TEST_MAPPING
new file mode 100644
index 0000000..08811f8
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsAppSearchTestCases"
+    },
+    {
+      "name": "FrameworksServicesTests",
+      "options": [
+        {
+          "include-filter": "com.android.server.appsearch"
+        }
+      ]
+    }
+  ]
+}
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
new file mode 100644
index 0000000..3dbb5cf
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java
@@ -0,0 +1,168 @@
+/*
+ * 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 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.
+ *
+ * @hide
+ */
+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);
+        if (docIds == null || docIds.isEmpty()) {
+            return SearchResultProto.getDefaultInstance();
+        }
+        SearchResultProto.Builder results = SearchResultProto.newBuilder();
+        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/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java b/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java
index 3835d93..0c4fcb4 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java
@@ -16,6 +16,7 @@
 
 package android.app.job;
 
+import android.annotation.SystemApi;
 import android.app.JobSchedulerImpl;
 import android.app.SystemServiceRegistry;
 import android.content.Context;
@@ -28,6 +29,7 @@
  *
  * @hide
  */
+@SystemApi
 public class JobSchedulerFrameworkInitializer {
     private JobSchedulerFrameworkInitializer() {
     }
@@ -38,8 +40,6 @@
      * {@link Context#getSystemService} can return them.
      *
      * <p>If this is called from other places, it throws a {@link IllegalStateException).
-     *
-     * TODO Make it a system API
      */
     public static void registerServiceWrappers() {
         SystemServiceRegistry.registerStaticService(
diff --git a/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java b/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java
index 8019d4f..4c44334 100644
--- a/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java
+++ b/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java
@@ -17,13 +17,10 @@
 package android.os;
 
 import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
 import android.content.Context;
 
-import java.util.List;
-
 /**
  * Access to the service that keeps track of device idleness and drives low power mode based on
  * that.
@@ -75,21 +72,6 @@
     }
 
     /**
-     * Add the specified packages to the power save whitelist.
-     *
-     * @return the number of packages that were successfully added to the whitelist
-     */
-    @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
-    public int addPowerSaveWhitelistApps(@NonNull List<String> packageNames) {
-        try {
-            return mService.addPowerSaveWhitelistApps(packageNames);
-        } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-            return 0;
-        }
-    }
-
-    /**
      * Return whether a given package is in the power-save whitelist or not.
      * @hide
      */
diff --git a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
index 7a3ed92..4ffcf8a 100644
--- a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
+++ b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
@@ -26,6 +26,8 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * Interface to access and modify the power save whitelist.
@@ -78,6 +80,31 @@
     }
 
     /**
+     * Add the specified package to the power save whitelist.
+     *
+     * @return true if the package was successfully added to the whitelist
+     */
+    @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
+    public boolean addToWhitelist(@NonNull String packageName) {
+        return addToWhitelist(Collections.singletonList(packageName)) == 1;
+    }
+
+    /**
+     * Add the specified packages to the power save whitelist.
+     *
+     * @return the number of packages that were successfully added to the whitelist
+     */
+    @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
+    public int addToWhitelist(@NonNull List<String> packageNames) {
+        try {
+            return mService.addPowerSaveWhitelistApps(packageNames);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+            return 0;
+        }
+    }
+
+    /**
      * Add an app to the temporary whitelist for a short amount of time.
      *
      * @param packageName The package to add to the temp whitelist
diff --git a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
index eefb9fa..1072406 100644
--- a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
@@ -94,7 +94,7 @@
         /**
          * Write the persist stats to the specified field.
          */
-        public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        public void dumpDebug(ProtoOutputStream proto, long fieldId) {
             final long token = proto.start(fieldId);
 
             final long flToken = proto.start(JobStorePersistStatsProto.FIRST_LOAD);
diff --git a/apex/jobscheduler/service/java/com/android/server/AnyMotionDetector.java b/apex/jobscheduler/service/java/com/android/server/AnyMotionDetector.java
index 8c5ee7f..316306d 100644
--- a/apex/jobscheduler/service/java/com/android/server/AnyMotionDetector.java
+++ b/apex/jobscheduler/service/java/com/android/server/AnyMotionDetector.java
@@ -231,8 +231,8 @@
                 Slog.d(TAG, "mCurrentGravityVector = " + currentGravityVectorString);
                 Slog.d(TAG, "mPreviousGravityVector = " + previousGravityVectorString);
             }
-            mRunningStats.reset();
             status = getStationaryStatus();
+            mRunningStats.reset();
             if (DEBUG) Slog.d(TAG, "getStationaryStatus() returned " + status);
             if (status != RESULT_UNKNOWN) {
                 if (mWakeLock.isHeld()) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 0a4e020..1ec96ec 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -2689,7 +2689,7 @@
         }
 
         @Override
-        protected int handleShellCommand(@NonNull ParcelFileDescriptor in,
+        public int handleShellCommand(@NonNull ParcelFileDescriptor in,
                 @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
                 @NonNull String[] args) {
             return (new JobSchedulerShellCommand(JobSchedulerService.this)).exec(
@@ -3345,7 +3345,7 @@
             mConcurrencyManager.dumpProtoLocked(proto,
                     JobSchedulerServiceDumpProto.CONCURRENCY_MANAGER, now, nowElapsed);
 
-            mJobs.getPersistStats().writeToProto(proto, JobSchedulerServiceDumpProto.PERSIST_STATS);
+            mJobs.getPersistStats().dumpDebug(proto, JobSchedulerServiceDumpProto.PERSIST_STATS);
         }
 
         proto.flush();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index 7d36303..8eeea1b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -639,7 +639,7 @@
         for (int i = 0; i < mAvailableNetworks.size(); i++) {
             Network network = mAvailableNetworks.valueAt(i);
             if (network != null) {
-                network.writeToProto(proto,
+                network.dumpDebug(proto,
                         StateControllerProto.ConnectivityController.AVAILABLE_NETWORKS);
             }
         }
@@ -658,7 +658,7 @@
                         js.getSourceUid());
                 NetworkRequest rn = js.getJob().getRequiredNetwork();
                 if (rn != null) {
-                    rn.writeToProto(proto,
+                    rn.dumpDebug(proto,
                             StateControllerProto.ConnectivityController.TrackedJob
                                     .REQUIRED_NETWORK);
                 }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index c76346f..a8d8bd9 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -1414,7 +1414,7 @@
         proto.write(JobStatusDumpProto.JobWorkItem.WORK_ID, work.getWorkId());
         proto.write(JobStatusDumpProto.JobWorkItem.DELIVERY_COUNT, work.getDeliveryCount());
         if (work.getIntent() != null) {
-            work.getIntent().writeToProto(proto, JobStatusDumpProto.JobWorkItem.INTENT);
+            work.getIntent().dumpDebug(proto, JobStatusDumpProto.JobWorkItem.INTENT);
         }
         Object grants = work.getGrants();
         if (grants != null) {
@@ -1683,7 +1683,7 @@
         if (full) {
             final long jiToken = proto.start(JobStatusDumpProto.JOB_INFO);
 
-            job.getService().writeToProto(proto, JobStatusDumpProto.JobInfo.SERVICE);
+            job.getService().dumpDebug(proto, JobStatusDumpProto.JobInfo.SERVICE);
 
             proto.write(JobStatusDumpProto.JobInfo.IS_PERIODIC, job.isPeriodic());
             proto.write(JobStatusDumpProto.JobInfo.PERIOD_INTERVAL_MS, job.getIntervalMillis());
@@ -1722,19 +1722,19 @@
                 }
             }
             if (job.getExtras() != null && !job.getExtras().maybeIsEmpty()) {
-                job.getExtras().writeToProto(proto, JobStatusDumpProto.JobInfo.EXTRAS);
+                job.getExtras().dumpDebug(proto, JobStatusDumpProto.JobInfo.EXTRAS);
             }
             if (job.getTransientExtras() != null && !job.getTransientExtras().maybeIsEmpty()) {
-                job.getTransientExtras().writeToProto(proto, JobStatusDumpProto.JobInfo.TRANSIENT_EXTRAS);
+                job.getTransientExtras().dumpDebug(proto, JobStatusDumpProto.JobInfo.TRANSIENT_EXTRAS);
             }
             if (job.getClipData() != null) {
-                job.getClipData().writeToProto(proto, JobStatusDumpProto.JobInfo.CLIP_DATA);
+                job.getClipData().dumpDebug(proto, JobStatusDumpProto.JobInfo.CLIP_DATA);
             }
             if (uriPerms != null) {
                 uriPerms.dump(proto, JobStatusDumpProto.JobInfo.GRANTED_URI_PERMISSIONS);
             }
             if (job.getRequiredNetwork() != null) {
-                job.getRequiredNetwork().writeToProto(proto, JobStatusDumpProto.JobInfo.REQUIRED_NETWORK);
+                job.getRequiredNetwork().dumpDebug(proto, JobStatusDumpProto.JobInfo.REQUIRED_NETWORK);
             }
             if (mTotalNetworkDownloadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
                 proto.write(JobStatusDumpProto.JobInfo.TOTAL_NETWORK_DOWNLOAD_BYTES,
@@ -1822,7 +1822,7 @@
         }
 
         if (network != null) {
-            network.writeToProto(proto, JobStatusDumpProto.NETWORK);
+            network.dumpDebug(proto, JobStatusDumpProto.NETWORK);
         }
 
         if (pendingWork != null) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 3fdc571..2e735a4 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -133,7 +133,7 @@
             return string(userId, packageName);
         }
 
-        public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        public void dumpDebug(ProtoOutputStream proto, long fieldId) {
             final long token = proto.start(fieldId);
 
             proto.write(StateControllerProto.QuotaController.Package.USER_ID, userId);
@@ -1638,7 +1638,7 @@
         public void dump(ProtoOutputStream proto, long fieldId, Predicate<JobStatus> predicate) {
             final long token = proto.start(fieldId);
 
-            mPkg.writeToProto(proto, StateControllerProto.QuotaController.Timer.PKG);
+            mPkg.dumpDebug(proto, StateControllerProto.QuotaController.Timer.PKG);
             proto.write(StateControllerProto.QuotaController.Timer.IS_ACTIVE, isActive());
             proto.write(StateControllerProto.QuotaController.Timer.START_TIME_ELAPSED,
                     mStartTimeElapsed);
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index bcd8be7..2f8b513 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -1171,7 +1171,8 @@
     private void fetchCarrierPrivilegedAppsLocked() {
         TelephonyManager telephonyManager =
                 mContext.getSystemService(TelephonyManager.class);
-        mCarrierPrivilegedApps = telephonyManager.getPackagesWithCarrierPrivilegesForAllPhones();
+        mCarrierPrivilegedApps =
+                telephonyManager.getCarrierPrivilegedPackagesForAllActiveSubscriptions();
         mHaveCarrierPrivilegedApps = true;
         if (DEBUG) {
             Slog.d(TAG, "apps with carrier privilege " + mCarrierPrivilegedApps);
diff --git a/apex/permission/Android.bp b/apex/permission/Android.bp
index 0274814..5945fb3 100644
--- a/apex/permission/Android.bp
+++ b/apex/permission/Android.bp
@@ -14,9 +14,12 @@
 
 apex {
     name: "com.android.permission",
-
+    defaults: ["com.android.permission-defaults"],
     manifest: "apex_manifest.json",
+}
 
+apex_defaults {
+    name: "com.android.permission-defaults",
     key: "com.android.permission.key",
     certificate: ":com.android.permission.certificate",
 }
diff --git a/apex/permission/testing/Android.bp b/apex/permission/testing/Android.bp
new file mode 100644
index 0000000..f8978dc
--- /dev/null
+++ b/apex/permission/testing/Android.bp
@@ -0,0 +1,25 @@
+// 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: "test_com.android.permission",
+    visibility: [
+        "//system/apex/tests",
+    ],
+    defaults: ["com.android.permission-defaults"],
+    manifest: "test_manifest.json",
+    file_contexts: ":com.android.permission-file_contexts",
+    // Test APEX, should never be installed
+    installable: false,
+}
diff --git a/apex/permission/testing/test_manifest.json b/apex/permission/testing/test_manifest.json
new file mode 100644
index 0000000..bc19a9e
--- /dev/null
+++ b/apex/permission/testing/test_manifest.json
@@ -0,0 +1,4 @@
+{
+  "name": "com.android.permission",
+  "version": 2147483647
+}
diff --git a/apex/sdkext/Android.bp b/apex/sdkext/Android.bp
new file mode 100644
index 0000000..aaf25b1
--- /dev/null
+++ b/apex/sdkext/Android.bp
@@ -0,0 +1,44 @@
+// 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.sdkext",
+    manifest: "manifest.json",
+    binaries: [ "derive_sdk" ],
+    java_libs: [ "framework-sdkext" ],
+    prebuilts: [
+      "com.android.sdkext.ldconfig",
+      "derive_sdk.rc",
+    ],
+    key: "com.android.sdkext.key",
+    certificate: ":com.android.sdkext.certificate",
+}
+
+apex_key {
+    name: "com.android.sdkext.key",
+    public_key: "com.android.sdkext.avbpubkey",
+    private_key: "com.android.sdkext.pem",
+}
+
+android_app_certificate {
+    name: "com.android.sdkext.certificate",
+    certificate: "com.android.sdkext",
+}
+
+prebuilt_etc {
+    name: "com.android.sdkext.ldconfig",
+    src: "ld.config.txt",
+    filename: "ld.config.txt",
+    installable: false,
+}
diff --git a/apex/sdkext/OWNERS b/apex/sdkext/OWNERS
new file mode 100644
index 0000000..feb2742
--- /dev/null
+++ b/apex/sdkext/OWNERS
@@ -0,0 +1 @@
+hansson@google.com
diff --git a/apex/sdkext/TEST_MAPPING b/apex/sdkext/TEST_MAPPING
new file mode 100644
index 0000000..91947f3
--- /dev/null
+++ b/apex/sdkext/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsSdkExtTestCases"
+    }
+  ]
+}
diff --git a/apex/sdkext/com.android.sdkext.avbpubkey b/apex/sdkext/com.android.sdkext.avbpubkey
new file mode 100644
index 0000000..8f47741
--- /dev/null
+++ b/apex/sdkext/com.android.sdkext.avbpubkey
Binary files differ
diff --git a/apex/sdkext/com.android.sdkext.pem b/apex/sdkext/com.android.sdkext.pem
new file mode 100644
index 0000000..8164601
--- /dev/null
+++ b/apex/sdkext/com.android.sdkext.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKQIBAAKCAgEAr72pTSavrziDP54AtQZlRclDxJf9HXRZwFRbYx9hWZ4z7ZtO
+pNBDPvPJCiAOVUsILgCQhBUolz2dyLob25Fd0PVp0n9ibIPEQYjTfHjOK40qb57N
+LhEp2ceGiAfsywPSi0TH1PQ6JgbCe/RM4TefI/sj3gYJPka3ksMvylhMIgUVLgME
+kYizhzwHqlLMspB858SioREZdGwcdZrMMIajGFU69Q9ZRDBzhPvxyKhYoObcOtk1
+uVaiE/fNoi3wKGJz2l2vhUuNrQW7MWlVMag+Qes4YACUTk9LZrOVFEJFjWc8xGUi
+ABtfKGs5JgNr/sWnhvifLn8lJuf0/BJmjD+L5QwXYs2cS7gcZJtTM12J94r0Twgw
+wF2lNmIxAE9sYqj5Rh3dIlTPE5vMUECmQEGjIBB/hzT65VxVqSjU/IlS506JTg3p
+IOQtZ15cUzTBpda4jrvqcq6RNVvgBCu2bV5D8Z4z9FUlPyvD+Zq/6lcoJfLtznAs
+G2463hyPAHTGBIcZ5p5bTuGxoAb6ivyqo4b9Qi4yYA6je9HJmuy8T3Mn5JROoeu9
+BH1K54r/mpT4TQPwuKUvRRtBAV2OPHjo+zp0Gd4Y6rxDYxEIdfEae7pQr/QExSPB
+q/QCr9RhixR1mO373LHuja+MxdAxIxugb2HTS61PQo+PbYrhJMcVuxTwJOECAwEA
+AQKCAgAH7ToRrMkH0ji5SdsmTx+KQkW4PFLCXVke/68PjX7KmAQnl3W4oVwnHr/W
+oROEbVn1GTlre7jU+YaAY0SWZrwgjLE1OWGrG1ZizlUbrCdAd6GOX09J4KROml1L
+DXB0x7tbZMLOrCVjSbLD/ITrM6MN8Gnxvbv0/yOQjxU8vzbP4gLOjHxMRCo001RV
+Ll7lPvcjTQ84zJilU6sE8vJ6zdfVZSK/ou2X0cekG+kP7+fvefo8/UcbEPlGhUrV
+IdVPPQGUu90K2hmN0FBdLi8Vik0klAN68Qu/bHwuKbNzsnmIoztucFFUR+fG3u84
+87aPS0L/J3+mjT2Tv6qhJANUGBmrK/h7MkelpKXlRTCITJLX9xP7hfSbJ4f6aLVq
+ZYPPciGxSBbUDgAwvPtOlMDzccg7YsYyiBBO28wh8MN97rePmc0z6nGmjeXhcbCC
+QktG50VYFCyqp5muKgqQmRfRjHFHLWs8GEqgxMeEL3U3HjYfCYr+6E8Sr5OnOBeH
+3buCi1+zgnNYCvbamgY/OJmW7f9h5O31hxmTplc2E1ZuxUGQZthabt1rN3bmNkyf
+KUmPwnIYkDkWBSV5lzyQExfS3/EVvj0EnHhx8faamimNrGo8xCcfnLT3c0WEFVmo
+yIyVRX3EpXJFM2JkeJ21/IEZXTzHSoNxk12CBG8i8lLSflWSMQKCAQEA2ZqVnOuV
+SZfLCUYUUh8Hvhc5zONstfq7ma1Zsttsdaj9t68nLRiBDvLOGnMjDkYZzoSd4fyl
+oy+YqWGBqcqa5kg1NOCH0I46p9d8RcWAfDnB4sqbLgWh70qsvni6igRijmsMDvkA
+U9HeEdPaLCjQ4UXw7GQvN5rRxuRt+OSqV3tV/Pk9JYyYjz7faC8dmbKDrWHHuOvm
+/9y6Xy+L5IgftykNlUeddSCIoMOAadM7BiRjsrHnOYBQ8xBcn0OYafpIswItrgVi
+IrsPJaBFidx8QYK4MVibyka6U0cm28OocDSPtSk/4jrnCEEhLjFUnWwuMXuBGlrd
+W7wP/muoJqb1VwKCAQEAzsAT90kkOCvAcrfGRE3KkUjwWAsQyP8u2+27JIQPqrpW
+GfWAzJXFt80TSp0Zf/Lrq3/SQ9n4AaL4K9dcMoreedoQN9C9JI7zPtZAWNrJVUcV
+dq2gZjBQ78+oK7uQgvFNWxga5D+Nh+Y+9Tp537fc5HIh0Y13PgsxxPk2OnZJTvLX
+HM5H7Aua9ssmqChsrKihuUsDSPozfBz+H7FNHEdKMqVLqJJSK6m0uMxuLovdVfka
+5S7iBMjEGZc46Iz3ckE0pdOiQLooNqfEQqFe5Uou/KZxxKI1NW25rEEBTVyQWt+2
+BNUCfKP7noZ45u5sUY3eJrgI7BrPEDbNS81WYaLchwKCAQA8Q4mHyd6wYO+EA/qA
+u8NDK9+AFMP4qhXme5HJ7Obetwx9IG7zGEQ1xZy6yoQ84cEn5qZq/bNJvFbFIhHs
+2gWIHRtPJ5e1dI5eCVmLYSUyQjSmAIJ1fm3YfY/VuE3BB3HcC11tkBw9GnQr78YO
+UMd4fAw7C4vgFGpgcMbcFUfvrmKkCsqaaZOeqETq75F9DWlWTSwo1HxHA/RBhENz
+6RcPfLkcTJcY5wevrjUUGcHQ86cAyDBHRngkuLVODkRZpU0Y9lN8TFVfVPre6sIX
+ag6nffJRCD8tB+V2RtBGMKunV4ctHt1oY/Oz34W260aJynoIjjG1ANEpJK4xQdNx
+0O9FAoIBAQCz2AGGKemHswdEwveEkuaSWpA3Bekj7lYkmTchHH9EU7JyAkx3qhDD
+QXB2hxGXawf1tsqAmypQwiJ+gGeCz6mW9UkGRF1DX9XX4yc2I5rew2a4RXAxc/Xz
+pP70i8O5I43Wn7FEusOyY2aAis1Y/eb4EQ+56QTAw5wXa3DwidRbCIJ2XDnT6oRy
+CWUnAYMG7ek/9TB2Wq5OWCn2B5S79IdmZsLZb+5qbMT3u1xcwO1Xy8jJc27IGpv6
+ZsDqCTV1/aJ+XQnWpBg28tiV3Sle6pjUzTRJh5AhWcEZRbKMSOiJI/CBY4k2Qq6t
+xuuEdgFjL7T+mTepqehUglcyiPuLEtAhAoIBAQDDQ5pTFOlunfYzm+CIvvImAgy7
+vrEabJYABATytAbXRMMbrKoEdU2ApEDyEW7PgysDnYLAZ+icObnJlBTYvNdlWFly
+XiviGVfpjFWDT9U/gUwFQu2lfEjoiivoGS92USHUy4UMVHiiznnm20VLLkgd3xna
+HUNSDdHIEgzOTmDsKJwMfA9zGckx23JJimPR5ekv6vr6QllYtECs4lTC1gVQAp2f
+5daxHRbkmO6gw1RgQADLkAnYz3aI1jNuHm5VyAZGt/d3JCtZ3Wwwejll8uJ4J09G
+oEtqyY9RVeHK50bLO4lyAXFiE+J6qqXjsGC20cpxeZYW5llMY/dhA6WV4YXV
+-----END RSA PRIVATE KEY-----
diff --git a/apex/sdkext/com.android.sdkext.pk8 b/apex/sdkext/com.android.sdkext.pk8
new file mode 100644
index 0000000..ccc0bf4
--- /dev/null
+++ b/apex/sdkext/com.android.sdkext.pk8
Binary files differ
diff --git a/apex/sdkext/com.android.sdkext.x509.pem b/apex/sdkext/com.android.sdkext.x509.pem
new file mode 100644
index 0000000..45d2ade
--- /dev/null
+++ b/apex/sdkext/com.android.sdkext.x509.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGIzCCBAugAwIBAgIUXuDL7QvzQh7S6rihWz2KRvCFVT0wDQYJKoZIhvcNAQEL
+BQAwgZ8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
+DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
+b2lkMRswGQYDVQQDDBJjb20uYW5kcm9pZC5zZGtleHQxIjAgBgkqhkiG9w0BCQEW
+E2FuZHJvaWRAYW5kcm9pZC5jb20wIBcNMTkxMjAyMTQyNDM0WhgPNDc1NzEwMjgx
+NDI0MzRaMIGfMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQG
+A1UEBwwNTW91bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwH
+QW5kcm9pZDEbMBkGA1UEAwwSY29tLmFuZHJvaWQuc2RrZXh0MSIwIAYJKoZIhvcN
+AQkBFhNhbmRyb2lkQGFuZHJvaWQuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
+MIICCgKCAgEAxFvZZ6ES1oqAu1K74/ZxnC3SOhHnLISLBgJEe7DqtdpuNFAwvdVO
+RL/HULhDbjYlOhpU2x3SavDIZZ2lRfiS9Q+M25WftxTRHVjBcpgwbV77TVxPKlAa
+tVN2lUVOY+s4QAVMNIXjC4kCKK/pCQtacH715EtdV47fWdg/Nx4iP/Aord8k3KGI
+9iI2ZOUjaugTRxu5lKRNDrv0bw5rEzyYmDyMud+kR/iS3/5oog57wPE0ffAkZXWE
+p3L2Cejre3ekCizsvVh6EmH6ForKLtL6f0z5Zir1f4R9+YcENspTlJR3pDhg7y3I
+uTQT/iDCtV0l+g2PjGZPEeAQHND3+kDQR7Sno/WC1Nhws6vcu1MdrC+kIh1ewx4y
+8moy/yqb5M98PJDzTSi/AOTB/OiqLXo/T8rjLBmirs9y3fTT6gJ6qXxOWgt8dle9
+7TBfa84Xi8uVY61c+A+YI0nLal7QDPsP3RPv5sJSQ9x9YnweVfD9Q0EOi52sSNu+
+QuN/kcUrMgPgha20VhfH/CkkPDyIp6aZyHHM69MIl+cYEm8vPa5uy3dosuRomT0f
+I4HOBjULDIuj+rIi+Rg3qHvmpuejwZXI/FBNWIhLEUG3ytgksjMaBoYAYflGdrcj
+BQexuF3EO+j4uo7JGjNcaT7wRoCH9gt29VHckDg2qz6VWXrlpmME4UkCAwEAAaNT
+MFEwHQYDVR0OBBYEFISN2nmUHllgPZMZ62U7mU3ZxzlXMB8GA1UdIwQYMBaAFISN
+2nmUHllgPZMZ62U7mU3ZxzlXMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
+BQADggIBAFHIwyBNIVyHXUsDUdcjxfojXQsF/BCL9ehE3pgdkvDfQanaIREWn0nc
+oCFDFkYMRqaXOGC5TKq4OCjXOLsdfODt8HQ3F9J1B0ghQ5tfOdw7xDugNAszqP/Q
+h7kpvqLTycjrqOeZ5KjxEEYtP/KlUmALgOKcTcSH+XhWyxhjF4j24T9F2yJRr3/A
+r1NGU/djH953bHKC8OpJ2teUpDLA4TxVp/EhslH2eVigF80c/w74QPLEWkD9zv/4
+YeRg/R5N83zHs99NtlWMIeHfK6fUbzMyaSZtvm+jK20tkByQb/OQRed+drk25MtL
+68IRvxqri367qRScdpTZbu0ByLO4X8gFdubRUWr+tcO4pZX+DJRVriExbOkU2xhS
+Vtslq23V/hwTuUNm1CXjR70mPS13BTmHrIQDqLoIw/WTQlGh+vxnlAFRIHM3KB2c
+OdzUBu+NcB4aZEd0KKtct600A0DKPr1MQPb5jDq9wEtPSQYwMF0nRFNnXltbrXMd
+4hhwnhKr74fVMUmb+7eQP56XE/Nk4D+npMO54vv1pav+DI2/nxCND9BOLBweY38p
+Tvd2RjesMok0zXuVXiCIu4GEpwo7WkSnv25xrb0Ey2M8QWnGNnCcX7Kv6ip3RdWy
+HiN0G8RJrs/yNEVSDRx8ZhtwTpXVPQxbARbmhNF4/fnolElkmrMP
+-----END CERTIFICATE-----
diff --git a/apex/sdkext/derive_sdk/Android.bp b/apex/sdkext/derive_sdk/Android.bp
new file mode 100644
index 0000000..c4e3c29
--- /dev/null
+++ b/apex/sdkext/derive_sdk/Android.bp
@@ -0,0 +1,37 @@
+// 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.
+
+cc_binary {
+    name: "derive_sdk",
+    srcs: [
+        "derive_sdk.cpp",
+        "sdk.proto",
+    ],
+    proto: {
+        type: "lite",
+    },
+    sdk_version: "current",
+    stl: "c++_static",
+    shared_libs: [ "liblog" ],
+    static_libs: [
+        "libbase_ndk",
+        "libprotobuf-cpp-lite-ndk",
+    ],
+}
+
+prebuilt_etc {
+    name: "derive_sdk.rc",
+    src: "derive_sdk.rc",
+    installable: false,
+}
diff --git a/apex/sdkext/derive_sdk/derive_sdk.cpp b/apex/sdkext/derive_sdk/derive_sdk.cpp
new file mode 100644
index 0000000..0aacebe
--- /dev/null
+++ b/apex/sdkext/derive_sdk/derive_sdk.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "derive_sdk"
+
+#include <algorithm>
+#include <dirent.h>
+#include <iostream>
+#include <sys/stat.h>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+
+#include "frameworks/base/apex/sdkext/derive_sdk/sdk.pb.h"
+
+using com::android::sdkext::proto::SdkVersion;
+
+int main(int, char**) {
+    std::unique_ptr<DIR, decltype(&closedir)> apex(opendir("/apex"), closedir);
+    if (!apex) {
+        LOG(ERROR) << "Could not read /apex";
+        return EXIT_FAILURE;
+    }
+    struct dirent* de;
+    std::vector<std::string> paths;
+    while ((de = readdir(apex.get()))) {
+        std::string name = de->d_name;
+        if (name[0] == '.' || name.find('@') != std::string::npos) {
+            // Skip <name>@<ver> dirs, as they are bind-mounted to <name>
+            continue;
+        }
+        std::string path = "/apex/" + name + "/etc/sdkinfo.binarypb";
+        struct stat statbuf;
+        if (stat(path.c_str(), &statbuf) == 0) {
+            paths.push_back(path);
+        }
+    }
+
+    std::vector<int> versions;
+    for (const auto& path : paths) {
+        std::string contents;
+        if (!android::base::ReadFileToString(path, &contents, true)) {
+            LOG(ERROR) << "failed to read " << path;
+            continue;
+        }
+        SdkVersion sdk_version;
+        if (!sdk_version.ParseFromString(contents)) {
+            LOG(ERROR) << "failed to parse " << path;
+            continue;
+        }
+        versions.push_back(sdk_version.version());
+    }
+    auto itr = std::min_element(versions.begin(), versions.end());
+    std::string prop_value = itr == versions.end() ? "0" : std::to_string(*itr);
+
+    if (!android::base::SetProperty("persist.com.android.sdkext.sdk_info", prop_value)) {
+        LOG(ERROR) << "failed to set sdk_info prop";
+        return EXIT_FAILURE;
+    }
+
+    return EXIT_SUCCESS;
+}
diff --git a/apex/sdkext/derive_sdk/derive_sdk.rc b/apex/sdkext/derive_sdk/derive_sdk.rc
new file mode 100644
index 0000000..1b66794
--- /dev/null
+++ b/apex/sdkext/derive_sdk/derive_sdk.rc
@@ -0,0 +1,3 @@
+service derive_sdk /apex/com.android.sdkext/bin/derive_sdk
+    oneshot
+    disabled
diff --git a/apex/sdkext/derive_sdk/sdk.proto b/apex/sdkext/derive_sdk/sdk.proto
new file mode 100644
index 0000000..d15b935
--- /dev/null
+++ b/apex/sdkext/derive_sdk/sdk.proto
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+package com.android.sdkext.proto;
+
+option java_outer_classname = "SdkProto";
+option optimize_for = LITE_RUNTIME;
+
+message SdkVersion {
+  int32 version = 1;
+}
diff --git a/apex/sdkext/framework/Android.bp b/apex/sdkext/framework/Android.bp
new file mode 100644
index 0000000..b17f0f8
--- /dev/null
+++ b/apex/sdkext/framework/Android.bp
@@ -0,0 +1,30 @@
+// 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-sdkext-sources",
+    srcs: [
+        "java/**/*.java",
+    ],
+    path: "java",
+}
+
+java_library {
+    name: "framework-sdkext",
+    srcs: [ ":framework-sdkext-sources" ],
+    sdk_version: "system_current",
+    libs: [ "framework-annotations-lib" ],
+    permitted_packages: [ "android.os.ext" ],
+    installable: true,
+}
diff --git a/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java b/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java
new file mode 100644
index 0000000..331ef21
--- /dev/null
+++ b/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java
@@ -0,0 +1,68 @@
+/*
+ * 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.os.ext;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.os.Build.VERSION_CODES;
+import android.os.SystemProperties;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Methods for interacting with the extension SDK.
+ *
+ * This class provides information about the extension SDK version present
+ * on this device. Use the {@link #getExtensionVersion(int) getExtension} to
+ * query for the extension version for the given SDK version.
+
+ * @hide
+ */
+@SystemApi
+public class SdkExtensions {
+
+    private static final int R_EXTENSION_INT;
+    static {
+        R_EXTENSION_INT = SystemProperties.getInt("persist.com.android.sdkext.sdk_info", 0);
+    }
+
+    /**
+     * Values suitable as parameters for {@link #getExtensionVersion(int)}.
+     * @hide
+     */
+    @IntDef(value = { VERSION_CODES.R })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SdkVersion {}
+
+    private SdkExtensions() { }
+
+    /**
+     * Return the version of the extension to the given SDK.
+     *
+     * @param sdk the SDK version to get the extension version of.
+     * @see SdkVersion
+     * @throws IllegalArgumentException if sdk is not an sdk version with extensions
+     */
+    public static int getExtensionVersion(@SdkVersion int sdk) {
+        if (sdk < VERSION_CODES.R) {
+            throw new IllegalArgumentException();
+        }
+        return R_EXTENSION_INT;
+    }
+
+}
diff --git a/apex/sdkext/framework/java/android/os/ext/package.html b/apex/sdkext/framework/java/android/os/ext/package.html
new file mode 100644
index 0000000..34c1697
--- /dev/null
+++ b/apex/sdkext/framework/java/android/os/ext/package.html
@@ -0,0 +1,5 @@
+<HTML>
+<BODY>
+Provides APIs to interface with the SDK extensions.
+</BODY>
+</HTML>
diff --git a/apex/sdkext/ld.config.txt b/apex/sdkext/ld.config.txt
new file mode 100644
index 0000000..b447068
--- /dev/null
+++ b/apex/sdkext/ld.config.txt
@@ -0,0 +1,31 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Bionic loader config file for the sdkext apex.
+
+dir.sdkext = /apex/com.android.sdkext/bin/
+
+[sdkext]
+additional.namespaces = platform
+
+namespace.default.isolated = true
+namespace.default.links = platform
+namespace.default.link.platform.allow_all_shared_libs = true
+
+###############################################################################
+# "platform" namespace: used for NDK libraries
+###############################################################################
+namespace.platform.isolated = true
+namespace.platform.search.paths = /system/${LIB}
+namespace.platform.asan.search.paths = /data/asan/system/${LIB}
+
+# /system/lib/libc.so, etc are symlinks to /apex/com.android.lib/lib/bionic/libc.so, etc.
+# Add /apex/... path to the permitted paths because linker uses realpath(3)
+# to check the accessibility of the lib. We could add this to search.paths
+# instead but that makes the resolution of bionic libs be dependent on
+# the order of /system/lib and /apex/... in search.paths. If /apex/...
+# is after /system/lib, then /apex/... is never tried because libc.so
+# is always found in /system/lib but fails to pass the accessibility test
+# because of its realpath.  It's better to not depend on the ordering if
+# possible.
+namespace.platform.permitted.paths = /apex/com.android.runtime/${LIB}/bionic
+namespace.platform.asan.permitted.paths = /apex/com.android.runtime/${LIB}/bionic
diff --git a/apex/sdkext/manifest.json b/apex/sdkext/manifest.json
new file mode 100644
index 0000000..048f5c4
--- /dev/null
+++ b/apex/sdkext/manifest.json
@@ -0,0 +1,4 @@
+{
+  "name": "com.android.sdkext",
+  "version": 1
+}
diff --git a/apex/statsd/aidl/Android.bp b/apex/statsd/aidl/Android.bp
new file mode 100644
index 0000000..e6ca544
--- /dev/null
+++ b/apex/statsd/aidl/Android.bp
@@ -0,0 +1,35 @@
+//
+// 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.
+//
+
+// TODO(b/145815909): move StatsDimensionsValue.aidl and StatsLogEventWrapper.aidl here
+filegroup {
+    name: "statsd_aidl",
+    srcs: ["**/*.aidl"],
+}
+
+// This library is currently unused
+aidl_interface {
+    name: "stats-event-parcel-aidl",
+    srcs: ["android/util/StatsEventParcel.aidl"],
+    backend: {
+        java: {
+            sdk_version: "28",
+        },
+        cpp: {
+            enabled: false,
+        }
+    }
+}
diff --git a/core/java/android/os/IPullAtomCallback.aidl b/apex/statsd/aidl/android/os/IPullAtomCallback.aidl
similarity index 100%
rename from core/java/android/os/IPullAtomCallback.aidl
rename to apex/statsd/aidl/android/os/IPullAtomCallback.aidl
diff --git a/apex/statsd/aidl/android/os/IPullAtomResultReceiver.aidl b/apex/statsd/aidl/android/os/IPullAtomResultReceiver.aidl
new file mode 100644
index 0000000..00d026e
--- /dev/null
+++ b/apex/statsd/aidl/android/os/IPullAtomResultReceiver.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.os;
+
+import android.util.StatsEventParcel;
+
+/**
+  * Binder interface to pull atoms for the stats service.
+  * {@hide}
+  */
+interface IPullAtomResultReceiver {
+
+    /**
+     * Indicate that a pull request for an atom is complete.
+     */
+     oneway void pullFinished(int atomTag, boolean success, in StatsEventParcel[] output);
+
+}
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/apex/statsd/aidl/android/os/IStatsCompanionService.aidl
similarity index 100%
rename from core/java/android/os/IStatsCompanionService.aidl
rename to apex/statsd/aidl/android/os/IStatsCompanionService.aidl
diff --git a/apex/statsd/aidl/android/os/IStatsManager.aidl b/apex/statsd/aidl/android/os/IStatsManager.aidl
new file mode 100644
index 0000000..cc62f07
--- /dev/null
+++ b/apex/statsd/aidl/android/os/IStatsManager.aidl
@@ -0,0 +1,249 @@
+/**
+ * Copyright (c) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.os.IStatsPullerCallback;
+import android.os.IPullAtomCallback;
+import android.os.ParcelFileDescriptor;
+
+/**
+  * Binder interface to communicate with the statistics management service.
+  * {@hide}
+  */
+interface IStatsManager {
+    /**
+     * Tell the stats daemon that the android system server is up and running.
+     */
+    oneway void systemRunning();
+
+    /**
+     * Tell the stats daemon that the StatsCompanionService is up and running.
+     * Two-way binder call so that caller knows message received.
+     */
+    void statsCompanionReady();
+
+    /**
+     * Tells statsd that an anomaly may have occurred, so statsd can check whether this is so and
+     * act accordingly.
+     * Two-way binder call so that caller's method (and corresponding wakelocks) will linger.
+     */
+    void informAnomalyAlarmFired();
+
+    /**
+     * Tells statsd that it is time to poll some stats. Statsd will be responsible for determing
+     * what stats to poll and initiating the polling.
+     * Two-way binder call so that caller's method (and corresponding wakelocks) will linger.
+     */
+    void informPollAlarmFired();
+
+    /**
+     * Tells statsd that it is time to handle periodic alarms. Statsd will be responsible for
+     * determing what alarm subscriber to trigger.
+     * Two-way binder call so that caller's method (and corresponding wakelocks) will linger.
+     */
+    void informAlarmForSubscriberTriggeringFired();
+
+    /**
+     * Tells statsd that the device is about to shutdown.
+     */
+    void informDeviceShutdown();
+
+    /**
+     * Inform statsd about a file descriptor for a pipe through which we will pipe version
+     * and package information for each uid.
+     * Versions and package information are supplied via UidData proto where info for each app
+     * is captured in its own element of a repeated ApplicationInfo message.
+     */
+    oneway void informAllUidData(in ParcelFileDescriptor fd);
+
+    /**
+     * Inform statsd what the uid, version, version_string, and installer are for one app that was
+     * updated.
+     */
+    oneway void informOnePackage(in String app, in int uid, in long version,
+        in String version_string, in String installer);
+
+    /**
+     * Inform stats that an app was removed.
+     */
+    oneway void informOnePackageRemoved(in String app, in int uid);
+
+    /**
+     * Fetches data for the specified configuration key. Returns a byte array representing proto
+     * wire-encoded of ConfigMetricsReportList.
+     *
+     * Requires Manifest.permission.DUMP.
+     */
+    byte[] getData(in long key, in String packageName);
+
+    /**
+     * Fetches metadata across statsd. Returns byte array representing wire-encoded proto.
+     *
+     * Requires Manifest.permission.DUMP.
+     */
+    byte[] getMetadata(in String packageName);
+
+    /**
+     * Sets a configuration with the specified config key and subscribes to updates for this
+     * configuration key. Broadcasts will be sent if this configuration needs to be collected.
+     * The configuration must be a wire-encoded StatsdConfig. The receiver for this data is
+     * registered in a separate function.
+     *
+     * Requires Manifest.permission.DUMP.
+     */
+    void addConfiguration(in long configKey, in byte[] config, in String packageName);
+
+    /**
+     * Registers the given pending intent for this config key. This intent is invoked when the
+     * memory consumed by the metrics for this configuration approach the pre-defined limits. There
+     * can be at most one listener per config key.
+     *
+     * Requires Manifest.permission.DUMP.
+     */
+    void setDataFetchOperation(long configKey, in IBinder intentSender, in String packageName);
+
+    /**
+     * Removes the data fetch operation for the specified configuration.
+     *
+     * Requires Manifest.permission.DUMP.
+     */
+    void removeDataFetchOperation(long configKey, in String packageName);
+
+    /**
+     * Registers the given pending intent for this packagename. This intent is invoked when the
+     * active status of any of the configs sent by this package changes and will contain a list of
+     * config ids that are currently active. It also returns the list of configs that are currently
+     * active. There can be at most one active configs changed listener per package.
+     *
+     * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
+     */
+    long[] setActiveConfigsChangedOperation(in IBinder intentSender, in String packageName);
+
+    /**
+     * Removes the active configs changed operation for the specified package name.
+     *
+     * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
+     */
+    void removeActiveConfigsChangedOperation(in String packageName);
+
+    /**
+     * Removes the configuration with the matching config key. No-op if this config key does not
+     * exist.
+     *
+     * Requires Manifest.permission.DUMP.
+     */
+    void removeConfiguration(in long configKey, in String packageName);
+
+    /**
+     * Set the IIntentSender (i.e. PendingIntent) to be used when broadcasting subscriber
+     * information to the given subscriberId within the given config.
+     *
+     * Suppose that the calling uid has added a config with key configKey, and that in this config
+     * it is specified that when a particular anomaly is detected, a broadcast should be sent to
+     * a BroadcastSubscriber with id subscriberId. This function links the given intentSender with
+     * that subscriberId (for that config), so that this intentSender is used to send the broadcast
+     * when the anomaly is detected.
+     *
+     * This function can only be called by the owner (uid) of the config. It must be called each
+     * time statsd starts. Later calls overwrite previous calls; only one intentSender is stored.
+     *
+     * intentSender must be convertible into an IntentSender using IntentSender(IBinder)
+     * and cannot be null.
+     *
+     * Requires Manifest.permission.DUMP.
+     */
+    void setBroadcastSubscriber(long configKey, long subscriberId, in IBinder intentSender,
+                                in String packageName);
+
+    /**
+     * Undoes setBroadcastSubscriber() for the (configKey, subscriberId) pair.
+     * Any broadcasts associated with subscriberId will henceforth not be sent.
+     * No-op if this (configKey, subsriberId) pair was not associated with an IntentSender.
+     *
+     * Requires Manifest.permission.DUMP.
+     */
+    void unsetBroadcastSubscriber(long configKey, long subscriberId, in String packageName);
+
+    /**
+     * Apps can send an atom via this application breadcrumb with the specified label and state for
+     * this label. This allows building custom metrics and predicates.
+     */
+    void sendAppBreadcrumbAtom(int label, int state);
+
+    /**
+     * Registers a puller callback function that, when invoked, pulls the data
+     * for the specified vendor atom tag.
+     *
+     * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS
+     * @deprecated please use registerPullAtomCallback.
+     */
+    oneway void registerPullerCallback(int atomTag, IStatsPullerCallback pullerCallback,
+                                       String packageName);
+
+   /**
+    * 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);
+
+   /**
+    * Registers a puller callback function that, when invoked, pulls the data
+    * for the specified atom tag.
+    */
+    oneway void registerNativePullAtomCallback(int atomTag, long coolDownNs, long timeoutNs,
+                           in int[] additiveFields, IPullAtomCallback pullerCallback);
+
+   /**
+    * Unregisters a puller callback function for the given vendor atom.
+    *
+    * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS
+    */
+   oneway void unregisterPullerCallback(int atomTag, String packageName);
+
+    /**
+     * The install requires staging.
+     */
+    const int FLAG_REQUIRE_STAGING = 0x01;
+
+    /**
+     * Rollback is enabled with this install.
+     */
+    const int FLAG_ROLLBACK_ENABLED = 0x02;
+
+    /**
+     * Requires low latency monitoring.
+     */
+    const int FLAG_REQUIRE_LOW_LATENCY_MONITOR = 0x04;
+
+    /**
+     * Logs an event for binary push for module updates.
+     */
+     oneway void sendBinaryPushStateChangedAtom(in String trainName, in long trainVersionCode,
+         in int options, in int state, in long[] experimentId);
+
+    /**
+     * Logs an event for watchdog rollbacks.
+     */
+     oneway void sendWatchdogRollbackOccurredAtom(in int rollbackType, in String packageName,
+         in long packageVersionCode, in int rollbackReason, in String failingPackageName);
+
+    /**
+     * Returns the most recently registered experiment IDs.
+     */
+    long[] getRegisteredExperimentIds();
+}
diff --git a/core/java/android/os/IStatsPullerCallback.aidl b/apex/statsd/aidl/android/os/IStatsPullerCallback.aidl
similarity index 100%
rename from core/java/android/os/IStatsPullerCallback.aidl
rename to apex/statsd/aidl/android/os/IStatsPullerCallback.aidl
diff --git a/apex/statsd/aidl/android/util/StatsEventParcel.aidl b/apex/statsd/aidl/android/util/StatsEventParcel.aidl
new file mode 100644
index 0000000..add8bfb
--- /dev/null
+++ b/apex/statsd/aidl/android/util/StatsEventParcel.aidl
@@ -0,0 +1,8 @@
+package android.util;
+
+/**
+ * @hide
+ */
+parcelable StatsEventParcel {
+    byte[] buffer;
+}
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index f2de200..6fb3bc4 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -18,6 +18,7 @@
 import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED;
 import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
 import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
+import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
 import static android.os.Process.getUidForPid;
 import static android.os.storage.VolumeInfo.TYPE_PRIVATE;
 import static android.os.storage.VolumeInfo.TYPE_PUBLIC;
@@ -40,6 +41,7 @@
 import android.app.AppOpsManager.HistoricalOpsRequest;
 import android.app.AppOpsManager.HistoricalPackageOps;
 import android.app.AppOpsManager.HistoricalUidOps;
+import android.app.INotificationManager;
 import android.app.ProcessMemoryState;
 import android.app.StatsManager;
 import android.bluetooth.BluetoothActivityEnergyInfo;
@@ -63,8 +65,7 @@
 import android.net.Network;
 import android.net.NetworkRequest;
 import android.net.NetworkStats;
-import android.net.wifi.IWifiManager;
-import android.net.wifi.WifiActivityEnergyInfo;
+import android.net.wifi.WifiManager;
 import android.os.BatteryStats;
 import android.os.BatteryStatsInternal;
 import android.os.Binder;
@@ -97,6 +98,7 @@
 import android.os.Temperature;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.connectivity.WifiActivityEnergyInfo;
 import android.os.storage.DiskInfo;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
@@ -115,7 +117,6 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.procstats.IProcessStats;
 import com.android.internal.app.procstats.ProcessStats;
-import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.BatterySipper;
 import com.android.internal.os.BatteryStatsHelper;
 import com.android.internal.os.BinderCallsStats.ExportedCallStat;
@@ -139,6 +140,7 @@
 import com.android.server.SystemService;
 import com.android.server.SystemServiceManager;
 import com.android.server.am.MemoryStatUtil.MemoryStat;
+import com.android.server.notification.NotificationManagerService;
 import com.android.server.role.RoleManagerInternal;
 import com.android.server.stats.IonMemoryUtil.IonAllocations;
 import com.android.server.stats.ProcfsMemoryUtil.MemorySnapshot;
@@ -170,6 +172,7 @@
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
@@ -342,7 +345,7 @@
 
     private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader();
     private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
-    private IWifiManager mWifiManager = null;
+    private WifiManager mWifiManager = null;
     private TelephonyManager mTelephony = null;
     @GuardedBy("sStatsdLock")
     private final HashSet<Long> mDeathTimeMillis = new HashSet<>();
@@ -535,7 +538,7 @@
 
     // Assumes that sStatsdLock is held.
     @GuardedBy("sStatsdLock")
-    private final void informAllUidsLocked(Context context) throws RemoteException {
+    private void informAllUidsLocked(Context context) throws RemoteException {
         UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
         PackageManager pm = context.getPackageManager();
         final List<UserInfo> users = um.getUsers(true);
@@ -557,7 +560,11 @@
             Slog.e(TAG, "Failed to close the read side of the pipe.", e);
         }
         final ParcelFileDescriptor writeFd = fds[1];
-        BackgroundThread.getHandler().post(() -> {
+        HandlerThread backgroundThread = new HandlerThread(
+                "statsCompanionService.bg", THREAD_PRIORITY_BACKGROUND);
+        backgroundThread.start();
+        Handler handler = new Handler(backgroundThread.getLooper());
+        handler.post(() -> {
             FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(writeFd);
             try {
                 ProtoOutputStream output = new ProtoOutputStream(fout);
@@ -607,6 +614,8 @@
                 }
             } finally {
                 IoUtils.closeQuietly(fout);
+                backgroundThread.quit();
+                backgroundThread.interrupt();
             }
         });
     }
@@ -1142,35 +1151,48 @@
     private void pullWifiActivityInfo(
             int tagId, long elapsedNanos, long wallClockNanos,
             List<StatsLogEventWrapper> pulledData) {
-        long token = Binder.clearCallingIdentity();
+        WifiManager wifiManager;
         synchronized (this) {
             if (mWifiManager == null) {
-                mWifiManager =
-                        IWifiManager.Stub.asInterface(
-                                ServiceManager.getService(Context.WIFI_SERVICE));
+                mWifiManager = mContext.getSystemService(WifiManager.class);
             }
+            wifiManager = mWifiManager;
         }
-        if (mWifiManager != null) {
-            try {
-                SynchronousResultReceiver wifiReceiver = new SynchronousResultReceiver("wifi");
-                mWifiManager.requestActivityInfo(wifiReceiver);
-                final WifiActivityEnergyInfo wifiInfo = awaitControllerInfo(wifiReceiver);
-                StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos,
-                        wallClockNanos);
-                e.writeLong(wifiInfo.getTimeStamp());
-                e.writeInt(wifiInfo.getStackState());
-                e.writeLong(wifiInfo.getControllerTxTimeMillis());
-                e.writeLong(wifiInfo.getControllerRxTimeMillis());
-                e.writeLong(wifiInfo.getControllerIdleTimeMillis());
-                e.writeLong(wifiInfo.getControllerEnergyUsed());
-                pulledData.add(e);
-            } catch (RemoteException e) {
-                Slog.e(TAG,
-                        "Pulling wifiManager for wifi controller activity energy info has error",
-                        e);
-            } finally {
-                Binder.restoreCallingIdentity(token);
+        if (wifiManager == null) {
+            return;
+        }
+        long token = Binder.clearCallingIdentity();
+        try {
+            SynchronousResultReceiver wifiReceiver = new SynchronousResultReceiver("wifi");
+            wifiManager.getWifiActivityEnergyInfoAsync(
+                    new Executor() {
+                        @Override
+                        public void execute(Runnable runnable) {
+                            // run the listener on the binder thread, if it was run on the main
+                            // thread it would deadlock since we would be waiting on ourselves
+                            runnable.run();
+                        }
+                    },
+                    info -> {
+                        Bundle bundle = new Bundle();
+                        bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, info);
+                        wifiReceiver.send(0, bundle);
+                    }
+            );
+            final WifiActivityEnergyInfo wifiInfo = awaitControllerInfo(wifiReceiver);
+            if (wifiInfo == null) {
+                return;
             }
+            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
+            e.writeLong(wifiInfo.getTimeSinceBootMillis());
+            e.writeInt(wifiInfo.getStackState());
+            e.writeLong(wifiInfo.getControllerTxDurationMillis());
+            e.writeLong(wifiInfo.getControllerRxDurationMillis());
+            e.writeLong(wifiInfo.getControllerIdleDurationMillis());
+            e.writeLong(wifiInfo.getControllerEnergyUsedMicroJoules());
+            pulledData.add(e);
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
     }
 
@@ -1730,14 +1752,7 @@
                 if (statsFiles.size() != 1) {
                     return;
                 }
-                InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(
-                        statsFiles.get(0));
-                int[] len = new int[1];
-                byte[] stats = readFully(stream, len);
-                StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos,
-                        wallClockNanos);
-                e.writeStorage(Arrays.copyOf(stats, len[0]));
-                pulledData.add(e);
+                unpackStreamedData(tagId, elapsedNanos, wallClockNanos, pulledData, statsFiles);
                 new File(mBaseDir.getAbsolutePath() + "/" + section + "_"
                         + lastHighWaterMark).delete();
                 new File(
@@ -1753,6 +1768,52 @@
         }
     }
 
+    private INotificationManager mNotificationManager =
+            INotificationManager.Stub.asInterface(
+                    ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+
+    private void pullNotificationStats(int reportId, int tagId, long elapsedNanos,
+            long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
+        final long callingToken = Binder.clearCallingIdentity();
+        try {
+            // determine last pull tine. Copy file trick from pullProcessStats?
+            long lastNotificationStatsNs = wallClockNanos -
+                    TimeUnit.NANOSECONDS.convert(1, TimeUnit.DAYS);
+
+            List<ParcelFileDescriptor> statsFiles = new ArrayList<>();
+            long notificationStatsNs = mNotificationManager.pullStats(
+                    lastNotificationStatsNs, reportId, true, statsFiles);
+            if (statsFiles.size() != 1) {
+                return;
+            }
+            unpackStreamedData(tagId, elapsedNanos, wallClockNanos, pulledData, statsFiles);
+        } catch (IOException e) {
+            Log.e(TAG, "Getting notistats failed: ", e);
+
+        } catch (RemoteException e) {
+            Log.e(TAG, "Getting notistats failed: ", e);
+        } catch (SecurityException e) {
+            Log.e(TAG, "Getting notistats failed: ", e);
+        } finally {
+            Binder.restoreCallingIdentity(callingToken);
+        }
+
+    }
+
+    static void unpackStreamedData(int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData, List<ParcelFileDescriptor> statsFiles)
+            throws IOException {
+        InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(
+                statsFiles.get(0));
+        int[] len = new int[1];
+        byte[] stats = readFully(stream, len);
+        StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos,
+                wallClockNanos);
+        e.writeStorage(Arrays.copyOf(stats, len[0]));
+        pulledData.add(e);
+    }
+
     static byte[] readFully(InputStream stream, int[] outLen) throws IOException {
         int pos = 0;
         final int initialAvail = stream.available();
@@ -1790,7 +1851,7 @@
         StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos,
                 wallClockNanos);
         ProtoOutputStream proto = new ProtoOutputStream();
-        powerProfile.writeToProto(proto);
+        powerProfile.dumpDebug(proto);
         proto.flush();
         e.writeStorage(proto.getBytes());
         pulledData.add(e);
@@ -2177,6 +2238,20 @@
                         e.writeLong(op.getBackgroundRejectCount(OP_FLAGS_ALL_TRUSTED));
                         e.writeLong(op.getForegroundAccessDuration(OP_FLAGS_ALL_TRUSTED));
                         e.writeLong(op.getBackgroundAccessDuration(OP_FLAGS_ALL_TRUSTED));
+
+                        String perm = AppOpsManager.opToPermission(op.getOpCode());
+                        if (perm == null) {
+                            e.writeBoolean(false);
+                        } else {
+                            PermissionInfo permInfo;
+                            try {
+                                permInfo = mContext.getPackageManager().getPermissionInfo(perm, 0);
+                                e.writeBoolean(permInfo.getProtection() == PROTECTION_DANGEROUS);
+                            } catch (PackageManager.NameNotFoundException exception) {
+                                e.writeBoolean(false);
+                            }
+                        }
+
                         pulledData.add(e);
                     }
                 }
@@ -2587,6 +2662,11 @@
                 pullAppOps(elapsedNanos, wallClockNanos, ret);
                 break;
             }
+            case StatsLog.NOTIFICATION_REMOTE_VIEWS: {
+                pullNotificationStats(NotificationManagerService.REPORT_REMOTE_VIEWS,
+                        tagId, elapsedNanos, wallClockNanos, ret);
+                break;
+            }
             default:
                 Slog.w(TAG, "No such tagId data as " + tagId);
                 return null;
diff --git a/api/current.txt b/api/current.txt
index f1c03a4..c7a210e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -299,6 +299,7 @@
     field public static final int animateFirstView = 16843477; // 0x10102d5
     field public static final int animateLayoutChanges = 16843506; // 0x10102f2
     field public static final int animateOnClick = 16843356; // 0x101025c
+    field public static final int animatedImageDrawable = 16844298; // 0x101060a
     field public static final int animation = 16843213; // 0x10101cd
     field public static final int animationCache = 16842989; // 0x10100ed
     field public static final int animationDuration = 16843026; // 0x1010112
@@ -723,6 +724,7 @@
     field public static final int host = 16842792; // 0x1010028
     field public static final int hotSpotX = 16844055; // 0x1010517
     field public static final int hotSpotY = 16844056; // 0x1010518
+    field public static final int htmlDescription = 16844299; // 0x101060b
     field public static final int hyphenationFrequency = 16843998; // 0x10104de
     field public static final int icon = 16842754; // 0x1010002
     field @Deprecated public static final int iconPreview = 16843337; // 0x1010249
@@ -1865,6 +1867,7 @@
     field public static final int accessibilityActionPageLeft = 16908360; // 0x1020048
     field public static final int accessibilityActionPageRight = 16908361; // 0x1020049
     field public static final int accessibilityActionPageUp = 16908358; // 0x1020046
+    field public static final int accessibilityActionPressAndHold = 16908362; // 0x102004a
     field public static final int accessibilityActionScrollDown = 16908346; // 0x102003a
     field public static final int accessibilityActionScrollLeft = 16908345; // 0x1020039
     field public static final int accessibilityActionScrollRight = 16908347; // 0x102003b
@@ -2925,6 +2928,7 @@
     method public int describeContents();
     method public static String feedbackTypeToString(int);
     method public static String flagToString(int);
+    method public int getAnimatedImageRes();
     method @Deprecated public boolean getCanRetrieveWindowContent();
     method public int getCapabilities();
     method @Deprecated public String getDescription();
@@ -2934,6 +2938,7 @@
     method public android.content.pm.ResolveInfo getResolveInfo();
     method public String getSettingsActivityName();
     method public String loadDescription(android.content.pm.PackageManager);
+    method @Nullable public String loadHtmlDescription(@NonNull android.content.pm.PackageManager);
     method public CharSequence loadSummary(android.content.pm.PackageManager);
     method public void setInteractiveUiTimeoutMillis(@IntRange(from=0) int);
     method public void setNonInteractiveUiTimeoutMillis(@IntRange(from=0) int);
@@ -5176,12 +5181,12 @@
     method public android.content.Intent getResultData();
   }
 
-  public abstract class IntentService extends android.app.Service {
-    ctor public IntentService(String);
-    method @Nullable public android.os.IBinder onBind(android.content.Intent);
-    method @WorkerThread protected abstract void onHandleIntent(@Nullable android.content.Intent);
-    method public void onStart(@Nullable android.content.Intent, int);
-    method public void setIntentRedelivery(boolean);
+  @Deprecated public abstract class IntentService extends android.app.Service {
+    ctor @Deprecated public IntentService(String);
+    method @Deprecated @Nullable public android.os.IBinder onBind(android.content.Intent);
+    method @Deprecated @WorkerThread protected abstract void onHandleIntent(@Nullable android.content.Intent);
+    method @Deprecated public void onStart(@Nullable android.content.Intent, int);
+    method @Deprecated public void setIntentRedelivery(boolean);
   }
 
   public class KeyguardManager {
@@ -6725,7 +6730,8 @@
     method @Nullable public String getAlwaysOnVpnPackage(@NonNull android.content.ComponentName);
     method @NonNull @WorkerThread public android.os.Bundle getApplicationRestrictions(@Nullable android.content.ComponentName, String);
     method @Deprecated @Nullable public String getApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName);
-    method public boolean getAutoTimeRequired();
+    method public boolean getAutoTime(@NonNull android.content.ComponentName);
+    method @Deprecated public boolean getAutoTimeRequired();
     method @NonNull public java.util.List<android.os.UserHandle> getBindDeviceAdminTargetUsers(@NonNull android.content.ComponentName);
     method public boolean getBluetoothContactSharingDisabled(@NonNull android.content.ComponentName);
     method public boolean getCameraDisabled(@Nullable android.content.ComponentName);
@@ -6828,7 +6834,7 @@
     method public boolean removeOverrideApn(@NonNull android.content.ComponentName, int);
     method public boolean removeUser(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
     method public boolean requestBugreport(@NonNull android.content.ComponentName);
-    method public boolean resetPassword(String, int);
+    method @Deprecated public boolean resetPassword(String, int);
     method public boolean resetPasswordWithToken(@NonNull android.content.ComponentName, String, byte[], int);
     method @Nullable public java.util.List<android.app.admin.NetworkEvent> retrieveNetworkLogs(@Nullable android.content.ComponentName, long);
     method @Nullable public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(@NonNull android.content.ComponentName);
@@ -6841,7 +6847,8 @@
     method public boolean setApplicationHidden(@NonNull android.content.ComponentName, String, boolean);
     method @WorkerThread public void setApplicationRestrictions(@Nullable android.content.ComponentName, String, android.os.Bundle);
     method @Deprecated public void setApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName, @Nullable String) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public void setAutoTimeRequired(@NonNull android.content.ComponentName, boolean);
+    method public void setAutoTime(@NonNull android.content.ComponentName, boolean);
+    method @Deprecated public void setAutoTimeRequired(@NonNull android.content.ComponentName, boolean);
     method public void setBackupServiceEnabled(@NonNull android.content.ComponentName, boolean);
     method public void setBluetoothContactSharingDisabled(@NonNull android.content.ComponentName, boolean);
     method public void setCameraDisabled(@NonNull android.content.ComponentName, boolean);
@@ -9899,6 +9906,7 @@
     method public abstract void sendOrderedBroadcast(@RequiresPermission android.content.Intent, @Nullable String);
     method public abstract void sendOrderedBroadcast(@NonNull @RequiresPermission android.content.Intent, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
     method public void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
+    method public void sendOrderedBroadcast(@NonNull @RequiresPermission android.content.Intent, @Nullable String, @Nullable String, @Nullable android.os.Bundle, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
     method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendOrderedBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
     method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void sendStickyBroadcast(@RequiresPermission android.content.Intent);
     method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void sendStickyBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
@@ -11357,6 +11365,15 @@
     field public int version;
   }
 
+  public final class InstallSourceInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public String getInitiatingPackageName();
+    method @Nullable public String getInstallingPackageName();
+    method @Nullable public String getOriginatingPackageName();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.InstallSourceInfo> CREATOR;
+  }
+
   public class InstrumentationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
     ctor public InstrumentationInfo();
     ctor public InstrumentationInfo(android.content.pm.InstrumentationInfo);
@@ -11555,8 +11572,11 @@
     field public static final int STATUS_FAILURE_ABORTED = 3; // 0x3
     field public static final int STATUS_FAILURE_BLOCKED = 2; // 0x2
     field public static final int STATUS_FAILURE_CONFLICT = 5; // 0x5
+    field public static final int STATUS_FAILURE_ILLEGAL_STATE = 9; // 0x9
     field public static final int STATUS_FAILURE_INCOMPATIBLE = 7; // 0x7
     field public static final int STATUS_FAILURE_INVALID = 4; // 0x4
+    field public static final int STATUS_FAILURE_NAME_NOT_FOUND = 8; // 0x8
+    field public static final int STATUS_FAILURE_SECURITY = 10; // 0xa
     field public static final int STATUS_FAILURE_STORAGE = 6; // 0x6
     field public static final int STATUS_PENDING_USER_ACTION = -1; // 0xffffffff
     field public static final int STATUS_SUCCESS = 0; // 0x0
@@ -11578,6 +11598,7 @@
     method public void removeChildSessionId(int);
     method public void removeSplit(@NonNull String) throws java.io.IOException;
     method public void setStagingProgress(float);
+    method public void transfer(@NonNull String, @NonNull android.content.IntentSender) throws android.content.pm.PackageManager.NameNotFoundException;
     method public void transfer(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
   }
 
@@ -11717,10 +11738,11 @@
     method public abstract int getComponentEnabledSetting(@NonNull android.content.ComponentName);
     method @NonNull public abstract android.graphics.drawable.Drawable getDefaultActivityIcon();
     method @Nullable public abstract android.graphics.drawable.Drawable getDrawable(@NonNull String, @DrawableRes int, @Nullable android.content.pm.ApplicationInfo);
+    method @NonNull public android.content.pm.InstallSourceInfo getInstallSourceInfo(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
     method @NonNull public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
     method @NonNull public java.util.List<android.content.pm.ModuleInfo> getInstalledModules(int);
     method @NonNull public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
-    method @Nullable public abstract String getInstallerPackageName(@NonNull String);
+    method @Deprecated @Nullable public abstract String getInstallerPackageName(@NonNull String);
     method @NonNull public abstract byte[] getInstantAppCookie();
     method public abstract int getInstantAppCookieMaxBytes();
     method @NonNull public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(@NonNull android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -13431,6 +13453,7 @@
     method public android.drm.DrmConvertedStatus closeConvertSession(int);
     method public android.drm.DrmConvertedStatus convertData(int, byte[]);
     method public String[] getAvailableDrmEngines();
+    method @NonNull public java.util.Collection<android.drm.DrmSupportInfo> getAvailableDrmSupportInfo();
     method public android.content.ContentValues getConstraints(String, int);
     method public android.content.ContentValues getConstraints(android.net.Uri, int);
     method public int getDrmObjectType(String, String);
@@ -22955,6 +22978,7 @@
     method public int getAccumulatedDeltaRangeState();
     method public double getAccumulatedDeltaRangeUncertaintyMeters();
     method public double getAutomaticGainControlLevelDb();
+    method @FloatRange(from=0, to=50) public double getBasebandCn0DbHz();
     method @Deprecated public long getCarrierCycles();
     method public float getCarrierFrequencyHz();
     method @Deprecated public double getCarrierPhase();
@@ -22972,6 +22996,7 @@
     method public int getSvid();
     method public double getTimeOffsetNanos();
     method public boolean hasAutomaticGainControlLevelDb();
+    method public boolean hasBasebandCn0DbHz();
     method @Deprecated public boolean hasCarrierCycles();
     method public boolean hasCarrierFrequencyHz();
     method @Deprecated public boolean hasCarrierPhase();
@@ -23063,6 +23088,7 @@
 
   public final class GnssStatus {
     method @FloatRange(from=0, to=360) public float getAzimuthDegrees(@IntRange(from=0) int);
+    method @FloatRange(from=0, to=63) public float getBasebandCn0DbHz(@IntRange(from=0) int);
     method @FloatRange(from=0) public float getCarrierFrequencyHz(@IntRange(from=0) int);
     method @FloatRange(from=0, to=63) public float getCn0DbHz(@IntRange(from=0) int);
     method public int getConstellationType(@IntRange(from=0) int);
@@ -23070,6 +23096,7 @@
     method @IntRange(from=0) public int getSatelliteCount();
     method @IntRange(from=1, to=200) public int getSvid(@IntRange(from=0) int);
     method public boolean hasAlmanacData(@IntRange(from=0) int);
+    method public boolean hasBasebandCn0DbHz(@IntRange(from=0) int);
     method public boolean hasCarrierFrequencyHz(@IntRange(from=0) int);
     method public boolean hasEphemerisData(@IntRange(from=0) int);
     method public boolean usedInFix(@IntRange(from=0) int);
@@ -23085,7 +23112,7 @@
 
   public static final class GnssStatus.Builder {
     ctor public GnssStatus.Builder();
-    method @NonNull public android.location.GnssStatus.Builder addSatellite(int, @IntRange(from=1, to=200) int, @FloatRange(from=0, to=63) float, @FloatRange(from=0xffffffa6, to=90) float, @FloatRange(from=0, to=360) float, boolean, boolean, boolean, boolean, @FloatRange(from=0) float);
+    method @NonNull public android.location.GnssStatus.Builder addSatellite(int, @IntRange(from=1, to=200) int, @FloatRange(from=0, to=63) float, @FloatRange(from=0xffffffa6, to=90) float, @FloatRange(from=0, to=360) float, boolean, boolean, boolean, boolean, @FloatRange(from=0) float, boolean, @FloatRange(from=0, to=63) float);
     method @NonNull public android.location.GnssStatus build();
     method @NonNull public android.location.GnssStatus.Builder clearSatellites();
   }
@@ -23251,6 +23278,8 @@
     method public void unregisterGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
     method public void unregisterGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback);
     method public void unregisterGnssStatusCallback(@NonNull android.location.GnssStatus.Callback);
+    field public static final String EXTRA_LOCATION_ENABLED = "android.location.extra.LOCATION_ENABLED";
+    field public static final String EXTRA_PROVIDER_ENABLED = "android.location.extra.PROVIDER_ENABLED";
     field public static final String EXTRA_PROVIDER_NAME = "android.location.extra.PROVIDER_NAME";
     field public static final String GPS_PROVIDER = "gps";
     field public static final String KEY_LOCATION_CHANGED = "location";
@@ -23768,6 +23797,7 @@
     method public int getSampleRate();
     method public int getState();
     method public int getTimestamp(@NonNull android.media.AudioTimestamp, int);
+    method public boolean isPrivacySensitive();
     method public int read(@NonNull byte[], int, int);
     method public int read(@NonNull byte[], int, int, int);
     method public int read(@NonNull short[], int, int);
@@ -23810,6 +23840,7 @@
     method @NonNull public android.media.AudioRecord.Builder setAudioPlaybackCaptureConfig(@NonNull android.media.AudioPlaybackCaptureConfiguration);
     method public android.media.AudioRecord.Builder setAudioSource(int) throws java.lang.IllegalArgumentException;
     method public android.media.AudioRecord.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
+    method @NonNull public android.media.AudioRecord.Builder setPrivacySensitive(boolean);
   }
 
   public static final class AudioRecord.MetricsConstants {
@@ -25048,6 +25079,7 @@
     method @NonNull public java.util.List<byte[]> getSecureStopIds();
     method @NonNull public java.util.List<byte[]> getSecureStops();
     method @android.media.MediaDrm.SecurityLevel public int getSecurityLevel(@NonNull byte[]);
+    method @NonNull public static java.util.List<java.util.UUID> getSupportedCryptoSchemes();
     method public static boolean isCryptoSchemeSupported(@NonNull java.util.UUID);
     method public static boolean isCryptoSchemeSupported(@NonNull java.util.UUID, @NonNull String);
     method public static boolean isCryptoSchemeSupported(@NonNull java.util.UUID, @NonNull String, @android.media.MediaDrm.SecurityLevel int);
@@ -25335,6 +25367,8 @@
     field public static final String KEY_COMPLEXITY = "complexity";
     field public static final String KEY_CREATE_INPUT_SURFACE_SUSPENDED = "create-input-buffers-suspended";
     field public static final String KEY_DURATION = "durationUs";
+    field public static final String KEY_ENCODER_DELAY = "encoder-delay";
+    field public static final String KEY_ENCODER_PADDING = "encoder-padding";
     field public static final String KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
     field public static final String KEY_FRAME_RATE = "frame-rate";
     field public static final String KEY_GRID_COLUMNS = "grid-cols";
@@ -25588,6 +25622,50 @@
     field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1
   }
 
+  public final class MediaParser {
+    method public boolean advance(@NonNull android.media.MediaParser.SeekableInputReader) throws java.io.IOException, java.lang.InterruptedException;
+    method @NonNull public static android.media.MediaParser create(@NonNull android.media.MediaParser.OutputConsumer, @NonNull java.lang.String...);
+    method @NonNull public static android.media.MediaParser createByName(@NonNull String, @NonNull android.media.MediaParser.OutputConsumer);
+    method @Nullable public String getExtractorName();
+    method @NonNull public static java.util.List<java.lang.String> getExtractorNames(@NonNull android.media.MediaFormat);
+    method public void release();
+    method public void seek(@NonNull android.media.MediaParser.SeekPoint);
+  }
+
+  public static interface MediaParser.InputReader {
+    method public long getLength();
+    method public long getPosition();
+    method public int read(@NonNull byte[], int, int) throws java.io.IOException, java.lang.InterruptedException;
+  }
+
+  public static interface MediaParser.OutputConsumer {
+    method public void onFormat(int, @NonNull android.media.MediaFormat);
+    method public void onSampleCompleted(int, long, int, int, int, @Nullable android.media.MediaCodec.CryptoInfo);
+    method public void onSampleData(int, @NonNull android.media.MediaParser.InputReader) throws java.io.IOException, java.lang.InterruptedException;
+    method public void onSeekMap(@NonNull android.media.MediaParser.SeekMap);
+    method public void onTracksFound(int);
+  }
+
+  public static interface MediaParser.SeekMap {
+    method public long getDurationUs();
+    method @NonNull public android.util.Pair<android.media.MediaParser.SeekPoint,android.media.MediaParser.SeekPoint> getSeekPoints(long);
+    method public boolean isSeekable();
+    field public static final int UNKNOWN_DURATION = -2147483648; // 0x80000000
+  }
+
+  public static final class MediaParser.SeekPoint {
+    field @NonNull public static final android.media.MediaParser.SeekPoint START;
+    field public final long position;
+    field public final long timeUs;
+  }
+
+  public static interface MediaParser.SeekableInputReader extends android.media.MediaParser.InputReader {
+    method public void seekToPosition(long);
+  }
+
+  public static final class MediaParser.UnrecognizedInputFormatException extends java.io.IOException {
+  }
+
   public class MediaPlayer implements android.media.AudioRouting android.media.VolumeAutomation {
     ctor public MediaPlayer();
     method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
@@ -25828,6 +25906,7 @@
     method public android.media.AudioDeviceInfo getPreferredDevice();
     method public android.media.AudioDeviceInfo getRoutedDevice();
     method public android.view.Surface getSurface();
+    method public boolean isPrivacySensitive();
     method public void pause() throws java.lang.IllegalStateException;
     method public void prepare() throws java.io.IOException, java.lang.IllegalStateException;
     method public void registerAudioRecordingCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioRecordingCallback);
@@ -25859,6 +25938,7 @@
     method public boolean setPreferredMicrophoneDirection(int);
     method public boolean setPreferredMicrophoneFieldDimension(@FloatRange(from=-1.0, to=1.0) float);
     method public void setPreviewDisplay(android.view.Surface);
+    method public void setPrivacySensitive(boolean);
     method public void setProfile(android.media.CamcorderProfile);
     method public void setVideoEncoder(int) throws java.lang.IllegalStateException;
     method public void setVideoEncodingBitRate(int);
@@ -28925,6 +29005,7 @@
     method @Nullable public String getInterfaceName();
     method @NonNull public java.util.List<android.net.LinkAddress> getLinkAddresses();
     method public int getMtu();
+    method @Nullable public android.net.IpPrefix getNat64Prefix();
     method @Nullable public String getPrivateDnsServerName();
     method @NonNull public java.util.List<android.net.RouteInfo> getRoutes();
     method public boolean isPrivateDnsActive();
@@ -28935,6 +29016,7 @@
     method public void setInterfaceName(@Nullable String);
     method public void setLinkAddresses(@NonNull java.util.Collection<android.net.LinkAddress>);
     method public void setMtu(int);
+    method public void setNat64Prefix(@Nullable android.net.IpPrefix);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.LinkProperties> CREATOR;
   }
@@ -29250,12 +29332,14 @@
     method public static long getMobileRxPackets();
     method public static long getMobileTxBytes();
     method public static long getMobileTxPackets();
+    method public static long getRxPackets(@NonNull String);
     method public static int getThreadStatsTag();
     method public static int getThreadStatsUid();
     method public static long getTotalRxBytes();
     method public static long getTotalRxPackets();
     method public static long getTotalTxBytes();
     method public static long getTotalTxPackets();
+    method public static long getTxPackets(@NonNull String);
     method public static long getUidRxBytes(int);
     method public static long getUidRxPackets(int);
     method @Deprecated public static long getUidTcpRxBytes(int);
@@ -29889,6 +29973,7 @@
     ctor @Deprecated public WifiConfiguration();
     method public int describeContents();
     method @Deprecated public android.net.ProxyInfo getHttpProxy();
+    method @Deprecated @NonNull public String getKey();
     method @Deprecated @NonNull public android.net.MacAddress getRandomizedMacAddress();
     method @Deprecated public boolean isPasspoint();
     method @Deprecated public void setHttpProxy(android.net.ProxyInfo);
@@ -30243,6 +30328,7 @@
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsEnhancedOpen(boolean);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsHiddenSsid(boolean);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsMetered(boolean);
+    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsUserAllowedToManuallyConnect(boolean);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsUserInteractionRequired(boolean);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPasspointConfig(@NonNull android.net.wifi.hotspot2.PasspointConfiguration);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriority(@IntRange(from=0) int);
@@ -30564,6 +30650,7 @@
     method @Nullable public android.net.wifi.p2p.WifiP2pWfdInfo getWfdInfo();
     method public boolean isGroupOwner();
     method public boolean isServiceDiscoveryCapable();
+    method public void update(@NonNull android.net.wifi.p2p.WifiP2pDevice);
     method public boolean wpsDisplaySupported();
     method public boolean wpsKeypadSupported();
     method public boolean wpsPbcSupported();
@@ -36856,6 +36943,7 @@
     method @WorkerThread public static boolean isBlocked(android.content.Context, String);
     method @WorkerThread public static int unblock(android.content.Context, String);
     field public static final String AUTHORITY = "com.android.blockednumber";
+    field public static final android.net.Uri AUTHORITY_URI;
   }
 
   public static class BlockedNumberContract.BlockedNumbers {
@@ -38595,15 +38683,13 @@
     ctor public MediaStore();
     method @Nullable public static android.net.Uri getDocumentUri(@NonNull android.content.Context, @NonNull android.net.Uri);
     method @NonNull public static java.util.Set<java.lang.String> getExternalVolumeNames(@NonNull android.content.Context);
-    method public static boolean getIncludePending(@NonNull android.net.Uri);
     method public static android.net.Uri getMediaScannerUri();
     method @Nullable public static android.net.Uri getMediaUri(@NonNull android.content.Context, @NonNull android.net.Uri);
     method public static boolean getRequireOriginal(@NonNull android.net.Uri);
     method @NonNull public static String getVersion(@NonNull android.content.Context);
     method @NonNull public static String getVersion(@NonNull android.content.Context, @NonNull String);
     method @NonNull public static String getVolumeName(@NonNull android.net.Uri);
-    method @NonNull public static android.net.Uri setIncludePending(@NonNull android.net.Uri);
-    method @NonNull public static android.net.Uri setIncludeTrashed(@NonNull android.net.Uri);
+    method @Deprecated @NonNull public static android.net.Uri setIncludePending(@NonNull android.net.Uri);
     method @NonNull public static android.net.Uri setRequireOriginal(@NonNull android.net.Uri);
     method public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri);
     method public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri, long);
@@ -38639,9 +38725,17 @@
     field public static final String INTENT_ACTION_TEXT_OPEN_FROM_SEARCH = "android.media.action.TEXT_OPEN_FROM_SEARCH";
     field public static final String INTENT_ACTION_VIDEO_CAMERA = "android.media.action.VIDEO_CAMERA";
     field public static final String INTENT_ACTION_VIDEO_PLAY_FROM_SEARCH = "android.media.action.VIDEO_PLAY_FROM_SEARCH";
+    field public static final int MATCH_DEFAULT = 0; // 0x0
+    field public static final int MATCH_EXCLUDE = 2; // 0x2
+    field public static final int MATCH_INCLUDE = 1; // 0x1
+    field public static final int MATCH_ONLY = 3; // 0x3
     field public static final String MEDIA_IGNORE_FILENAME = ".nomedia";
     field public static final String MEDIA_SCANNER_VOLUME = "volume";
     field public static final String META_DATA_STILL_IMAGE_CAMERA_PREWARM_SERVICE = "android.media.still_image_camera_preview_service";
+    field public static final String QUERY_ARG_MATCH_FAVORITE = "android:query-arg-match-favorite";
+    field public static final String QUERY_ARG_MATCH_PENDING = "android:query-arg-match-pending";
+    field public static final String QUERY_ARG_MATCH_TRASHED = "android:query-arg-match-trashed";
+    field public static final String QUERY_ARG_RELATED_URI = "android:query-arg-related-uri";
     field public static final String UNKNOWN_STRING = "<unknown>";
     field public static final String VOLUME_EXTERNAL = "external";
     field public static final String VOLUME_EXTERNAL_PRIMARY = "external_primary";
@@ -38816,6 +38910,7 @@
     field public static final int MEDIA_TYPE_IMAGE = 1; // 0x1
     field public static final int MEDIA_TYPE_NONE = 0; // 0x0
     field public static final int MEDIA_TYPE_PLAYLIST = 4; // 0x4
+    field public static final int MEDIA_TYPE_SUBTITLE = 5; // 0x5
     field public static final int MEDIA_TYPE_VIDEO = 3; // 0x3
     field public static final String MIME_TYPE = "mime_type";
     field public static final String PARENT = "parent";
@@ -41525,6 +41620,7 @@
     field public static final int FLAG_DONT_SAVE_ON_FINISH = 2; // 0x2
     field public static final int FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE = 1; // 0x1
     field public static final int NEGATIVE_BUTTON_STYLE_CANCEL = 0; // 0x0
+    field public static final int NEGATIVE_BUTTON_STYLE_NEVER = 2; // 0x2
     field public static final int NEGATIVE_BUTTON_STYLE_REJECT = 1; // 0x1
     field public static final int POSITIVE_BUTTON_STYLE_CONTINUE = 1; // 0x1
     field public static final int POSITIVE_BUTTON_STYLE_SAVE = 0; // 0x0
@@ -42734,6 +42830,7 @@
     method public static String[] listxattr(String) throws android.system.ErrnoException;
     method public static long lseek(java.io.FileDescriptor, long, int) throws android.system.ErrnoException;
     method public static android.system.StructStat lstat(String) throws android.system.ErrnoException;
+    method @NonNull public static java.io.FileDescriptor memfd_create(@NonNull String, int) throws android.system.ErrnoException;
     method public static void mincore(long, long, byte[]) throws android.system.ErrnoException;
     method public static void mkdir(String, int) throws android.system.ErrnoException;
     method public static void mkfifo(String, int) throws android.system.ErrnoException;
@@ -43042,6 +43139,7 @@
     field public static final int MCAST_UNBLOCK_SOURCE;
     field public static final int MCL_CURRENT;
     field public static final int MCL_FUTURE;
+    field public static final int MFD_CLOEXEC;
     field public static final int MSG_CTRUNC;
     field public static final int MSG_DONTROUTE;
     field public static final int MSG_EOR;
@@ -43053,6 +43151,7 @@
     field public static final int MS_INVALIDATE;
     field public static final int MS_SYNC;
     field public static final int NETLINK_INET_DIAG;
+    field public static final int NETLINK_NETFILTER;
     field public static final int NETLINK_ROUTE;
     field public static final int NI_DGRAM;
     field public static final int NI_NAMEREQD;
@@ -43463,6 +43562,7 @@
     method public int getCallProperties();
     method public String getCallerDisplayName();
     method public int getCallerDisplayNamePresentation();
+    method public int getCallerNumberVerificationStatus();
     method public final long getConnectTimeMillis();
     method public long getCreationTimeMillis();
     method public android.telecom.DisconnectCause getDisconnectCause();
@@ -43644,6 +43744,7 @@
     method public final android.telecom.CallAudioState getCallAudioState();
     method public final String getCallerDisplayName();
     method public final int getCallerDisplayNamePresentation();
+    method public int getCallerNumberVerificationStatus();
     method public final android.telecom.Conference getConference();
     method public final java.util.List<android.telecom.Conferenceable> getConferenceables();
     method public final int getConnectionCapabilities();
@@ -43695,6 +43796,7 @@
     method public final void setAudioModeIsVoip(boolean);
     method public final void setAudioRoute(int);
     method public final void setCallerDisplayName(String, int);
+    method public void setCallerNumberVerificationStatus(int);
     method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
     method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>);
     method public final void setConnectionCapabilities(int);
@@ -43714,6 +43816,27 @@
     method public final void setVideoProvider(android.telecom.Connection.VideoProvider);
     method public final void setVideoState(int);
     method public static String stateToString(int);
+    field public static final int AUDIO_CODEC_AMR = 1; // 0x1
+    field public static final int AUDIO_CODEC_AMR_WB = 2; // 0x2
+    field public static final int AUDIO_CODEC_EVRC = 4; // 0x4
+    field public static final int AUDIO_CODEC_EVRC_B = 5; // 0x5
+    field public static final int AUDIO_CODEC_EVRC_NW = 7; // 0x7
+    field public static final int AUDIO_CODEC_EVRC_WB = 6; // 0x6
+    field public static final int AUDIO_CODEC_EVS_FB = 20; // 0x14
+    field public static final int AUDIO_CODEC_EVS_NB = 17; // 0x11
+    field public static final int AUDIO_CODEC_EVS_SWB = 19; // 0x13
+    field public static final int AUDIO_CODEC_EVS_WB = 18; // 0x12
+    field public static final int AUDIO_CODEC_G711A = 13; // 0xd
+    field public static final int AUDIO_CODEC_G711AB = 15; // 0xf
+    field public static final int AUDIO_CODEC_G711U = 11; // 0xb
+    field public static final int AUDIO_CODEC_G722 = 14; // 0xe
+    field public static final int AUDIO_CODEC_G723 = 12; // 0xc
+    field public static final int AUDIO_CODEC_G729 = 16; // 0x10
+    field public static final int AUDIO_CODEC_GSM_EFR = 8; // 0x8
+    field public static final int AUDIO_CODEC_GSM_FR = 9; // 0x9
+    field public static final int AUDIO_CODEC_GSM_HR = 10; // 0xa
+    field public static final int AUDIO_CODEC_NONE = 0; // 0x0
+    field public static final int AUDIO_CODEC_QCELP13K = 3; // 0x3
     field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 8388608; // 0x800000
     field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
     field public static final int CAPABILITY_CAN_PULL_CALL = 16777216; // 0x1000000
@@ -43747,6 +43870,7 @@
     field public static final String EVENT_RTT_AUDIO_INDICATION_CHANGED = "android.telecom.event.RTT_AUDIO_INDICATION_CHANGED";
     field public static final String EXTRA_ANSWERING_DROPS_FG_CALL = "android.telecom.extra.ANSWERING_DROPS_FG_CALL";
     field public static final String EXTRA_ANSWERING_DROPS_FG_CALL_APP_NAME = "android.telecom.extra.ANSWERING_DROPS_FG_CALL_APP_NAME";
+    field public static final String EXTRA_AUDIO_CODEC = "android.telecom.extra.AUDIO_CODEC";
     field public static final String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
     field public static final String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
     field public static final String EXTRA_IS_RTT_AUDIO_PRESENT = "android.telecom.extra.IS_RTT_AUDIO_PRESENT";
@@ -43768,6 +43892,9 @@
     field public static final int STATE_NEW = 1; // 0x1
     field public static final int STATE_PULLING_CALL = 7; // 0x7
     field public static final int STATE_RINGING = 2; // 0x2
+    field public static final int VERIFICATION_STATUS_FAILED = 2; // 0x2
+    field public static final int VERIFICATION_STATUS_NOT_VERIFIED = 0; // 0x0
+    field public static final int VERIFICATION_STATUS_PASSED = 1; // 0x1
   }
 
   public static final class Connection.RttModifyStatus {
@@ -44281,6 +44408,7 @@
     field public static final int EUTRAN = 3; // 0x3
     field public static final int GERAN = 1; // 0x1
     field public static final int IWLAN = 5; // 0x5
+    field public static final int NGRAN = 6; // 0x6
     field public static final int UNKNOWN = 0; // 0x0
     field public static final int UTRAN = 2; // 0x2
   }
@@ -44353,6 +44481,52 @@
     field public static final int BAND_T810 = 7; // 0x7
   }
 
+  public static final class AccessNetworkConstants.NgranBands {
+    field public static final int BAND_1 = 1; // 0x1
+    field public static final int BAND_12 = 12; // 0xc
+    field public static final int BAND_14 = 14; // 0xe
+    field public static final int BAND_18 = 18; // 0x12
+    field public static final int BAND_2 = 2; // 0x2
+    field public static final int BAND_20 = 20; // 0x14
+    field public static final int BAND_25 = 25; // 0x19
+    field public static final int BAND_257 = 257; // 0x101
+    field public static final int BAND_258 = 258; // 0x102
+    field public static final int BAND_260 = 260; // 0x104
+    field public static final int BAND_261 = 261; // 0x105
+    field public static final int BAND_28 = 28; // 0x1c
+    field public static final int BAND_29 = 29; // 0x1d
+    field public static final int BAND_3 = 3; // 0x3
+    field public static final int BAND_30 = 30; // 0x1e
+    field public static final int BAND_34 = 34; // 0x22
+    field public static final int BAND_38 = 38; // 0x26
+    field public static final int BAND_39 = 39; // 0x27
+    field public static final int BAND_40 = 40; // 0x28
+    field public static final int BAND_41 = 41; // 0x29
+    field public static final int BAND_48 = 48; // 0x30
+    field public static final int BAND_5 = 5; // 0x5
+    field public static final int BAND_50 = 50; // 0x32
+    field public static final int BAND_51 = 51; // 0x33
+    field public static final int BAND_65 = 65; // 0x41
+    field public static final int BAND_66 = 66; // 0x42
+    field public static final int BAND_7 = 7; // 0x7
+    field public static final int BAND_70 = 70; // 0x46
+    field public static final int BAND_71 = 71; // 0x47
+    field public static final int BAND_74 = 74; // 0x4a
+    field public static final int BAND_75 = 75; // 0x4b
+    field public static final int BAND_76 = 76; // 0x4c
+    field public static final int BAND_77 = 77; // 0x4d
+    field public static final int BAND_78 = 78; // 0x4e
+    field public static final int BAND_79 = 79; // 0x4f
+    field public static final int BAND_8 = 8; // 0x8
+    field public static final int BAND_80 = 80; // 0x50
+    field public static final int BAND_81 = 81; // 0x51
+    field public static final int BAND_82 = 82; // 0x52
+    field public static final int BAND_83 = 83; // 0x53
+    field public static final int BAND_84 = 84; // 0x54
+    field public static final int BAND_86 = 86; // 0x56
+    field public static final int BAND_90 = 90; // 0x5a
+  }
+
   public static final class AccessNetworkConstants.UtranBand {
     field public static final int BAND_1 = 1; // 0x1
     field public static final int BAND_10 = 10; // 0xa
@@ -44468,6 +44642,7 @@
     field public static final String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
     field public static final String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array";
     field public static final String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
+    field public static final String KEY_DISABLE_SUPPLEMENTARY_SERVICES_IN_AIRPLANE_MODE_BOOL = "disable_supplementary_services_in_airplane_mode_bool";
     field public static final String KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY = "disconnect_cause_play_busytone_int_array";
     field public static final String KEY_DISPLAY_HD_AUDIO_PROPERTY_BOOL = "display_hd_audio_property_bool";
     field public static final String KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL = "drop_video_call_when_answering_audio_call_bool";
@@ -44536,7 +44711,6 @@
     field public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT = "opportunistic_network_entry_threshold_rssnr_int";
     field public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT = "opportunistic_network_exit_threshold_rsrp_int";
     field public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT = "opportunistic_network_exit_threshold_rssnr_int";
-    field public static final String KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT = "parameters_use_for_5g_nr_signal_bar_int";
     field public static final String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
     field public static final String KEY_PREVENT_CLIR_ACTIVATION_AND_DEACTIVATION_CODE_BOOL = "prevent_clir_activation_and_deactivation_code_bool";
     field public static final String KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY = "radio_restart_failure_causes_int_array";
@@ -44738,6 +44912,7 @@
     method public abstract int getAsuLevel();
     method public abstract int getDbm();
     method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public abstract int getLevel();
+    method public static final int getNumSignalStrengthLevels();
     method public abstract int hashCode();
     field public static final int SIGNAL_STRENGTH_GOOD = 3; // 0x3
     field public static final int SIGNAL_STRENGTH_GREAT = 4; // 0x4
@@ -44936,6 +45111,12 @@
     field public static final int SCAN_TYPE_PERIODIC = 1; // 0x1
   }
 
+  public final class PhoneCapability implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PhoneCapability> CREATOR;
+  }
+
   public class PhoneNumberFormattingTextWatcher implements android.text.TextWatcher {
     ctor public PhoneNumberFormattingTextWatcher();
     ctor public PhoneNumberFormattingTextWatcher(String);
@@ -45981,6 +46162,193 @@
 
 }
 
+package android.telephony.ims {
+
+  public final class ImsReasonInfo implements android.os.Parcelable {
+    ctor public ImsReasonInfo(int, int, @Nullable String);
+    method public int describeContents();
+    method public int getCode();
+    method public int getExtraCode();
+    method @Nullable public String getExtraMessage();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int CODE_ACCESS_CLASS_BLOCKED = 1512; // 0x5e8
+    field public static final int CODE_ANSWERED_ELSEWHERE = 1014; // 0x3f6
+    field public static final int CODE_BLACKLISTED_CALL_ID = 506; // 0x1fa
+    field public static final int CODE_CALL_BARRED = 240; // 0xf0
+    field public static final int CODE_CALL_DROP_IWLAN_TO_LTE_UNAVAILABLE = 1100; // 0x44c
+    field public static final int CODE_CALL_END_CAUSE_CALL_PULL = 1016; // 0x3f8
+    field public static final int CODE_CALL_PULL_OUT_OF_SYNC = 1015; // 0x3f7
+    field public static final int CODE_DATA_DISABLED = 1406; // 0x57e
+    field public static final int CODE_DATA_LIMIT_REACHED = 1405; // 0x57d
+    field public static final int CODE_DIAL_MODIFIED_TO_DIAL = 246; // 0xf6
+    field public static final int CODE_DIAL_MODIFIED_TO_DIAL_VIDEO = 247; // 0xf7
+    field public static final int CODE_DIAL_MODIFIED_TO_SS = 245; // 0xf5
+    field public static final int CODE_DIAL_MODIFIED_TO_USSD = 244; // 0xf4
+    field public static final int CODE_DIAL_VIDEO_MODIFIED_TO_DIAL = 248; // 0xf8
+    field public static final int CODE_DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO = 249; // 0xf9
+    field public static final int CODE_DIAL_VIDEO_MODIFIED_TO_SS = 250; // 0xfa
+    field public static final int CODE_DIAL_VIDEO_MODIFIED_TO_USSD = 251; // 0xfb
+    field public static final int CODE_ECBM_NOT_SUPPORTED = 901; // 0x385
+    field public static final int CODE_EMERGENCY_PERM_FAILURE = 364; // 0x16c
+    field public static final int CODE_EMERGENCY_TEMP_FAILURE = 363; // 0x16b
+    field public static final int CODE_EPDG_TUNNEL_ESTABLISH_FAILURE = 1400; // 0x578
+    field public static final int CODE_EPDG_TUNNEL_LOST_CONNECTION = 1402; // 0x57a
+    field public static final int CODE_EPDG_TUNNEL_REKEY_FAILURE = 1401; // 0x579
+    field public static final int CODE_FDN_BLOCKED = 241; // 0xf1
+    field public static final int CODE_IKEV2_AUTH_FAILURE = 1408; // 0x580
+    field public static final int CODE_IMEI_NOT_ACCEPTED = 243; // 0xf3
+    field public static final int CODE_IWLAN_DPD_FAILURE = 1300; // 0x514
+    field public static final int CODE_LOCAL_CALL_BUSY = 142; // 0x8e
+    field public static final int CODE_LOCAL_CALL_CS_RETRY_REQUIRED = 146; // 0x92
+    field public static final int CODE_LOCAL_CALL_DECLINE = 143; // 0x8f
+    field public static final int CODE_LOCAL_CALL_EXCEEDED = 141; // 0x8d
+    field public static final int CODE_LOCAL_CALL_RESOURCE_RESERVATION_FAILED = 145; // 0x91
+    field public static final int CODE_LOCAL_CALL_TERMINATED = 148; // 0x94
+    field public static final int CODE_LOCAL_CALL_VCC_ON_PROGRESSING = 144; // 0x90
+    field public static final int CODE_LOCAL_CALL_VOLTE_RETRY_REQUIRED = 147; // 0x93
+    field public static final int CODE_LOCAL_ENDED_BY_CONFERENCE_MERGE = 108; // 0x6c
+    field public static final int CODE_LOCAL_HO_NOT_FEASIBLE = 149; // 0x95
+    field public static final int CODE_LOCAL_ILLEGAL_ARGUMENT = 101; // 0x65
+    field public static final int CODE_LOCAL_ILLEGAL_STATE = 102; // 0x66
+    field public static final int CODE_LOCAL_IMS_SERVICE_DOWN = 106; // 0x6a
+    field public static final int CODE_LOCAL_INTERNAL_ERROR = 103; // 0x67
+    field public static final int CODE_LOCAL_LOW_BATTERY = 112; // 0x70
+    field public static final int CODE_LOCAL_NETWORK_IP_CHANGED = 124; // 0x7c
+    field public static final int CODE_LOCAL_NETWORK_NO_LTE_COVERAGE = 122; // 0x7a
+    field public static final int CODE_LOCAL_NETWORK_NO_SERVICE = 121; // 0x79
+    field public static final int CODE_LOCAL_NETWORK_ROAMING = 123; // 0x7b
+    field public static final int CODE_LOCAL_NOT_REGISTERED = 132; // 0x84
+    field public static final int CODE_LOCAL_NO_PENDING_CALL = 107; // 0x6b
+    field public static final int CODE_LOCAL_POWER_OFF = 111; // 0x6f
+    field public static final int CODE_LOCAL_SERVICE_UNAVAILABLE = 131; // 0x83
+    field public static final int CODE_LOW_BATTERY = 505; // 0x1f9
+    field public static final int CODE_MAXIMUM_NUMBER_OF_CALLS_REACHED = 1403; // 0x57b
+    field public static final int CODE_MEDIA_INIT_FAILED = 401; // 0x191
+    field public static final int CODE_MEDIA_NOT_ACCEPTABLE = 403; // 0x193
+    field public static final int CODE_MEDIA_NO_DATA = 402; // 0x192
+    field public static final int CODE_MEDIA_UNSPECIFIED = 404; // 0x194
+    field public static final int CODE_MULTIENDPOINT_NOT_SUPPORTED = 902; // 0x386
+    field public static final int CODE_NETWORK_DETACH = 1513; // 0x5e9
+    field public static final int CODE_NETWORK_REJECT = 1504; // 0x5e0
+    field public static final int CODE_NETWORK_RESP_TIMEOUT = 1503; // 0x5df
+    field public static final int CODE_NO_CSFB_IN_CS_ROAM = 1516; // 0x5ec
+    field public static final int CODE_NO_VALID_SIM = 1501; // 0x5dd
+    field public static final int CODE_OEM_CAUSE_1 = 61441; // 0xf001
+    field public static final int CODE_OEM_CAUSE_10 = 61450; // 0xf00a
+    field public static final int CODE_OEM_CAUSE_11 = 61451; // 0xf00b
+    field public static final int CODE_OEM_CAUSE_12 = 61452; // 0xf00c
+    field public static final int CODE_OEM_CAUSE_13 = 61453; // 0xf00d
+    field public static final int CODE_OEM_CAUSE_14 = 61454; // 0xf00e
+    field public static final int CODE_OEM_CAUSE_15 = 61455; // 0xf00f
+    field public static final int CODE_OEM_CAUSE_2 = 61442; // 0xf002
+    field public static final int CODE_OEM_CAUSE_3 = 61443; // 0xf003
+    field public static final int CODE_OEM_CAUSE_4 = 61444; // 0xf004
+    field public static final int CODE_OEM_CAUSE_5 = 61445; // 0xf005
+    field public static final int CODE_OEM_CAUSE_6 = 61446; // 0xf006
+    field public static final int CODE_OEM_CAUSE_7 = 61447; // 0xf007
+    field public static final int CODE_OEM_CAUSE_8 = 61448; // 0xf008
+    field public static final int CODE_OEM_CAUSE_9 = 61449; // 0xf009
+    field public static final int CODE_RADIO_ACCESS_FAILURE = 1505; // 0x5e1
+    field public static final int CODE_RADIO_INTERNAL_ERROR = 1502; // 0x5de
+    field public static final int CODE_RADIO_LINK_FAILURE = 1506; // 0x5e2
+    field public static final int CODE_RADIO_LINK_LOST = 1507; // 0x5e3
+    field public static final int CODE_RADIO_OFF = 1500; // 0x5dc
+    field public static final int CODE_RADIO_RELEASE_ABNORMAL = 1511; // 0x5e7
+    field public static final int CODE_RADIO_RELEASE_NORMAL = 1510; // 0x5e6
+    field public static final int CODE_RADIO_SETUP_FAILURE = 1509; // 0x5e5
+    field public static final int CODE_RADIO_UPLINK_FAILURE = 1508; // 0x5e4
+    field public static final int CODE_REGISTRATION_ERROR = 1000; // 0x3e8
+    field public static final int CODE_REJECTED_ELSEWHERE = 1017; // 0x3f9
+    field public static final int CODE_REJECT_1X_COLLISION = 1603; // 0x643
+    field public static final int CODE_REJECT_CALL_ON_OTHER_SUB = 1602; // 0x642
+    field public static final int CODE_REJECT_CALL_TYPE_NOT_ALLOWED = 1605; // 0x645
+    field public static final int CODE_REJECT_CONFERENCE_TTY_NOT_ALLOWED = 1617; // 0x651
+    field public static final int CODE_REJECT_INTERNAL_ERROR = 1612; // 0x64c
+    field public static final int CODE_REJECT_MAX_CALL_LIMIT_REACHED = 1608; // 0x648
+    field public static final int CODE_REJECT_ONGOING_CALL_SETUP = 1607; // 0x647
+    field public static final int CODE_REJECT_ONGOING_CALL_TRANSFER = 1611; // 0x64b
+    field public static final int CODE_REJECT_ONGOING_CALL_UPGRADE = 1616; // 0x650
+    field public static final int CODE_REJECT_ONGOING_CALL_WAITING_DISABLED = 1601; // 0x641
+    field public static final int CODE_REJECT_ONGOING_CONFERENCE_CALL = 1618; // 0x652
+    field public static final int CODE_REJECT_ONGOING_CS_CALL = 1621; // 0x655
+    field public static final int CODE_REJECT_ONGOING_E911_CALL = 1606; // 0x646
+    field public static final int CODE_REJECT_ONGOING_ENCRYPTED_CALL = 1620; // 0x654
+    field public static final int CODE_REJECT_ONGOING_HANDOVER = 1614; // 0x64e
+    field public static final int CODE_REJECT_QOS_FAILURE = 1613; // 0x64d
+    field public static final int CODE_REJECT_SERVICE_NOT_REGISTERED = 1604; // 0x644
+    field public static final int CODE_REJECT_UNKNOWN = 1600; // 0x640
+    field public static final int CODE_REJECT_UNSUPPORTED_SDP_HEADERS = 1610; // 0x64a
+    field public static final int CODE_REJECT_UNSUPPORTED_SIP_HEADERS = 1609; // 0x649
+    field public static final int CODE_REJECT_VT_AVPF_NOT_ALLOWED = 1619; // 0x653
+    field public static final int CODE_REJECT_VT_TTY_NOT_ALLOWED = 1615; // 0x64f
+    field public static final int CODE_REMOTE_CALL_DECLINE = 1404; // 0x57c
+    field public static final int CODE_SESSION_MODIFICATION_FAILED = 1517; // 0x5ed
+    field public static final int CODE_SIP_ALTERNATE_EMERGENCY_CALL = 1514; // 0x5ea
+    field public static final int CODE_SIP_AMBIGUOUS = 376; // 0x178
+    field public static final int CODE_SIP_BAD_ADDRESS = 337; // 0x151
+    field public static final int CODE_SIP_BAD_REQUEST = 331; // 0x14b
+    field public static final int CODE_SIP_BUSY = 338; // 0x152
+    field public static final int CODE_SIP_CALL_OR_TRANS_DOES_NOT_EXIST = 372; // 0x174
+    field public static final int CODE_SIP_CLIENT_ERROR = 342; // 0x156
+    field public static final int CODE_SIP_EXTENSION_REQUIRED = 370; // 0x172
+    field public static final int CODE_SIP_FORBIDDEN = 332; // 0x14c
+    field public static final int CODE_SIP_GLOBAL_ERROR = 362; // 0x16a
+    field public static final int CODE_SIP_INTERVAL_TOO_BRIEF = 371; // 0x173
+    field public static final int CODE_SIP_LOOP_DETECTED = 373; // 0x175
+    field public static final int CODE_SIP_METHOD_NOT_ALLOWED = 366; // 0x16e
+    field public static final int CODE_SIP_NOT_ACCEPTABLE = 340; // 0x154
+    field public static final int CODE_SIP_NOT_FOUND = 333; // 0x14d
+    field public static final int CODE_SIP_NOT_REACHABLE = 341; // 0x155
+    field public static final int CODE_SIP_NOT_SUPPORTED = 334; // 0x14e
+    field public static final int CODE_SIP_PROXY_AUTHENTICATION_REQUIRED = 367; // 0x16f
+    field public static final int CODE_SIP_REDIRECTED = 321; // 0x141
+    field public static final int CODE_SIP_REQUEST_CANCELLED = 339; // 0x153
+    field public static final int CODE_SIP_REQUEST_ENTITY_TOO_LARGE = 368; // 0x170
+    field public static final int CODE_SIP_REQUEST_PENDING = 377; // 0x179
+    field public static final int CODE_SIP_REQUEST_TIMEOUT = 335; // 0x14f
+    field public static final int CODE_SIP_REQUEST_URI_TOO_LARGE = 369; // 0x171
+    field public static final int CODE_SIP_SERVER_ERROR = 354; // 0x162
+    field public static final int CODE_SIP_SERVER_INTERNAL_ERROR = 351; // 0x15f
+    field public static final int CODE_SIP_SERVER_TIMEOUT = 353; // 0x161
+    field public static final int CODE_SIP_SERVICE_UNAVAILABLE = 352; // 0x160
+    field public static final int CODE_SIP_TEMPRARILY_UNAVAILABLE = 336; // 0x150
+    field public static final int CODE_SIP_TOO_MANY_HOPS = 374; // 0x176
+    field public static final int CODE_SIP_TRANSACTION_DOES_NOT_EXIST = 343; // 0x157
+    field public static final int CODE_SIP_UNDECIPHERABLE = 378; // 0x17a
+    field public static final int CODE_SIP_USER_MARKED_UNWANTED = 365; // 0x16d
+    field public static final int CODE_SIP_USER_REJECTED = 361; // 0x169
+    field public static final int CODE_SUPP_SVC_CANCELLED = 1202; // 0x4b2
+    field public static final int CODE_SUPP_SVC_FAILED = 1201; // 0x4b1
+    field public static final int CODE_SUPP_SVC_REINVITE_COLLISION = 1203; // 0x4b3
+    field public static final int CODE_TIMEOUT_1XX_WAITING = 201; // 0xc9
+    field public static final int CODE_TIMEOUT_NO_ANSWER = 202; // 0xca
+    field public static final int CODE_TIMEOUT_NO_ANSWER_CALL_UPDATE = 203; // 0xcb
+    field public static final int CODE_UNSPECIFIED = 0; // 0x0
+    field public static final int CODE_USER_CANCELLED_SESSION_MODIFICATION = 512; // 0x200
+    field public static final int CODE_USER_DECLINE = 504; // 0x1f8
+    field public static final int CODE_USER_IGNORE = 503; // 0x1f7
+    field public static final int CODE_USER_NOANSWER = 502; // 0x1f6
+    field public static final int CODE_USER_REJECTED_SESSION_MODIFICATION = 511; // 0x1ff
+    field public static final int CODE_USER_TERMINATED = 501; // 0x1f5
+    field public static final int CODE_USER_TERMINATED_BY_REMOTE = 510; // 0x1fe
+    field public static final int CODE_UT_CB_PASSWORD_MISMATCH = 821; // 0x335
+    field public static final int CODE_UT_NETWORK_ERROR = 804; // 0x324
+    field public static final int CODE_UT_NOT_SUPPORTED = 801; // 0x321
+    field public static final int CODE_UT_OPERATION_NOT_ALLOWED = 803; // 0x323
+    field public static final int CODE_UT_SERVICE_UNAVAILABLE = 802; // 0x322
+    field public static final int CODE_UT_SS_MODIFIED_TO_DIAL = 822; // 0x336
+    field public static final int CODE_UT_SS_MODIFIED_TO_DIAL_VIDEO = 825; // 0x339
+    field public static final int CODE_UT_SS_MODIFIED_TO_SS = 824; // 0x338
+    field public static final int CODE_UT_SS_MODIFIED_TO_USSD = 823; // 0x337
+    field public static final int CODE_WIFI_LOST = 1407; // 0x57f
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsReasonInfo> CREATOR;
+    field public static final int EXTRA_CODE_CALL_RETRY_BY_SETTINGS = 3; // 0x3
+    field public static final int EXTRA_CODE_CALL_RETRY_NORMAL = 1; // 0x1
+    field public static final int EXTRA_CODE_CALL_RETRY_SILENT_REDIAL = 2; // 0x2
+  }
+
+}
+
 package android.telephony.mbms {
 
   public class DownloadProgressListener {
@@ -46168,12 +46536,12 @@
 
 package android.text {
 
-  public class AlteredCharSequence implements java.lang.CharSequence android.text.GetChars {
-    method public char charAt(int);
-    method public void getChars(int, int, char[], int);
-    method public int length();
-    method public static android.text.AlteredCharSequence make(CharSequence, char[], int, int);
-    method public CharSequence subSequence(int, int);
+  @Deprecated public class AlteredCharSequence implements java.lang.CharSequence android.text.GetChars {
+    method @Deprecated public char charAt(int);
+    method @Deprecated public void getChars(int, int, char[], int);
+    method @Deprecated public int length();
+    method @Deprecated public static android.text.AlteredCharSequence make(CharSequence, char[], int, int);
+    method @Deprecated public CharSequence subSequence(int, int);
   }
 
   @Deprecated public class AndroidCharacter {
@@ -46485,30 +46853,30 @@
   public static class Layout.Directions {
   }
 
-  public abstract class LoginFilter implements android.text.InputFilter {
-    method public CharSequence filter(CharSequence, int, int, android.text.Spanned, int, int);
-    method public abstract boolean isAllowed(char);
-    method public void onInvalidCharacter(char);
-    method public void onStart();
-    method public void onStop();
+  @Deprecated public abstract class LoginFilter implements android.text.InputFilter {
+    method @Deprecated public CharSequence filter(CharSequence, int, int, android.text.Spanned, int, int);
+    method @Deprecated public abstract boolean isAllowed(char);
+    method @Deprecated public void onInvalidCharacter(char);
+    method @Deprecated public void onStart();
+    method @Deprecated public void onStop();
   }
 
-  public static class LoginFilter.PasswordFilterGMail extends android.text.LoginFilter {
-    ctor public LoginFilter.PasswordFilterGMail();
-    ctor public LoginFilter.PasswordFilterGMail(boolean);
-    method public boolean isAllowed(char);
+  @Deprecated public static class LoginFilter.PasswordFilterGMail extends android.text.LoginFilter {
+    ctor @Deprecated public LoginFilter.PasswordFilterGMail();
+    ctor @Deprecated public LoginFilter.PasswordFilterGMail(boolean);
+    method @Deprecated public boolean isAllowed(char);
   }
 
-  public static class LoginFilter.UsernameFilterGMail extends android.text.LoginFilter {
-    ctor public LoginFilter.UsernameFilterGMail();
-    ctor public LoginFilter.UsernameFilterGMail(boolean);
-    method public boolean isAllowed(char);
+  @Deprecated public static class LoginFilter.UsernameFilterGMail extends android.text.LoginFilter {
+    ctor @Deprecated public LoginFilter.UsernameFilterGMail();
+    ctor @Deprecated public LoginFilter.UsernameFilterGMail(boolean);
+    method @Deprecated public boolean isAllowed(char);
   }
 
-  public static class LoginFilter.UsernameFilterGeneric extends android.text.LoginFilter {
-    ctor public LoginFilter.UsernameFilterGeneric();
-    ctor public LoginFilter.UsernameFilterGeneric(boolean);
-    method public boolean isAllowed(char);
+  @Deprecated public static class LoginFilter.UsernameFilterGeneric extends android.text.LoginFilter {
+    ctor @Deprecated public LoginFilter.UsernameFilterGeneric();
+    ctor @Deprecated public LoginFilter.UsernameFilterGeneric(boolean);
+    method @Deprecated public boolean isAllowed(char);
   }
 
   public interface NoCopySpan {
@@ -52497,6 +52865,9 @@
 package android.view.accessibility {
 
   public final class AccessibilityEvent extends android.view.accessibility.AccessibilityRecord implements android.os.Parcelable {
+    ctor public AccessibilityEvent();
+    ctor public AccessibilityEvent(int);
+    ctor public AccessibilityEvent(@NonNull android.view.accessibility.AccessibilityEvent);
     method public void appendRecord(android.view.accessibility.AccessibilityRecord);
     method public int describeContents();
     method public static String eventTypeToString(int);
@@ -52607,6 +52978,10 @@
   }
 
   public class AccessibilityNodeInfo implements android.os.Parcelable {
+    ctor public AccessibilityNodeInfo();
+    ctor public AccessibilityNodeInfo(@NonNull android.view.View);
+    ctor public AccessibilityNodeInfo(@NonNull android.view.View, int);
+    ctor public AccessibilityNodeInfo(@NonNull android.view.accessibility.AccessibilityNodeInfo);
     method public void addAction(android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction);
     method @Deprecated public void addAction(int);
     method public void addChild(android.view.View);
@@ -52754,6 +53129,7 @@
     field public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
     field public static final String ACTION_ARGUMENT_MOVE_WINDOW_X = "ACTION_ARGUMENT_MOVE_WINDOW_X";
     field public static final String ACTION_ARGUMENT_MOVE_WINDOW_Y = "ACTION_ARGUMENT_MOVE_WINDOW_Y";
+    field public static final String ACTION_ARGUMENT_PRESS_HOLD_DURATION_MILLIS_INT = "android.view.accessibility.action.ARGUMENT_PRESS_HOLD_DURATION_MILLIS_INT";
     field public static final String ACTION_ARGUMENT_PROGRESS_VALUE = "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";
     field public static final String ACTION_ARGUMENT_ROW_INT = "android.view.accessibility.action.ARGUMENT_ROW_INT";
     field public static final String ACTION_ARGUMENT_SELECTION_END_INT = "ACTION_ARGUMENT_SELECTION_END_INT";
@@ -52821,6 +53197,7 @@
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_PAGE_RIGHT;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_PAGE_UP;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_PASTE;
+    field @NonNull public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_PRESS_AND_HOLD;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_PREVIOUS_HTML_ELEMENT;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SCROLL_BACKWARD;
@@ -52840,6 +53217,8 @@
   }
 
   public static final class AccessibilityNodeInfo.CollectionInfo {
+    ctor public AccessibilityNodeInfo.CollectionInfo(int, int, boolean);
+    ctor public AccessibilityNodeInfo.CollectionInfo(int, int, boolean, int);
     method public int getColumnCount();
     method public int getRowCount();
     method public int getSelectionMode();
@@ -52852,6 +53231,8 @@
   }
 
   public static final class AccessibilityNodeInfo.CollectionItemInfo {
+    ctor public AccessibilityNodeInfo.CollectionItemInfo(int, int, int, int, boolean);
+    ctor public AccessibilityNodeInfo.CollectionItemInfo(int, int, int, int, boolean, boolean);
     method public int getColumnIndex();
     method public int getColumnSpan();
     method public int getRowIndex();
@@ -52863,6 +53244,7 @@
   }
 
   public static final class AccessibilityNodeInfo.RangeInfo {
+    ctor public AccessibilityNodeInfo.RangeInfo(int, float, float, float);
     method public float getCurrent();
     method public float getMax();
     method public float getMin();
@@ -52894,6 +53276,8 @@
   }
 
   public class AccessibilityRecord {
+    ctor public AccessibilityRecord();
+    ctor public AccessibilityRecord(@NonNull android.view.accessibility.AccessibilityRecord);
     method public int getAddedCount();
     method public CharSequence getBeforeText();
     method public CharSequence getClassName();
@@ -52954,6 +53338,8 @@
   }
 
   public final class AccessibilityWindowInfo implements android.os.Parcelable {
+    ctor public AccessibilityWindowInfo();
+    ctor public AccessibilityWindowInfo(@NonNull android.view.accessibility.AccessibilityWindowInfo);
     method public int describeContents();
     method public android.view.accessibility.AccessibilityNodeInfo getAnchor();
     method public void getBoundsInScreen(android.graphics.Rect);
@@ -55136,12 +55522,12 @@
   }
 
   public class WebView extends android.widget.AbsoluteLayout implements android.view.ViewGroup.OnHierarchyChangeListener android.view.ViewTreeObserver.OnGlobalFocusChangeListener {
-    ctor public WebView(android.content.Context);
-    ctor public WebView(android.content.Context, android.util.AttributeSet);
-    ctor public WebView(android.content.Context, android.util.AttributeSet, int);
-    ctor public WebView(android.content.Context, android.util.AttributeSet, int, int);
-    ctor @Deprecated public WebView(android.content.Context, android.util.AttributeSet, int, boolean);
-    method public void addJavascriptInterface(Object, String);
+    ctor public WebView(@NonNull android.content.Context);
+    ctor public WebView(@NonNull android.content.Context, @Nullable android.util.AttributeSet);
+    ctor public WebView(@NonNull android.content.Context, @Nullable android.util.AttributeSet, int);
+    ctor public WebView(@NonNull android.content.Context, @Nullable android.util.AttributeSet, int, int);
+    ctor @Deprecated public WebView(@NonNull android.content.Context, @Nullable android.util.AttributeSet, int, boolean);
+    method public void addJavascriptInterface(@NonNull Object, @NonNull String);
     method public boolean canGoBack();
     method public boolean canGoBackOrForward(int);
     method public boolean canGoForward();
@@ -55155,40 +55541,40 @@
     method public void clearMatches();
     method public void clearSslPreferences();
     method @Deprecated public void clearView();
-    method public android.webkit.WebBackForwardList copyBackForwardList();
+    method @NonNull public android.webkit.WebBackForwardList copyBackForwardList();
     method @Deprecated public android.print.PrintDocumentAdapter createPrintDocumentAdapter();
-    method public android.print.PrintDocumentAdapter createPrintDocumentAdapter(String);
-    method public android.webkit.WebMessagePort[] createWebMessageChannel();
+    method @NonNull public android.print.PrintDocumentAdapter createPrintDocumentAdapter(@NonNull String);
+    method @NonNull public android.webkit.WebMessagePort[] createWebMessageChannel();
     method public void destroy();
     method public static void disableWebView();
-    method public void documentHasImages(android.os.Message);
+    method public void documentHasImages(@NonNull android.os.Message);
     method public static void enableSlowWholeDocumentDraw();
-    method public void evaluateJavascript(String, @Nullable android.webkit.ValueCallback<java.lang.String>);
+    method public void evaluateJavascript(@NonNull String, @Nullable android.webkit.ValueCallback<java.lang.String>);
     method @Deprecated @Nullable public static String findAddress(String);
     method @Deprecated public int findAll(String);
-    method public void findAllAsync(String);
+    method public void findAllAsync(@NonNull String);
     method public void findNext(boolean);
     method public void flingScroll(int, int);
     method @Deprecated public void freeMemory();
     method @Nullable public android.net.http.SslCertificate getCertificate();
     method @android.view.ViewDebug.ExportedProperty(category="webview") public int getContentHeight();
     method @Nullable public static android.content.pm.PackageInfo getCurrentWebViewPackage();
-    method public android.graphics.Bitmap getFavicon();
-    method public android.webkit.WebView.HitTestResult getHitTestResult();
+    method @Nullable public android.graphics.Bitmap getFavicon();
+    method @NonNull public android.webkit.WebView.HitTestResult getHitTestResult();
     method @Deprecated @Nullable public String[] getHttpAuthUsernamePassword(String, String);
-    method @android.view.ViewDebug.ExportedProperty(category="webview") public String getOriginalUrl();
+    method @android.view.ViewDebug.ExportedProperty(category="webview") @Nullable public String getOriginalUrl();
     method public int getProgress();
     method public boolean getRendererPriorityWaivedWhenNotVisible();
     method public int getRendererRequestedPriority();
     method @NonNull public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
     method @Deprecated @android.view.ViewDebug.ExportedProperty(category="webview") public float getScale();
-    method public android.webkit.WebSettings getSettings();
+    method @NonNull public android.webkit.WebSettings getSettings();
     method @NonNull public android.view.textclassifier.TextClassifier getTextClassifier();
-    method @android.view.ViewDebug.ExportedProperty(category="webview") public String getTitle();
-    method @android.view.ViewDebug.ExportedProperty(category="webview") public String getUrl();
+    method @android.view.ViewDebug.ExportedProperty(category="webview") @Nullable public String getTitle();
+    method @android.view.ViewDebug.ExportedProperty(category="webview") @Nullable public String getUrl();
     method @Nullable public android.webkit.WebChromeClient getWebChromeClient();
     method @NonNull public static ClassLoader getWebViewClassLoader();
-    method public android.webkit.WebViewClient getWebViewClient();
+    method @NonNull public android.webkit.WebViewClient getWebViewClient();
     method @NonNull public android.os.Looper getWebViewLooper();
     method @Nullable public android.webkit.WebViewRenderProcess getWebViewRenderProcess();
     method @Nullable public android.webkit.WebViewRenderProcessClient getWebViewRenderProcessClient();
@@ -55197,10 +55583,10 @@
     method public void goForward();
     method public void invokeZoomPicker();
     method public boolean isPrivateBrowsingEnabled();
-    method public void loadData(String, @Nullable String, @Nullable String);
-    method public void loadDataWithBaseURL(@Nullable String, String, @Nullable String, @Nullable String, @Nullable String);
-    method public void loadUrl(String, java.util.Map<java.lang.String,java.lang.String>);
-    method public void loadUrl(String);
+    method public void loadData(@NonNull String, @Nullable String, @Nullable String);
+    method public void loadDataWithBaseURL(@Nullable String, @NonNull String, @Nullable String, @Nullable String, @Nullable String);
+    method public void loadUrl(@NonNull String, @NonNull java.util.Map<java.lang.String,java.lang.String>);
+    method public void loadUrl(@NonNull String);
     method @Deprecated public void onChildViewAdded(android.view.View, android.view.View);
     method @Deprecated public void onChildViewRemoved(android.view.View, android.view.View);
     method @Deprecated public void onGlobalFocusChanged(android.view.View, android.view.View);
@@ -55211,23 +55597,23 @@
     method public boolean pageDown(boolean);
     method public boolean pageUp(boolean);
     method public void pauseTimers();
-    method public void postUrl(String, byte[]);
-    method public void postVisualStateCallback(long, android.webkit.WebView.VisualStateCallback);
-    method public void postWebMessage(android.webkit.WebMessage, android.net.Uri);
+    method public void postUrl(@NonNull String, @NonNull byte[]);
+    method public void postVisualStateCallback(long, @NonNull android.webkit.WebView.VisualStateCallback);
+    method public void postWebMessage(@NonNull android.webkit.WebMessage, @NonNull android.net.Uri);
     method public void reload();
     method public void removeJavascriptInterface(@NonNull String);
     method public void requestFocusNodeHref(@Nullable android.os.Message);
-    method public void requestImageRef(android.os.Message);
-    method @Nullable public android.webkit.WebBackForwardList restoreState(android.os.Bundle);
+    method public void requestImageRef(@NonNull android.os.Message);
+    method @Nullable public android.webkit.WebBackForwardList restoreState(@NonNull android.os.Bundle);
     method public void resumeTimers();
     method @Deprecated public void savePassword(String, String, String);
-    method @Nullable public android.webkit.WebBackForwardList saveState(android.os.Bundle);
-    method public void saveWebArchive(String);
-    method public void saveWebArchive(String, boolean, @Nullable android.webkit.ValueCallback<java.lang.String>);
+    method @Nullable public android.webkit.WebBackForwardList saveState(@NonNull android.os.Bundle);
+    method public void saveWebArchive(@NonNull String);
+    method public void saveWebArchive(@NonNull String, boolean, @Nullable android.webkit.ValueCallback<java.lang.String>);
     method @Deprecated public void setCertificate(android.net.http.SslCertificate);
-    method public static void setDataDirectorySuffix(String);
-    method public void setDownloadListener(android.webkit.DownloadListener);
-    method public void setFindListener(android.webkit.WebView.FindListener);
+    method public static void setDataDirectorySuffix(@NonNull String);
+    method public void setDownloadListener(@Nullable android.webkit.DownloadListener);
+    method public void setFindListener(@Nullable android.webkit.WebView.FindListener);
     method @Deprecated public void setHorizontalScrollbarOverlay(boolean);
     method @Deprecated public void setHttpAuthUsernamePassword(String, String, String, String);
     method public void setInitialScale(int);
@@ -55238,9 +55624,9 @@
     method public static void setSafeBrowsingWhitelist(@NonNull java.util.List<java.lang.String>, @Nullable android.webkit.ValueCallback<java.lang.Boolean>);
     method public void setTextClassifier(@Nullable android.view.textclassifier.TextClassifier);
     method @Deprecated public void setVerticalScrollbarOverlay(boolean);
-    method public void setWebChromeClient(android.webkit.WebChromeClient);
+    method public void setWebChromeClient(@Nullable android.webkit.WebChromeClient);
     method public static void setWebContentsDebuggingEnabled(boolean);
-    method public void setWebViewClient(android.webkit.WebViewClient);
+    method public void setWebViewClient(@NonNull android.webkit.WebViewClient);
     method public void setWebViewRenderProcessClient(@NonNull java.util.concurrent.Executor, @NonNull android.webkit.WebViewRenderProcessClient);
     method public void setWebViewRenderProcessClient(@Nullable android.webkit.WebViewRenderProcessClient);
     method @Deprecated public boolean shouldDelayChildPressedState();
@@ -55288,8 +55674,8 @@
 
   public class WebView.WebViewTransport {
     ctor public WebView.WebViewTransport();
-    method public android.webkit.WebView getWebView();
-    method public void setWebView(android.webkit.WebView);
+    method @Nullable public android.webkit.WebView getWebView();
+    method public void setWebView(@Nullable android.webkit.WebView);
   }
 
   public class WebViewClient {
diff --git a/api/removed.txt b/api/removed.txt
index e0e26f7..1a2f434 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -438,7 +438,9 @@
   public final class MediaStore {
     method @Deprecated @NonNull public static android.net.Uri createPending(@NonNull android.content.Context, @NonNull android.provider.MediaStore.PendingParams);
     method @Deprecated @NonNull public static java.util.Set<java.lang.String> getAllVolumeNames(@NonNull android.content.Context);
+    method @Deprecated public static boolean getIncludePending(@NonNull android.net.Uri);
     method @Deprecated @NonNull public static android.provider.MediaStore.PendingSession openPending(@NonNull android.content.Context, @NonNull android.net.Uri);
+    method @Deprecated @NonNull public static android.net.Uri setIncludeTrashed(@NonNull android.net.Uri);
   }
 
   public static interface MediaStore.Audio.AudioColumns extends android.provider.MediaStore.MediaColumns {
diff --git a/api/system-current.txt b/api/system-current.txt
index 936c04e..794ef28 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -58,7 +58,7 @@
     field public static final String CLEAR_APP_USER_DATA = "android.permission.CLEAR_APP_USER_DATA";
     field public static final String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
     field public static final String CONFIGURE_WIFI_DISPLAY = "android.permission.CONFIGURE_WIFI_DISPLAY";
-    field public static final String CONNECTIVITY_INTERNAL = "android.permission.CONNECTIVITY_INTERNAL";
+    field @Deprecated public static final String CONNECTIVITY_INTERNAL = "android.permission.CONNECTIVITY_INTERNAL";
     field public static final String CONNECTIVITY_USE_RESTRICTED_NETWORKS = "android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS";
     field public static final String CONTROL_DISPLAY_COLOR_TRANSFORMS = "android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS";
     field public static final String CONTROL_DISPLAY_SATURATION = "android.permission.CONTROL_DISPLAY_SATURATION";
@@ -126,6 +126,7 @@
     field public static final String MODIFY_QUIET_MODE = "android.permission.MODIFY_QUIET_MODE";
     field public static final String MOVE_PACKAGE = "android.permission.MOVE_PACKAGE";
     field public static final String NETWORK_CARRIER_PROVISIONING = "android.permission.NETWORK_CARRIER_PROVISIONING";
+    field public static final String NETWORK_FACTORY = "android.permission.NETWORK_FACTORY";
     field public static final String NETWORK_MANAGED_PROVISIONING = "android.permission.NETWORK_MANAGED_PROVISIONING";
     field public static final String NETWORK_SCAN = "android.permission.NETWORK_SCAN";
     field public static final String NETWORK_SETTINGS = "android.permission.NETWORK_SETTINGS";
@@ -135,6 +136,7 @@
     field public static final String NOTIFICATION_DURING_SETUP = "android.permission.NOTIFICATION_DURING_SETUP";
     field public static final String NOTIFY_TV_INPUTS = "android.permission.NOTIFY_TV_INPUTS";
     field public static final String OBSERVE_APP_USAGE = "android.permission.OBSERVE_APP_USAGE";
+    field public static final String OBSERVE_NETWORK_POLICY = "android.permission.OBSERVE_NETWORK_POLICY";
     field public static final String OBSERVE_ROLE_HOLDERS = "android.permission.OBSERVE_ROLE_HOLDERS";
     field public static final String OPEN_ACCESSIBILITY_DETAILS_SETTINGS = "android.permission.OPEN_ACCESSIBILITY_DETAILS_SETTINGS";
     field public static final String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG";
@@ -213,6 +215,8 @@
     field public static final String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
     field public static final String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK";
     field public static final String WHITELIST_RESTRICTED_PERMISSIONS = "android.permission.WHITELIST_RESTRICTED_PERMISSIONS";
+    field public static final String WIFI_SET_DEVICE_MOBILITY_STATE = "android.permission.WIFI_SET_DEVICE_MOBILITY_STATE";
+    field public static final String WIFI_UPDATE_USABILITY_STATS_SCORE = "android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE";
     field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
     field public static final String WRITE_DREAM_STATE = "android.permission.WRITE_DREAM_STATE";
     field public static final String WRITE_EMBEDDED_SUBSCRIPTIONS = "android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS";
@@ -652,6 +656,29 @@
     method public boolean isStatusBarExpansionDisabled();
   }
 
+  public final class SystemServiceRegistry {
+    method public static <TServiceClass> void registerContextAwareService(@NonNull String, @NonNull Class<TServiceClass>, @NonNull android.app.SystemServiceRegistry.ContextAwareServiceProducerWithBinder<TServiceClass>);
+    method public static <TServiceClass> void registerContextAwareService(@NonNull String, @NonNull Class<TServiceClass>, @NonNull android.app.SystemServiceRegistry.ContextAwareServiceProducerWithoutBinder<TServiceClass>);
+    method public static <TServiceClass> void registerStaticService(@NonNull String, @NonNull Class<TServiceClass>, @NonNull android.app.SystemServiceRegistry.StaticServiceProducerWithBinder<TServiceClass>);
+    method public static <TServiceClass> void registerStaticService(@NonNull String, @NonNull Class<TServiceClass>, @NonNull android.app.SystemServiceRegistry.StaticServiceProducerWithoutBinder<TServiceClass>);
+  }
+
+  public static interface SystemServiceRegistry.ContextAwareServiceProducerWithBinder<TServiceClass> {
+    method @NonNull public TServiceClass createService(@NonNull android.content.Context, @NonNull android.os.IBinder);
+  }
+
+  public static interface SystemServiceRegistry.ContextAwareServiceProducerWithoutBinder<TServiceClass> {
+    method @NonNull public TServiceClass createService(@NonNull android.content.Context);
+  }
+
+  public static interface SystemServiceRegistry.StaticServiceProducerWithBinder<TServiceClass> {
+    method @NonNull public TServiceClass createService(@NonNull android.os.IBinder);
+  }
+
+  public static interface SystemServiceRegistry.StaticServiceProducerWithoutBinder<TServiceClass> {
+    method @NonNull public TServiceClass createService();
+  }
+
   public class UiModeManager {
     method @RequiresPermission(android.Manifest.permission.ENTER_CAR_MODE_PRIORITIZED) public void enableCarMode(@IntRange(from=0) int, int);
     field public static final String ACTION_ENTER_CAR_MODE_PRIORITIZED = "android.app.action.ENTER_CAR_MODE_PRIORITIZED";
@@ -805,6 +832,7 @@
     method @RequiresPermission(android.Manifest.permission.BACKUP) public void backupNow();
     method @RequiresPermission(android.Manifest.permission.BACKUP) public android.app.backup.RestoreSession beginRestoreSession();
     method @RequiresPermission(android.Manifest.permission.BACKUP) public void cancelBackups();
+    method @RequiresPermission(android.Manifest.permission.BACKUP) public void excludeKeysFromRestore(@NonNull String, @NonNull java.util.List<java.lang.String>);
     method @RequiresPermission(android.Manifest.permission.BACKUP) public long getAvailableRestoreToken(String);
     method @RequiresPermission(android.Manifest.permission.BACKUP) public android.content.Intent getConfigurationIntent(String);
     method @RequiresPermission(android.Manifest.permission.BACKUP) public String getCurrentTransport();
@@ -1091,6 +1119,10 @@
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public abstract int scheduleAsPackage(@NonNull android.app.job.JobInfo, @NonNull String, int, String);
   }
 
+  public class JobSchedulerFrameworkInitializer {
+    method public static void registerServiceWrappers();
+  }
+
 }
 
 package android.app.prediction {
@@ -1166,6 +1198,7 @@
     field public static final int ACTION_DISMISS = 2; // 0x2
     field public static final int ACTION_LAUNCH = 1; // 0x1
     field public static final int ACTION_PIN = 3; // 0x3
+    field public static final int ACTION_UNPIN = 4; // 0x4
     field @NonNull public static final android.os.Parcelable.Creator<android.app.prediction.AppTargetEvent> CREATOR;
   }
 
@@ -1297,6 +1330,25 @@
 
 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 @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 @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 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);
+    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
+    field public static final int OPTIONAL_CODECS_PREF_UNKNOWN = -1; // 0xffffffff
+    field public static final int OPTIONAL_CODECS_SUPPORTED = 1; // 0x1
+    field public static final int OPTIONAL_CODECS_SUPPORT_UNKNOWN = -1; // 0xffffffff
+  }
+
   public final class BluetoothAdapter {
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean addOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean connectAllEnabledProfiles(@NonNull android.bluetooth.BluetoothDevice);
@@ -1309,16 +1361,66 @@
     method public boolean isBleScanAlwaysAvailable();
     method public boolean isLeEnabled();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean removeOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setActiveDevice(@Nullable android.bluetooth.BluetoothDevice, int);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean setScanMode(int, int);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean setScanMode(int);
     field public static final String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
     field public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE = "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
+    field public static final int ACTIVE_DEVICE_ALL = 2; // 0x2
+    field public static final int ACTIVE_DEVICE_AUDIO = 0; // 0x0
+    field public static final int ACTIVE_DEVICE_PHONE_CALL = 1; // 0x1
   }
 
   public static interface BluetoothAdapter.OnMetadataChangedListener {
     method public void onMetadataChanged(@NonNull android.bluetooth.BluetoothDevice, int, @Nullable byte[]);
   }
 
+  public final class BluetoothCodecConfig implements android.os.Parcelable {
+    ctor public BluetoothCodecConfig(int, int, int, int, int, long, long, long, long);
+    ctor public BluetoothCodecConfig(int);
+    method public int getBitsPerSample();
+    method @NonNull public String getCodecName();
+    method public int getCodecPriority();
+    method public long getCodecSpecific1();
+    method public int getCodecType();
+    method public int getSampleRate();
+    method public boolean isMandatoryCodec();
+    field public static final int BITS_PER_SAMPLE_16 = 1; // 0x1
+    field public static final int BITS_PER_SAMPLE_24 = 2; // 0x2
+    field public static final int BITS_PER_SAMPLE_32 = 4; // 0x4
+    field public static final int BITS_PER_SAMPLE_NONE = 0; // 0x0
+    field public static final int CHANNEL_MODE_MONO = 1; // 0x1
+    field public static final int CHANNEL_MODE_NONE = 0; // 0x0
+    field public static final int CHANNEL_MODE_STEREO = 2; // 0x2
+    field public static final int CODEC_PRIORITY_DEFAULT = 0; // 0x0
+    field public static final int CODEC_PRIORITY_DISABLED = -1; // 0xffffffff
+    field public static final int CODEC_PRIORITY_HIGHEST = 1000000; // 0xf4240
+    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothCodecConfig> CREATOR;
+    field public static final int SAMPLE_RATE_176400 = 16; // 0x10
+    field public static final int SAMPLE_RATE_192000 = 32; // 0x20
+    field public static final int SAMPLE_RATE_44100 = 1; // 0x1
+    field public static final int SAMPLE_RATE_48000 = 2; // 0x2
+    field public static final int SAMPLE_RATE_88200 = 4; // 0x4
+    field public static final int SAMPLE_RATE_96000 = 8; // 0x8
+    field public static final int SAMPLE_RATE_NONE = 0; // 0x0
+    field public static final int SOURCE_CODEC_TYPE_AAC = 1; // 0x1
+    field public static final int SOURCE_CODEC_TYPE_APTX = 2; // 0x2
+    field public static final int SOURCE_CODEC_TYPE_APTX_HD = 3; // 0x3
+    field public static final int SOURCE_CODEC_TYPE_INVALID = 1000000; // 0xf4240
+    field public static final int SOURCE_CODEC_TYPE_LDAC = 4; // 0x4
+    field public static final int SOURCE_CODEC_TYPE_MAX = 5; // 0x5
+    field public static final int SOURCE_CODEC_TYPE_SBC = 0; // 0x0
+  }
+
+  public final class BluetoothCodecStatus implements android.os.Parcelable {
+    ctor public BluetoothCodecStatus(@Nullable android.bluetooth.BluetoothCodecConfig, @Nullable android.bluetooth.BluetoothCodecConfig[], @Nullable android.bluetooth.BluetoothCodecConfig[]);
+    method @Nullable public android.bluetooth.BluetoothCodecConfig getCodecConfig();
+    method @Nullable public android.bluetooth.BluetoothCodecConfig[] getCodecsLocalCapabilities();
+    method @Nullable public android.bluetooth.BluetoothCodecConfig[] getCodecsSelectableCapabilities();
+    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothCodecStatus> CREATOR;
+    field public static final String EXTRA_CODEC_STATUS = "android.bluetooth.extra.CODEC_STATUS";
+  }
+
   public final class BluetoothDevice implements android.os.Parcelable {
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelBondProcess();
     method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public byte[] getMetadata(int);
@@ -1357,7 +1459,15 @@
   public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean connect(android.bluetooth.BluetoothDevice);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean disconnect(android.bluetooth.BluetoothDevice);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setPriority(android.bluetooth.BluetoothDevice, int);
+    method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothDevice getActiveDevice();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setPriority(android.bluetooth.BluetoothDevice, int);
+  }
+
+  public final class BluetoothHearingAid implements android.bluetooth.BluetoothProfile {
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
   }
 
   public final class BluetoothPan implements android.bluetooth.BluetoothProfile {
@@ -1376,9 +1486,43 @@
   }
 
   public interface BluetoothProfile {
+    field public static final int CONNECTION_POLICY_ALLOWED = 100; // 0x64
+    field public static final int CONNECTION_POLICY_FORBIDDEN = 0; // 0x0
+    field public static final int CONNECTION_POLICY_UNKNOWN = -1; // 0xffffffff
     field public static final int PAN = 5; // 0x5
-    field public static final int PRIORITY_OFF = 0; // 0x0
-    field public static final int PRIORITY_ON = 100; // 0x64
+    field @Deprecated public static final int PRIORITY_OFF = 0; // 0x0
+    field @Deprecated public static final int PRIORITY_ON = 100; // 0x64
+  }
+
+  public final class BluetoothUuid {
+    method public static boolean containsAnyUuid(@Nullable android.os.ParcelUuid[], @Nullable android.os.ParcelUuid[]);
+    method @NonNull public static android.os.ParcelUuid parseUuidFrom(@Nullable byte[]);
+    field @NonNull public static final android.os.ParcelUuid A2DP_SINK;
+    field @NonNull public static final android.os.ParcelUuid A2DP_SOURCE;
+    field @NonNull public static final android.os.ParcelUuid ADV_AUDIO_DIST;
+    field @NonNull public static final android.os.ParcelUuid AVRCP_CONTROLLER;
+    field @NonNull public static final android.os.ParcelUuid AVRCP_TARGET;
+    field @NonNull public static final android.os.ParcelUuid BASE_UUID;
+    field @NonNull public static final android.os.ParcelUuid BNEP;
+    field @NonNull public static final android.os.ParcelUuid HEARING_AID;
+    field @NonNull public static final android.os.ParcelUuid HFP;
+    field @NonNull public static final android.os.ParcelUuid HFP_AG;
+    field @NonNull public static final android.os.ParcelUuid HID;
+    field @NonNull public static final android.os.ParcelUuid HOGP;
+    field @NonNull public static final android.os.ParcelUuid HSP;
+    field @NonNull public static final android.os.ParcelUuid HSP_AG;
+    field @NonNull public static final android.os.ParcelUuid MAP;
+    field @NonNull public static final android.os.ParcelUuid MAS;
+    field @NonNull public static final android.os.ParcelUuid MNS;
+    field @NonNull public static final android.os.ParcelUuid NAP;
+    field @NonNull public static final android.os.ParcelUuid OBEX_OBJECT_PUSH;
+    field @NonNull public static final android.os.ParcelUuid PANU;
+    field @NonNull public static final android.os.ParcelUuid PBAP_PCE;
+    field @NonNull public static final android.os.ParcelUuid PBAP_PSE;
+    field @NonNull public static final android.os.ParcelUuid SAP;
+    field public static final int UUID_BYTES_128_BIT = 16; // 0x10
+    field public static final int UUID_BYTES_16_BIT = 2; // 0x2
+    field public static final int UUID_BYTES_32_BIT = 4; // 0x4
   }
 
 }
@@ -1586,7 +1730,7 @@
   }
 
   public abstract class AtomicFormula implements android.content.integrity.Formula {
-    ctor public AtomicFormula(@android.content.integrity.AtomicFormula.Key int);
+    ctor public AtomicFormula(int);
     method public int getKey();
     field public static final int APP_CERTIFICATE = 1; // 0x1
     field public static final int EQ = 0; // 0x0
@@ -1602,7 +1746,7 @@
   }
 
   public static final class AtomicFormula.BooleanAtomicFormula extends android.content.integrity.AtomicFormula implements android.os.Parcelable {
-    ctor public AtomicFormula.BooleanAtomicFormula(@android.content.integrity.AtomicFormula.Key int, boolean);
+    ctor public AtomicFormula.BooleanAtomicFormula(int, boolean);
     method public int describeContents();
     method public int getTag();
     method public boolean getValue();
@@ -1612,7 +1756,7 @@
   }
 
   public static final class AtomicFormula.IntAtomicFormula extends android.content.integrity.AtomicFormula implements android.os.Parcelable {
-    ctor public AtomicFormula.IntAtomicFormula(@android.content.integrity.AtomicFormula.Key int, @android.content.integrity.AtomicFormula.Operator int, int);
+    ctor public AtomicFormula.IntAtomicFormula(int, int, int);
     method public int describeContents();
     method public int getOperator();
     method public int getTag();
@@ -1622,14 +1766,8 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.content.integrity.AtomicFormula.IntAtomicFormula> CREATOR;
   }
 
-  @IntDef({android.content.integrity.AtomicFormula.PACKAGE_NAME, android.content.integrity.AtomicFormula.APP_CERTIFICATE, android.content.integrity.AtomicFormula.INSTALLER_NAME, android.content.integrity.AtomicFormula.INSTALLER_CERTIFICATE, android.content.integrity.AtomicFormula.VERSION_CODE, android.content.integrity.AtomicFormula.PRE_INSTALLED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface AtomicFormula.Key {
-  }
-
-  @IntDef({android.content.integrity.AtomicFormula.EQ, android.content.integrity.AtomicFormula.LT, android.content.integrity.AtomicFormula.LE, android.content.integrity.AtomicFormula.GT, android.content.integrity.AtomicFormula.GE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface AtomicFormula.Operator {
-  }
-
   public static final class AtomicFormula.StringAtomicFormula extends android.content.integrity.AtomicFormula implements android.os.Parcelable {
-    ctor public AtomicFormula.StringAtomicFormula(@android.content.integrity.AtomicFormula.Key int, @NonNull String, boolean);
+    ctor public AtomicFormula.StringAtomicFormula(int, @NonNull String, boolean);
     method public int describeContents();
     method public boolean getIsHashedValue();
     method public int getTag();
@@ -1640,9 +1778,9 @@
   }
 
   public final class CompoundFormula implements android.content.integrity.Formula android.os.Parcelable {
-    ctor public CompoundFormula(@android.content.integrity.CompoundFormula.Connector int, @NonNull java.util.List<android.content.integrity.Formula>);
+    ctor public CompoundFormula(int, @NonNull java.util.List<android.content.integrity.Formula>);
     method public int describeContents();
-    method @android.content.integrity.CompoundFormula.Connector public int getConnector();
+    method public int getConnector();
     method @NonNull public java.util.List<android.content.integrity.Formula> getFormulas();
     method public int getTag();
     method public boolean isSatisfied(@NonNull android.content.integrity.AppInstallMetadata);
@@ -1653,11 +1791,8 @@
     field public static final int OR = 1; // 0x1
   }
 
-  @IntDef({android.content.integrity.CompoundFormula.AND, android.content.integrity.CompoundFormula.OR, android.content.integrity.CompoundFormula.NOT}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface CompoundFormula.Connector {
-  }
-
   public interface Formula {
-    method @android.content.integrity.Formula.Tag public int getTag();
+    method public int getTag();
     method public boolean isSatisfied(@NonNull android.content.integrity.AppInstallMetadata);
     method @NonNull public static android.content.integrity.Formula readFromParcel(@NonNull android.os.Parcel);
     method public static void writeToParcel(@NonNull android.content.integrity.Formula, @NonNull android.os.Parcel, int);
@@ -1667,13 +1802,10 @@
     field public static final int STRING_ATOMIC_FORMULA_TAG = 1; // 0x1
   }
 
-  @IntDef({android.content.integrity.Formula.COMPOUND_FORMULA_TAG, android.content.integrity.Formula.STRING_ATOMIC_FORMULA_TAG, android.content.integrity.Formula.INT_ATOMIC_FORMULA_TAG, android.content.integrity.Formula.BOOLEAN_ATOMIC_FORMULA_TAG}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface Formula.Tag {
-  }
-
   public final class Rule implements android.os.Parcelable {
-    ctor public Rule(@NonNull android.content.integrity.Formula, @android.content.integrity.Rule.Effect int);
+    ctor public Rule(@NonNull android.content.integrity.Formula, int);
     method public int describeContents();
-    method @android.content.integrity.Rule.Effect public int getEffect();
+    method public int getEffect();
     method @NonNull public android.content.integrity.Formula getFormula();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.content.integrity.Rule> CREATOR;
@@ -1681,9 +1813,6 @@
     field public static final int FORCE_ALLOW = 1; // 0x1
   }
 
-  @IntDef({android.content.integrity.Rule.DENY, android.content.integrity.Rule.FORCE_ALLOW}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface Rule.Effect {
-  }
-
   public class RuleSet {
     method @NonNull public java.util.List<android.content.integrity.Rule> getRules();
     method @NonNull public String getVersion();
@@ -3784,16 +3913,19 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioVolumeGroup> getAudioVolumeGroups();
     method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
     method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
+    method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioDeviceAddress getPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
     method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
     method public boolean isAudioServerRunning();
     method public boolean isHdmiSystemAudioSupported();
     method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
     method public void registerVolumeGroupCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.VolumeGroupCallback);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean removePreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException;
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy) throws java.lang.IllegalArgumentException;
     method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int requestAudioFocus(@NonNull android.media.AudioFocusRequest, @Nullable android.media.audiopolicy.AudioPolicy);
     method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback);
     method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAddress);
     method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setVolumeIndexForAttributes(@NonNull android.media.AudioAttributes, int, int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
     method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicyAsync(@NonNull android.media.audiopolicy.AudioPolicy);
@@ -3964,9 +4096,11 @@
   }
 
   public final class AudioProductStrategy implements android.os.Parcelable {
+    method @NonNull public static android.media.audiopolicy.AudioProductStrategy createInvalidAudioProductStrategy(int);
     method public int describeContents();
     method @NonNull public android.media.AudioAttributes getAudioAttributes();
     method public int getId();
+    method public boolean supportsAudioAttributes(@NonNull android.media.AudioAttributes);
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.media.audiopolicy.AudioProductStrategy> CREATOR;
   }
@@ -4312,7 +4446,7 @@
   public class ConnectivityManager {
     method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull android.os.ParcelFileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
     method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull java.net.Socket, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
-    method @RequiresPermission(android.Manifest.permission.LOCAL_MAC_ADDRESS) public String getCaptivePortalServerUrl();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCaptivePortalServerUrl();
     method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
     method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
     method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
@@ -4351,6 +4485,7 @@
   public final class IpConfiguration implements android.os.Parcelable {
     ctor public IpConfiguration();
     ctor public IpConfiguration(@NonNull android.net.IpConfiguration);
+    method public int describeContents();
     method @Nullable public android.net.ProxyInfo getHttpProxy();
     method @NonNull public android.net.IpConfiguration.IpAssignment getIpAssignment();
     method @NonNull public android.net.IpConfiguration.ProxySettings getProxySettings();
@@ -4359,6 +4494,7 @@
     method public void setIpAssignment(@NonNull android.net.IpConfiguration.IpAssignment);
     method public void setProxySettings(@NonNull android.net.IpConfiguration.ProxySettings);
     method public void setStaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.IpConfiguration> CREATOR;
   }
 
@@ -4411,7 +4547,6 @@
     ctor public LinkProperties(@Nullable android.net.LinkProperties);
     method public boolean addDnsServer(@NonNull java.net.InetAddress);
     method public boolean addLinkAddress(@NonNull android.net.LinkAddress);
-    method @Nullable public android.net.IpPrefix getNat64Prefix();
     method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
     method @Nullable public String getTcpBufferSizes();
     method @NonNull public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
@@ -4425,7 +4560,6 @@
     method public boolean removeDnsServer(@NonNull java.net.InetAddress);
     method public boolean removeLinkAddress(@NonNull android.net.LinkAddress);
     method public boolean removeRoute(@NonNull android.net.RouteInfo);
-    method public void setNat64Prefix(@Nullable android.net.IpPrefix);
     method public void setPcscfServers(@NonNull java.util.Collection<java.net.InetAddress>);
     method public void setPrivateDnsServerName(@Nullable String);
     method public void setTcpBufferSizes(@Nullable String);
@@ -4436,6 +4570,7 @@
   public class Network implements android.os.Parcelable {
     ctor public Network(@NonNull android.net.Network);
     method @NonNull public android.net.Network getPrivateDnsBypassingCopy();
+    field public final int netId;
   }
 
   public final class NetworkCapabilities implements android.os.Parcelable {
@@ -4680,7 +4815,7 @@
     method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getOutboundTrafficSelectors();
   }
 
-  public abstract class ChildSessionOptions {
+  public abstract class ChildSessionParams {
   }
 
   public class IkeFqdnIdentification extends android.net.ipsec.ike.IkeIdentification {
@@ -4725,11 +4860,11 @@
   }
 
   public final class IkeSession implements java.lang.AutoCloseable {
-    ctor public IkeSession(@NonNull android.content.Context, @NonNull android.net.ipsec.ike.IkeSessionOptions, @NonNull android.net.ipsec.ike.ChildSessionOptions, @NonNull java.util.concurrent.Executor, @NonNull android.net.ipsec.ike.IkeSessionCallback, @NonNull android.net.ipsec.ike.ChildSessionCallback);
+    ctor public IkeSession(@NonNull android.content.Context, @NonNull android.net.ipsec.ike.IkeSessionParams, @NonNull android.net.ipsec.ike.ChildSessionParams, @NonNull java.util.concurrent.Executor, @NonNull android.net.ipsec.ike.IkeSessionCallback, @NonNull android.net.ipsec.ike.ChildSessionCallback);
     method public void close();
     method public void closeChildSession(@NonNull android.net.ipsec.ike.ChildSessionCallback);
     method public void kill();
-    method public void openChildSession(@NonNull android.net.ipsec.ike.ChildSessionOptions, @NonNull android.net.ipsec.ike.ChildSessionCallback);
+    method public void openChildSession(@NonNull android.net.ipsec.ike.ChildSessionParams, @NonNull android.net.ipsec.ike.ChildSessionCallback);
   }
 
   public interface IkeSessionCallback {
@@ -4747,21 +4882,21 @@
     field public static final int EXTENSION_TYPE_MOBIKE = 2; // 0x2
   }
 
-  public final class IkeSessionOptions {
+  public final class IkeSessionParams {
   }
 
-  public static final class IkeSessionOptions.Builder {
-    ctor public IkeSessionOptions.Builder();
-    method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder addSaProposal(@NonNull android.net.ipsec.ike.IkeSaProposal);
-    method @NonNull public android.net.ipsec.ike.IkeSessionOptions build();
-    method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setAuthDigitalSignature(@NonNull java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.security.PrivateKey);
-    method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setAuthDigitalSignature(@NonNull java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.util.List<java.security.cert.X509Certificate>, @NonNull java.security.PrivateKey);
-    method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setAuthEap(@NonNull java.security.cert.X509Certificate, @NonNull android.net.eap.EapSessionConfig);
-    method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setAuthPsk(@NonNull byte[]);
-    method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setLocalIdentification(@NonNull android.net.ipsec.ike.IkeIdentification);
-    method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setRemoteIdentification(@NonNull android.net.ipsec.ike.IkeIdentification);
-    method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setServerAddress(@NonNull java.net.InetAddress);
-    method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setUdpEncapsulationSocket(@NonNull android.net.IpSecManager.UdpEncapsulationSocket);
+  public static final class IkeSessionParams.Builder {
+    ctor public IkeSessionParams.Builder();
+    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.IkeSaProposal);
+    method @NonNull public android.net.ipsec.ike.IkeSessionParams build();
+    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthDigitalSignature(@NonNull java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.security.PrivateKey);
+    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthDigitalSignature(@NonNull java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.util.List<java.security.cert.X509Certificate>, @NonNull java.security.PrivateKey);
+    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthEap(@NonNull java.security.cert.X509Certificate, @NonNull android.net.eap.EapSessionConfig);
+    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthPsk(@NonNull byte[]);
+    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setLocalIdentification(@NonNull android.net.ipsec.ike.IkeIdentification);
+    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setRemoteIdentification(@NonNull android.net.ipsec.ike.IkeIdentification);
+    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setServerAddress(@NonNull java.net.InetAddress);
+    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setUdpEncapsulationSocket(@NonNull android.net.IpSecManager.UdpEncapsulationSocket);
   }
 
   public final class IkeTrafficSelector {
@@ -4798,33 +4933,33 @@
     field public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = 2; // 0x2
   }
 
-  public final class TransportModeChildSessionOptions extends android.net.ipsec.ike.ChildSessionOptions {
+  public final class TransportModeChildSessionParams extends android.net.ipsec.ike.ChildSessionParams {
   }
 
-  public static final class TransportModeChildSessionOptions.Builder {
-    ctor public TransportModeChildSessionOptions.Builder();
-    method @NonNull public android.net.ipsec.ike.TransportModeChildSessionOptions.Builder addInboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
-    method @NonNull public android.net.ipsec.ike.TransportModeChildSessionOptions.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
-    method @NonNull public android.net.ipsec.ike.TransportModeChildSessionOptions.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal);
-    method @NonNull public android.net.ipsec.ike.TransportModeChildSessionOptions build();
+  public static final class TransportModeChildSessionParams.Builder {
+    ctor public TransportModeChildSessionParams.Builder();
+    method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addInboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
+    method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
+    method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal);
+    method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams build();
   }
 
-  public final class TunnelModeChildSessionOptions extends android.net.ipsec.ike.ChildSessionOptions {
+  public final class TunnelModeChildSessionParams extends android.net.ipsec.ike.ChildSessionParams {
   }
 
-  public static final class TunnelModeChildSessionOptions.Builder {
-    ctor public TunnelModeChildSessionOptions.Builder();
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalAddressRequest(int);
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalAddressRequest(@NonNull java.net.InetAddress, int);
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalDhcpServerRequest(int);
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalDhcpServerRequest(@NonNull java.net.InetAddress);
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalDnsServerRequest(int);
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalDnsServerRequest(@NonNull java.net.InetAddress);
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalSubnetRequest(int);
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal);
-    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions build();
+  public static final class TunnelModeChildSessionParams.Builder {
+    ctor public TunnelModeChildSessionParams.Builder();
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalAddressRequest(int);
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalAddressRequest(@NonNull java.net.InetAddress, int);
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalDhcpServerRequest(int);
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalDhcpServerRequest(@NonNull java.net.InetAddress);
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalDnsServerRequest(int);
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalDnsServerRequest(@NonNull java.net.InetAddress);
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addInternalSubnetRequest(int);
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal);
+    method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams build();
   }
 
 }
@@ -5246,18 +5381,30 @@
 
   public final class SoftApConfiguration implements android.os.Parcelable {
     method public int describeContents();
+    method public int getBand();
     method @Nullable public android.net.MacAddress getBssid();
+    method public int getChannel();
+    method public int getSecurityType();
     method @Nullable public String getSsid();
     method @Nullable public String getWpa2Passphrase();
+    method public boolean isHiddenSsid();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int BAND_2GHZ = 0; // 0x0
+    field public static final int BAND_5GHZ = 1; // 0x1
+    field public static final int BAND_ANY = -1; // 0xffffffff
     field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.SoftApConfiguration> CREATOR;
+    field public static final int SECURITY_TYPE_OPEN = 0; // 0x0
+    field public static final int SECURITY_TYPE_WPA2_PSK = 1; // 0x1
   }
 
   public static final class SoftApConfiguration.Builder {
     ctor public SoftApConfiguration.Builder();
     ctor public SoftApConfiguration.Builder(@NonNull android.net.wifi.SoftApConfiguration);
     method @NonNull public android.net.wifi.SoftApConfiguration build();
+    method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBand(int);
     method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBssid(@Nullable android.net.MacAddress);
+    method @NonNull public android.net.wifi.SoftApConfiguration.Builder setChannel(int);
+    method @NonNull public android.net.wifi.SoftApConfiguration.Builder setHiddenSsid(boolean);
     method @NonNull public android.net.wifi.SoftApConfiguration.Builder setSsid(@Nullable String);
     method @NonNull public android.net.wifi.SoftApConfiguration.Builder setWpa2Passphrase(@Nullable String);
   }
@@ -5395,7 +5542,7 @@
   }
 
   public class WifiManager {
-    method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void addOnWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
+    method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void addOnWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void allowAutojoin(int, boolean);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(int, @Nullable android.net.wifi.WifiManager.ActionListener);
@@ -5411,8 +5558,10 @@
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,java.util.List<android.net.wifi.ScanResult>> getMatchingOsuProviders(@Nullable java.util.List<android.net.wifi.ScanResult>);
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,android.net.wifi.hotspot2.PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(@NonNull java.util.Set<android.net.wifi.hotspot2.OsuProvider>);
     method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
+    method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.SoftApConfiguration getSoftApConfiguration();
     method public int getVerboseLoggingLevel();
-    method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.WifiConfiguration getWifiApConfiguration();
+    method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void getWifiActivityEnergyInfoAsync(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiActivityEnergyInfoListener);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.WifiConfiguration getWifiApConfiguration();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public int getWifiApState();
     method public boolean isApMacRandomizationSupported();
     method public boolean isConnectedMacRandomizationSupported();
@@ -5428,27 +5577,31 @@
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerSoftApCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SoftApCallback);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerTrafficStateCallback(@NonNull android.net.wifi.WifiManager.TrafficStateCallback);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerTrafficStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.TrafficStateCallback);
-    method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void removeOnWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
+    method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void removeOnWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreBackupData(@NonNull byte[]);
+    method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreSoftApBackupData(@NonNull byte[]);
     method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreSupplicantBackupData(@NonNull byte[], @NonNull byte[]);
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveBackupData();
+    method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveSoftApBackupData();
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
-    method @RequiresPermission("android.permission.WIFI_SET_DEVICE_MOBILITY_STATE") public void setDeviceMobilityState(int);
-    method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
+    method @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE) public void setDeviceMobilityState(int);
+    method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public boolean setSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsConfiguratorInitiator(@NonNull String, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsEnrolleeInitiator(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startLocalOnlyHotspot(@NonNull android.net.wifi.SoftApConfiguration, @Nullable java.util.concurrent.Executor, @Nullable android.net.wifi.WifiManager.LocalOnlyHotspotCallback);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public boolean startScan(android.os.WorkSource);
-    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean startSoftAp(@Nullable android.net.wifi.WifiConfiguration);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startSubscriptionProvisioning(@NonNull android.net.wifi.hotspot2.OsuProvider, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.hotspot2.ProvisioningCallback);
+    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean startTetheredHotspot(@Nullable android.net.wifi.SoftApConfiguration);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void stopEasyConnectSession();
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean stopSoftAp();
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterNetworkRequestMatchCallback(@NonNull android.net.wifi.WifiManager.NetworkRequestMatchCallback);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterSoftApCallback(@NonNull android.net.wifi.WifiManager.SoftApCallback);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterTrafficStateCallback(@NonNull android.net.wifi.WifiManager.TrafficStateCallback);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void updateInterfaceIpState(@Nullable String, int);
-    method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void updateWifiUsabilityScore(int, int, int);
+    method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void updateWifiUsabilityScore(int, int, int);
     field public static final String ACTION_LINK_CONFIGURATION_CHANGED = "android.net.wifi.LINK_CONFIGURATION_CHANGED";
+    field @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING) public static final String ACTION_NETWORK_SETTINGS_RESET = "android.net.wifi.action.NETWORK_SETTINGS_RESET";
     field public static final String ACTION_PASSPOINT_LAUNCH_OSU_VIEW = "android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW";
     field public static final String ACTION_REQUEST_DISABLE = "android.net.wifi.action.REQUEST_DISABLE";
     field public static final String ACTION_REQUEST_ENABLE = "android.net.wifi.action.REQUEST_ENABLE";
@@ -5511,6 +5664,10 @@
     method public default void select(@NonNull android.net.wifi.WifiConfiguration);
   }
 
+  public static interface WifiManager.OnWifiActivityEnergyInfoListener {
+    method public void onWifiActivityEnergyInfo(@Nullable android.os.connectivity.WifiActivityEnergyInfo);
+  }
+
   public static interface WifiManager.OnWifiUsabilityStatsListener {
     method public void onWifiUsabilityStats(int, boolean, @NonNull android.net.wifi.WifiUsabilityStatsEntry);
   }
@@ -5550,6 +5707,7 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public java.util.List<java.lang.Integer> getAvailableChannels(int);
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean getScanResults();
     method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public java.util.List<android.net.wifi.ScanResult> getSingleScanResults();
+    method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void registerScanListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiScanner.ScanListener);
     method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setScanningEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener, android.os.WorkSource);
@@ -5561,6 +5719,7 @@
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void stopScan(android.net.wifi.WifiScanner.ScanListener);
     method @Deprecated public void stopTrackingBssids(android.net.wifi.WifiScanner.BssidListener);
     method @Deprecated public void stopTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
+    method public void unregisterScanListener(@NonNull android.net.wifi.WifiScanner.ScanListener);
     field public static final int MAX_SCAN_PERIOD_MS = 1024000; // 0xfa000
     field public static final int MIN_SCAN_PERIOD_MS = 1000; // 0x3e8
     field public static final int REASON_DUPLICATE_REQEUST = -5; // 0xfffffffb
@@ -5573,10 +5732,16 @@
     field public static final int REPORT_EVENT_AFTER_EACH_SCAN = 1; // 0x1
     field public static final int REPORT_EVENT_FULL_SCAN_RESULT = 2; // 0x2
     field public static final int REPORT_EVENT_NO_BATCH = 4; // 0x4
+    field public static final int SCAN_TYPE_HIGH_ACCURACY = 2; // 0x2
+    field public static final int SCAN_TYPE_LOW_LATENCY = 0; // 0x0
+    field public static final int SCAN_TYPE_LOW_POWER = 1; // 0x1
+    field public static final int WIFI_BAND_24_5_6_GHZ = 11; // 0xb
+    field public static final int WIFI_BAND_24_5_WITH_DFS_6_GHZ = 15; // 0xf
     field public static final int WIFI_BAND_24_GHZ = 1; // 0x1
     field public static final int WIFI_BAND_5_GHZ = 2; // 0x2
     field public static final int WIFI_BAND_5_GHZ_DFS_ONLY = 4; // 0x4
     field public static final int WIFI_BAND_5_GHZ_WITH_DFS = 6; // 0x6
+    field public static final int WIFI_BAND_6_GHZ = 8; // 0x8
     field public static final int WIFI_BAND_BOTH = 3; // 0x3
     field public static final int WIFI_BAND_BOTH_WITH_DFS = 7; // 0x7
     field public static final int WIFI_BAND_UNSPECIFIED = 0; // 0x0
@@ -5641,6 +5806,7 @@
     ctor public WifiScanner.ScanSettings();
     field public int band;
     field public android.net.wifi.WifiScanner.ChannelSpec[] channels;
+    field @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public final java.util.List<android.net.wifi.WifiScanner.ScanSettings.HiddenNetwork> hiddenNetworks;
     field public boolean hideFromAppOps;
     field public boolean ignoreLocationSettings;
     field public int maxPeriodInMs;
@@ -5649,6 +5815,12 @@
     field public int periodInMs;
     field public int reportEvents;
     field public int stepCount;
+    field @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public int type;
+  }
+
+  public static class WifiScanner.ScanSettings.HiddenNetwork {
+    ctor public WifiScanner.ScanSettings.HiddenNetwork(@NonNull String);
+    field @NonNull public final String ssid;
   }
 
   @Deprecated public static interface WifiScanner.WifiChangeListener extends android.net.wifi.WifiScanner.ActionListener {
@@ -5953,6 +6125,7 @@
   }
 
   public class Binder implements android.os.IBinder {
+    method public int handleShellCommand(@NonNull android.os.ParcelFileDescriptor, @NonNull android.os.ParcelFileDescriptor, @NonNull android.os.ParcelFileDescriptor, @NonNull String[]);
     method public static void setProxyTransactListener(@Nullable android.os.Binder.ProxyTransactListener);
   }
 
@@ -5963,6 +6136,7 @@
 
   public final class BugreportManager {
     method @RequiresPermission(android.Manifest.permission.DUMP) public void cancelBugreport();
+    method @RequiresPermission(android.Manifest.permission.DUMP) public void requestBugreport(@NonNull android.os.BugreportParams, @Nullable CharSequence, @Nullable CharSequence);
     method @RequiresPermission(android.Manifest.permission.DUMP) public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
   }
 
@@ -6256,6 +6430,8 @@
   }
 
   public class PowerWhitelistManager {
+    method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public boolean addToWhitelist(@NonNull String);
+    method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public int addToWhitelist(@NonNull java.util.List<java.lang.String>);
     method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String, long);
     method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String, int, @NonNull String);
     field public static final int EVENT_MMS = 2; // 0x2
@@ -6408,6 +6584,7 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.PersistableBundle getSeedAccountOptions();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountType();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public long[] getSerialNumbersOfUsers(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<android.os.UserHandle> getUserHandles(boolean);
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public android.graphics.Bitmap getUserIcon();
     method @Deprecated @android.os.UserManager.UserRestrictionSource @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserRestrictionSource(String, android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<android.os.UserManager.EnforcingUser> getUserRestrictionSources(String, android.os.UserHandle);
@@ -6496,6 +6673,32 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.os.connectivity.CellularBatteryStats> CREATOR;
   }
 
+  public final class WifiActivityEnergyInfo implements android.os.Parcelable {
+    ctor public WifiActivityEnergyInfo(long, int, long, long, long, long);
+    method public int describeContents();
+    method public long getControllerEnergyUsedMicroJoules();
+    method public long getControllerIdleDurationMillis();
+    method public long getControllerRxDurationMillis();
+    method public long getControllerScanDurationMillis();
+    method public long getControllerTxDurationMillis();
+    method public int getStackState();
+    method public long getTimeSinceBootMillis();
+    method public boolean isValid();
+    method public void setControllerEnergyUsedMicroJoules(long);
+    method public void setControllerIdleDurationMillis(long);
+    method public void setControllerRxDurationMillis(long);
+    method public void setControllerScanDurationMillis(long);
+    method public void setControllerTxDurationMillis(long);
+    method public void setStackState(int);
+    method public void setTimeSinceBootMillis(long);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.os.connectivity.WifiActivityEnergyInfo> CREATOR;
+    field public static final int STACK_STATE_INVALID = 0; // 0x0
+    field public static final int STACK_STATE_STATE_ACTIVE = 1; // 0x1
+    field public static final int STACK_STATE_STATE_IDLE = 3; // 0x3
+    field public static final int STACK_STATE_STATE_SCANNING = 2; // 0x2
+  }
+
   public final class WifiBatteryStats implements android.os.Parcelable {
     method public int describeContents();
     method public long getEnergyConsumedMaMillis();
@@ -6518,6 +6721,14 @@
 
 }
 
+package android.os.ext {
+
+  public class SdkExtensions {
+    method public static int getExtensionVersion(int);
+  }
+
+}
+
 package android.os.image {
 
   public class DynamicSystemClient {
@@ -6600,6 +6811,8 @@
   public final class PermissionManager {
     method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public int getRuntimePermissionsVersion();
     method @NonNull public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions();
+    method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToLuiApp(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+    method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void revokeDefaultPermissionsFromLuiApps(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
   }
 
@@ -6713,7 +6926,6 @@
 package android.provider {
 
   public class BlockedNumberContract {
-    field @NonNull public static final android.net.Uri AUTHORITY_URI;
     field public static final String METHOD_NOTIFY_EMERGENCY_CONTACT = "notify_emergency_contact";
     field public static final String METHOD_SHOULD_SYSTEM_BLOCK_NUMBER = "should_system_block_number";
     field public static final String RES_BLOCK_STATUS = "block_status";
@@ -6827,6 +7039,11 @@
     field public static final int FLAG_REMOVABLE_USB = 524288; // 0x80000
   }
 
+  public final class MediaStore {
+    method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE) public static java.util.Set<java.lang.String> getRecentExternalVolumeNames(@NonNull android.content.Context);
+    method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE) public static java.util.Collection<java.io.File> getVolumeScanPaths(@NonNull String) throws java.io.FileNotFoundException;
+  }
+
   public abstract class SearchIndexableData {
     ctor public SearchIndexableData();
     ctor public SearchIndexableData(android.content.Context);
@@ -6942,6 +7159,7 @@
     field public static final String ACTION_ACCESSIBILITY_DETAILS_SETTINGS = "android.settings.ACCESSIBILITY_DETAILS_SETTINGS";
     field public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
     field public static final String ACTION_LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS = "android.settings.LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS";
+    field public static final String ACTION_MANAGE_APP_OVERLAY_PERMISSION = "android.settings.MANAGE_APP_OVERLAY_PERMISSION";
     field public static final String ACTION_MANAGE_DOMAIN_URLS = "android.settings.MANAGE_DOMAIN_URLS";
     field public static final String ACTION_MANAGE_MORE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_MORE_DEFAULT_APPS_SETTINGS";
     field public static final String ACTION_NOTIFICATION_POLICY_ACCESS_DETAIL_SETTINGS = "android.settings.NOTIFICATION_POLICY_ACCESS_DETAIL_SETTINGS";
@@ -6960,6 +7178,8 @@
     field public static final String DEVICE_DEMO_MODE = "device_demo_mode";
     field public static final String DEVICE_PROVISIONING_MOBILE_DATA_ENABLED = "device_provisioning_mobile_data";
     field public static final String EUICC_PROVISIONED = "euicc_provisioned";
+    field public static final String EUICC_SUPPORTED_COUNTRIES = "euicc_supported_countries";
+    field public static final String EUICC_UNSUPPORTED_COUNTRIES = "euicc_unsupported_countries";
     field public static final String INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT = "install_carrier_app_notification_persistent";
     field public static final String INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS = "install_carrier_app_notification_sleep_millis";
     field public static final String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update";
@@ -7081,6 +7301,10 @@
     field public static final String SUB_ID = "sub_id";
   }
 
+  public static final class Telephony.SimInfo {
+    field @NonNull public static final android.net.Uri CONTENT_URI;
+  }
+
   public static final class Telephony.Sms.Intents {
     field public static final String ACTION_SMS_EMERGENCY_CB_RECEIVED = "android.provider.action.SMS_EMERGENCY_CB_RECEIVED";
   }
@@ -7942,7 +8166,7 @@
   }
 
   public static class CallScreeningService.CallResponse.Builder {
-    method public android.telecom.CallScreeningService.CallResponse.Builder setShouldScreenCallFurther(boolean);
+    method @NonNull public android.telecom.CallScreeningService.CallResponse.Builder setShouldScreenCallViaAudioProcessing(boolean);
   }
 
   public abstract class Conference extends android.telecom.Conferenceable {
@@ -7980,6 +8204,10 @@
     field public static final int PROPERTY_REMOTELY_HOSTED = 2048; // 0x800
   }
 
+  public final class ConnectionRequest implements android.os.Parcelable {
+    method @Nullable public String getTelecomCallId();
+  }
+
   public abstract class ConnectionService extends android.app.Service {
     method public final void addExistingConnection(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.Connection, @NonNull android.telecom.Conference);
   }
@@ -8187,6 +8415,7 @@
     method public java.util.List<android.telecom.PhoneAccountHandle> getAllPhoneAccountHandles();
     method public java.util.List<android.telecom.PhoneAccount> getAllPhoneAccounts();
     method public int getAllPhoneAccountsCount();
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts(boolean);
     method public int getCallState();
     method public android.telecom.PhoneAccountHandle getConnectionManager();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCurrentTtyMode();
@@ -8307,6 +8536,10 @@
     field public final double lng;
   }
 
+  public class CellBroadcastIntents {
+    method public static void sendOrderedBroadcastForBackgroundReceivers(@NonNull android.content.Context, @Nullable android.os.UserHandle, @NonNull android.content.Intent, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
+  }
+
   public abstract class CellBroadcastService extends android.app.Service {
     ctor public CellBroadcastService();
     method @CallSuper public android.os.IBinder onBind(@Nullable android.content.Intent);
@@ -9145,6 +9378,7 @@
     method @NonNull public android.content.ContentValues getContentValues();
     method @Nullable public android.telephony.SmsCbEtwsInfo getEtwsWarningInfo();
     method public int getGeographicalScope();
+    method @NonNull public java.util.List<android.telephony.CbGeoUtils.Geometry> getGeometries();
     method @Nullable public String getLanguageCode();
     method @NonNull public android.telephony.SmsCbLocation getLocation();
     method public int getMaximumWaitingDuration();
@@ -9261,6 +9495,7 @@
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int);
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<java.lang.String> getCarrierPrivilegedPackagesForAllActiveSubscriptions();
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(int);
@@ -9986,186 +10221,6 @@
   }
 
   public final class ImsReasonInfo implements android.os.Parcelable {
-    ctor public ImsReasonInfo(int, int, String);
-    method public int describeContents();
-    method public int getCode();
-    method public int getExtraCode();
-    method public String getExtraMessage();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final int CODE_ACCESS_CLASS_BLOCKED = 1512; // 0x5e8
-    field public static final int CODE_ANSWERED_ELSEWHERE = 1014; // 0x3f6
-    field public static final int CODE_BLACKLISTED_CALL_ID = 506; // 0x1fa
-    field public static final int CODE_CALL_BARRED = 240; // 0xf0
-    field public static final int CODE_CALL_DROP_IWLAN_TO_LTE_UNAVAILABLE = 1100; // 0x44c
-    field public static final int CODE_CALL_END_CAUSE_CALL_PULL = 1016; // 0x3f8
-    field public static final int CODE_CALL_PULL_OUT_OF_SYNC = 1015; // 0x3f7
-    field public static final int CODE_DATA_DISABLED = 1406; // 0x57e
-    field public static final int CODE_DATA_LIMIT_REACHED = 1405; // 0x57d
-    field public static final int CODE_DIAL_MODIFIED_TO_DIAL = 246; // 0xf6
-    field public static final int CODE_DIAL_MODIFIED_TO_DIAL_VIDEO = 247; // 0xf7
-    field public static final int CODE_DIAL_MODIFIED_TO_SS = 245; // 0xf5
-    field public static final int CODE_DIAL_MODIFIED_TO_USSD = 244; // 0xf4
-    field public static final int CODE_DIAL_VIDEO_MODIFIED_TO_DIAL = 248; // 0xf8
-    field public static final int CODE_DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO = 249; // 0xf9
-    field public static final int CODE_DIAL_VIDEO_MODIFIED_TO_SS = 250; // 0xfa
-    field public static final int CODE_DIAL_VIDEO_MODIFIED_TO_USSD = 251; // 0xfb
-    field public static final int CODE_ECBM_NOT_SUPPORTED = 901; // 0x385
-    field public static final int CODE_EMERGENCY_PERM_FAILURE = 364; // 0x16c
-    field public static final int CODE_EMERGENCY_TEMP_FAILURE = 363; // 0x16b
-    field public static final int CODE_EPDG_TUNNEL_ESTABLISH_FAILURE = 1400; // 0x578
-    field public static final int CODE_EPDG_TUNNEL_LOST_CONNECTION = 1402; // 0x57a
-    field public static final int CODE_EPDG_TUNNEL_REKEY_FAILURE = 1401; // 0x579
-    field public static final int CODE_FDN_BLOCKED = 241; // 0xf1
-    field public static final int CODE_IKEV2_AUTH_FAILURE = 1408; // 0x580
-    field public static final int CODE_IMEI_NOT_ACCEPTED = 243; // 0xf3
-    field public static final int CODE_IWLAN_DPD_FAILURE = 1300; // 0x514
-    field public static final int CODE_LOCAL_CALL_BUSY = 142; // 0x8e
-    field public static final int CODE_LOCAL_CALL_CS_RETRY_REQUIRED = 146; // 0x92
-    field public static final int CODE_LOCAL_CALL_DECLINE = 143; // 0x8f
-    field public static final int CODE_LOCAL_CALL_EXCEEDED = 141; // 0x8d
-    field public static final int CODE_LOCAL_CALL_RESOURCE_RESERVATION_FAILED = 145; // 0x91
-    field public static final int CODE_LOCAL_CALL_TERMINATED = 148; // 0x94
-    field public static final int CODE_LOCAL_CALL_VCC_ON_PROGRESSING = 144; // 0x90
-    field public static final int CODE_LOCAL_CALL_VOLTE_RETRY_REQUIRED = 147; // 0x93
-    field public static final int CODE_LOCAL_ENDED_BY_CONFERENCE_MERGE = 108; // 0x6c
-    field public static final int CODE_LOCAL_HO_NOT_FEASIBLE = 149; // 0x95
-    field public static final int CODE_LOCAL_ILLEGAL_ARGUMENT = 101; // 0x65
-    field public static final int CODE_LOCAL_ILLEGAL_STATE = 102; // 0x66
-    field public static final int CODE_LOCAL_IMS_SERVICE_DOWN = 106; // 0x6a
-    field public static final int CODE_LOCAL_INTERNAL_ERROR = 103; // 0x67
-    field public static final int CODE_LOCAL_LOW_BATTERY = 112; // 0x70
-    field public static final int CODE_LOCAL_NETWORK_IP_CHANGED = 124; // 0x7c
-    field public static final int CODE_LOCAL_NETWORK_NO_LTE_COVERAGE = 122; // 0x7a
-    field public static final int CODE_LOCAL_NETWORK_NO_SERVICE = 121; // 0x79
-    field public static final int CODE_LOCAL_NETWORK_ROAMING = 123; // 0x7b
-    field public static final int CODE_LOCAL_NOT_REGISTERED = 132; // 0x84
-    field public static final int CODE_LOCAL_NO_PENDING_CALL = 107; // 0x6b
-    field public static final int CODE_LOCAL_POWER_OFF = 111; // 0x6f
-    field public static final int CODE_LOCAL_SERVICE_UNAVAILABLE = 131; // 0x83
-    field public static final int CODE_LOW_BATTERY = 505; // 0x1f9
-    field public static final int CODE_MAXIMUM_NUMBER_OF_CALLS_REACHED = 1403; // 0x57b
-    field public static final int CODE_MEDIA_INIT_FAILED = 401; // 0x191
-    field public static final int CODE_MEDIA_NOT_ACCEPTABLE = 403; // 0x193
-    field public static final int CODE_MEDIA_NO_DATA = 402; // 0x192
-    field public static final int CODE_MEDIA_UNSPECIFIED = 404; // 0x194
-    field public static final int CODE_MULTIENDPOINT_NOT_SUPPORTED = 902; // 0x386
-    field public static final int CODE_NETWORK_DETACH = 1513; // 0x5e9
-    field public static final int CODE_NETWORK_REJECT = 1504; // 0x5e0
-    field public static final int CODE_NETWORK_RESP_TIMEOUT = 1503; // 0x5df
-    field public static final int CODE_NO_CSFB_IN_CS_ROAM = 1516; // 0x5ec
-    field public static final int CODE_NO_VALID_SIM = 1501; // 0x5dd
-    field public static final int CODE_OEM_CAUSE_1 = 61441; // 0xf001
-    field public static final int CODE_OEM_CAUSE_10 = 61450; // 0xf00a
-    field public static final int CODE_OEM_CAUSE_11 = 61451; // 0xf00b
-    field public static final int CODE_OEM_CAUSE_12 = 61452; // 0xf00c
-    field public static final int CODE_OEM_CAUSE_13 = 61453; // 0xf00d
-    field public static final int CODE_OEM_CAUSE_14 = 61454; // 0xf00e
-    field public static final int CODE_OEM_CAUSE_15 = 61455; // 0xf00f
-    field public static final int CODE_OEM_CAUSE_2 = 61442; // 0xf002
-    field public static final int CODE_OEM_CAUSE_3 = 61443; // 0xf003
-    field public static final int CODE_OEM_CAUSE_4 = 61444; // 0xf004
-    field public static final int CODE_OEM_CAUSE_5 = 61445; // 0xf005
-    field public static final int CODE_OEM_CAUSE_6 = 61446; // 0xf006
-    field public static final int CODE_OEM_CAUSE_7 = 61447; // 0xf007
-    field public static final int CODE_OEM_CAUSE_8 = 61448; // 0xf008
-    field public static final int CODE_OEM_CAUSE_9 = 61449; // 0xf009
-    field public static final int CODE_RADIO_ACCESS_FAILURE = 1505; // 0x5e1
-    field public static final int CODE_RADIO_INTERNAL_ERROR = 1502; // 0x5de
-    field public static final int CODE_RADIO_LINK_FAILURE = 1506; // 0x5e2
-    field public static final int CODE_RADIO_LINK_LOST = 1507; // 0x5e3
-    field public static final int CODE_RADIO_OFF = 1500; // 0x5dc
-    field public static final int CODE_RADIO_RELEASE_ABNORMAL = 1511; // 0x5e7
-    field public static final int CODE_RADIO_RELEASE_NORMAL = 1510; // 0x5e6
-    field public static final int CODE_RADIO_SETUP_FAILURE = 1509; // 0x5e5
-    field public static final int CODE_RADIO_UPLINK_FAILURE = 1508; // 0x5e4
-    field public static final int CODE_REGISTRATION_ERROR = 1000; // 0x3e8
-    field public static final int CODE_REJECTED_ELSEWHERE = 1017; // 0x3f9
-    field public static final int CODE_REJECT_1X_COLLISION = 1603; // 0x643
-    field public static final int CODE_REJECT_CALL_ON_OTHER_SUB = 1602; // 0x642
-    field public static final int CODE_REJECT_CALL_TYPE_NOT_ALLOWED = 1605; // 0x645
-    field public static final int CODE_REJECT_CONFERENCE_TTY_NOT_ALLOWED = 1617; // 0x651
-    field public static final int CODE_REJECT_INTERNAL_ERROR = 1612; // 0x64c
-    field public static final int CODE_REJECT_MAX_CALL_LIMIT_REACHED = 1608; // 0x648
-    field public static final int CODE_REJECT_ONGOING_CALL_SETUP = 1607; // 0x647
-    field public static final int CODE_REJECT_ONGOING_CALL_TRANSFER = 1611; // 0x64b
-    field public static final int CODE_REJECT_ONGOING_CALL_UPGRADE = 1616; // 0x650
-    field public static final int CODE_REJECT_ONGOING_CALL_WAITING_DISABLED = 1601; // 0x641
-    field public static final int CODE_REJECT_ONGOING_CONFERENCE_CALL = 1618; // 0x652
-    field public static final int CODE_REJECT_ONGOING_CS_CALL = 1621; // 0x655
-    field public static final int CODE_REJECT_ONGOING_E911_CALL = 1606; // 0x646
-    field public static final int CODE_REJECT_ONGOING_ENCRYPTED_CALL = 1620; // 0x654
-    field public static final int CODE_REJECT_ONGOING_HANDOVER = 1614; // 0x64e
-    field public static final int CODE_REJECT_QOS_FAILURE = 1613; // 0x64d
-    field public static final int CODE_REJECT_SERVICE_NOT_REGISTERED = 1604; // 0x644
-    field public static final int CODE_REJECT_UNKNOWN = 1600; // 0x640
-    field public static final int CODE_REJECT_UNSUPPORTED_SDP_HEADERS = 1610; // 0x64a
-    field public static final int CODE_REJECT_UNSUPPORTED_SIP_HEADERS = 1609; // 0x649
-    field public static final int CODE_REJECT_VT_AVPF_NOT_ALLOWED = 1619; // 0x653
-    field public static final int CODE_REJECT_VT_TTY_NOT_ALLOWED = 1615; // 0x64f
-    field public static final int CODE_REMOTE_CALL_DECLINE = 1404; // 0x57c
-    field public static final int CODE_SESSION_MODIFICATION_FAILED = 1517; // 0x5ed
-    field public static final int CODE_SIP_ALTERNATE_EMERGENCY_CALL = 1514; // 0x5ea
-    field public static final int CODE_SIP_AMBIGUOUS = 376; // 0x178
-    field public static final int CODE_SIP_BAD_ADDRESS = 337; // 0x151
-    field public static final int CODE_SIP_BAD_REQUEST = 331; // 0x14b
-    field public static final int CODE_SIP_BUSY = 338; // 0x152
-    field public static final int CODE_SIP_CALL_OR_TRANS_DOES_NOT_EXIST = 372; // 0x174
-    field public static final int CODE_SIP_CLIENT_ERROR = 342; // 0x156
-    field public static final int CODE_SIP_EXTENSION_REQUIRED = 370; // 0x172
-    field public static final int CODE_SIP_FORBIDDEN = 332; // 0x14c
-    field public static final int CODE_SIP_GLOBAL_ERROR = 362; // 0x16a
-    field public static final int CODE_SIP_INTERVAL_TOO_BRIEF = 371; // 0x173
-    field public static final int CODE_SIP_LOOP_DETECTED = 373; // 0x175
-    field public static final int CODE_SIP_METHOD_NOT_ALLOWED = 366; // 0x16e
-    field public static final int CODE_SIP_NOT_ACCEPTABLE = 340; // 0x154
-    field public static final int CODE_SIP_NOT_FOUND = 333; // 0x14d
-    field public static final int CODE_SIP_NOT_REACHABLE = 341; // 0x155
-    field public static final int CODE_SIP_NOT_SUPPORTED = 334; // 0x14e
-    field public static final int CODE_SIP_PROXY_AUTHENTICATION_REQUIRED = 367; // 0x16f
-    field public static final int CODE_SIP_REDIRECTED = 321; // 0x141
-    field public static final int CODE_SIP_REQUEST_CANCELLED = 339; // 0x153
-    field public static final int CODE_SIP_REQUEST_ENTITY_TOO_LARGE = 368; // 0x170
-    field public static final int CODE_SIP_REQUEST_PENDING = 377; // 0x179
-    field public static final int CODE_SIP_REQUEST_TIMEOUT = 335; // 0x14f
-    field public static final int CODE_SIP_REQUEST_URI_TOO_LARGE = 369; // 0x171
-    field public static final int CODE_SIP_SERVER_ERROR = 354; // 0x162
-    field public static final int CODE_SIP_SERVER_INTERNAL_ERROR = 351; // 0x15f
-    field public static final int CODE_SIP_SERVER_TIMEOUT = 353; // 0x161
-    field public static final int CODE_SIP_SERVICE_UNAVAILABLE = 352; // 0x160
-    field public static final int CODE_SIP_TEMPRARILY_UNAVAILABLE = 336; // 0x150
-    field public static final int CODE_SIP_TOO_MANY_HOPS = 374; // 0x176
-    field public static final int CODE_SIP_TRANSACTION_DOES_NOT_EXIST = 343; // 0x157
-    field public static final int CODE_SIP_UNDECIPHERABLE = 378; // 0x17a
-    field public static final int CODE_SIP_USER_MARKED_UNWANTED = 365; // 0x16d
-    field public static final int CODE_SIP_USER_REJECTED = 361; // 0x169
-    field public static final int CODE_SUPP_SVC_CANCELLED = 1202; // 0x4b2
-    field public static final int CODE_SUPP_SVC_FAILED = 1201; // 0x4b1
-    field public static final int CODE_SUPP_SVC_REINVITE_COLLISION = 1203; // 0x4b3
-    field public static final int CODE_TIMEOUT_1XX_WAITING = 201; // 0xc9
-    field public static final int CODE_TIMEOUT_NO_ANSWER = 202; // 0xca
-    field public static final int CODE_TIMEOUT_NO_ANSWER_CALL_UPDATE = 203; // 0xcb
-    field public static final int CODE_UNSPECIFIED = 0; // 0x0
-    field public static final int CODE_USER_CANCELLED_SESSION_MODIFICATION = 512; // 0x200
-    field public static final int CODE_USER_DECLINE = 504; // 0x1f8
-    field public static final int CODE_USER_IGNORE = 503; // 0x1f7
-    field public static final int CODE_USER_NOANSWER = 502; // 0x1f6
-    field public static final int CODE_USER_REJECTED_SESSION_MODIFICATION = 511; // 0x1ff
-    field public static final int CODE_USER_TERMINATED = 501; // 0x1f5
-    field public static final int CODE_USER_TERMINATED_BY_REMOTE = 510; // 0x1fe
-    field public static final int CODE_UT_CB_PASSWORD_MISMATCH = 821; // 0x335
-    field public static final int CODE_UT_NETWORK_ERROR = 804; // 0x324
-    field public static final int CODE_UT_NOT_SUPPORTED = 801; // 0x321
-    field public static final int CODE_UT_OPERATION_NOT_ALLOWED = 803; // 0x323
-    field public static final int CODE_UT_SERVICE_UNAVAILABLE = 802; // 0x322
-    field public static final int CODE_UT_SS_MODIFIED_TO_DIAL = 822; // 0x336
-    field public static final int CODE_UT_SS_MODIFIED_TO_DIAL_VIDEO = 825; // 0x339
-    field public static final int CODE_UT_SS_MODIFIED_TO_SS = 824; // 0x338
-    field public static final int CODE_UT_SS_MODIFIED_TO_USSD = 823; // 0x337
-    field public static final int CODE_WIFI_LOST = 1407; // 0x57f
-    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsReasonInfo> CREATOR;
-    field public static final int EXTRA_CODE_CALL_RETRY_BY_SETTINGS = 3; // 0x3
-    field public static final int EXTRA_CODE_CALL_RETRY_NORMAL = 1; // 0x1
-    field public static final int EXTRA_CODE_CALL_RETRY_SILENT_REDIAL = 2; // 0x2
     field public static final String EXTRA_MSG_SERVICE_NOT_AUTHORIZED = "Forbidden. Not Authorized for Service";
   }
 
diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt
index ab0f0f9..9a635757 100644
--- a/api/system-lint-baseline.txt
+++ b/api/system-lint-baseline.txt
@@ -65,7 +65,7 @@
 MissingNullability: android.media.tv.TvRecordingClient.RecordingCallback#onEvent(String, String, android.os.Bundle) parameter #1:
     
 MissingNullability: android.media.tv.TvRecordingClient.RecordingCallback#onEvent(String, String, android.os.Bundle) parameter #2:
-    
+
 MissingNullability: android.net.wifi.rtt.RangingRequest.Builder#addResponder(android.net.wifi.rtt.ResponderConfig):
     
 MissingNullability: android.printservice.recommendation.RecommendationService#attachBaseContext(android.content.Context) parameter #0:
@@ -181,6 +181,8 @@
     Bare field saePasswordId must be marked final, or moved behind accessors if mutable
 MutableBareField: android.net.wifi.WifiConfiguration#shared:
     Bare field shared must be marked final, or moved behind accessors if mutable
+MutableBareField: android.net.wifi.WifiScanner.ScanSettings#type:
+    Bare field type must be marked final, or moved behind accessors if mutable
 
 
 NoClone: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
@@ -194,7 +196,6 @@
 ProtectedMember: android.service.notification.NotificationAssistantService#attachBaseContext(android.content.Context):
     
 
-
 SamShouldBeLast: android.accounts.AccountManager#addAccount(String, String, String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
     
 SamShouldBeLast: android.accounts.AccountManager#addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean):
diff --git a/api/test-current.txt b/api/test-current.txt
index 6f5fef1..acea9aa 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -578,6 +578,7 @@
     field public static final int ACTION_DISMISS = 2; // 0x2
     field public static final int ACTION_LAUNCH = 1; // 0x1
     field public static final int ACTION_PIN = 3; // 0x3
+    field public static final int ACTION_UNPIN = 4; // 0x4
     field @NonNull public static final android.os.Parcelable.Creator<android.app.prediction.AppTargetEvent> CREATOR;
   }
 
@@ -1086,6 +1087,7 @@
     ctor public GnssMeasurement();
     method public void reset();
     method public void resetAutomaticGainControlLevel();
+    method public void resetBasebandCn0DbHz();
     method @Deprecated public void resetCarrierCycles();
     method public void resetCarrierFrequencyHz();
     method @Deprecated public void resetCarrierPhase();
@@ -1097,6 +1099,7 @@
     method public void setAccumulatedDeltaRangeState(int);
     method public void setAccumulatedDeltaRangeUncertaintyMeters(double);
     method public void setAutomaticGainControlLevelInDb(double);
+    method public void setBasebandCn0DbHz(double);
     method @Deprecated public void setCarrierCycles(long);
     method public void setCarrierFrequencyHz(float);
     method @Deprecated public void setCarrierPhase(double);
@@ -1467,7 +1470,6 @@
     ctor public LinkProperties(@Nullable android.net.LinkProperties);
     method public boolean addDnsServer(@NonNull java.net.InetAddress);
     method public boolean addLinkAddress(@NonNull android.net.LinkAddress);
-    method @Nullable public android.net.IpPrefix getNat64Prefix();
     method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
     method @Nullable public String getTcpBufferSizes();
     method @NonNull public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
@@ -1481,7 +1483,6 @@
     method public boolean removeDnsServer(@NonNull java.net.InetAddress);
     method public boolean removeLinkAddress(@NonNull android.net.LinkAddress);
     method public boolean removeRoute(@NonNull android.net.RouteInfo);
-    method public void setNat64Prefix(@Nullable android.net.IpPrefix);
     method public void setPcscfServers(@NonNull java.util.Collection<java.net.InetAddress>);
     method public void setPrivateDnsServerName(@Nullable String);
     method public void setTcpBufferSizes(@Nullable String);
@@ -1757,6 +1758,7 @@
 
   public final class BugreportManager {
     method @RequiresPermission(android.Manifest.permission.DUMP) public void cancelBugreport();
+    method @RequiresPermission(android.Manifest.permission.DUMP) public void requestBugreport(@NonNull android.os.BugreportParams, @Nullable CharSequence, @Nullable CharSequence);
     method @RequiresPermission(android.Manifest.permission.DUMP) public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
   }
 
@@ -1795,7 +1797,6 @@
   }
 
   public class DeviceIdleManager {
-    method @RequiresPermission("android.permission.DEVICE_POWER") public int addPowerSaveWhitelistApps(@NonNull java.util.List<java.lang.String>);
     method @NonNull public String[] getSystemPowerWhitelist();
     method @NonNull public String[] getSystemPowerWhitelistExceptIdle();
   }
@@ -2044,6 +2045,8 @@
   }
 
   public class PowerWhitelistManager {
+    method @RequiresPermission("android.permission.DEVICE_POWER") public boolean addToWhitelist(@NonNull String);
+    method @RequiresPermission("android.permission.DEVICE_POWER") public int addToWhitelist(@NonNull java.util.List<java.lang.String>);
     method @RequiresPermission("android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST") public void whitelistAppTemporarily(@NonNull String, long);
     method @RequiresPermission("android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST") public long whitelistAppTemporarilyForEvent(@NonNull String, int, @NonNull String);
     field public static final int EVENT_MMS = 2; // 0x2
@@ -2453,7 +2456,7 @@
     method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static void deleteContributedMedia(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static long getContributedMediaSize(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
     method @NonNull public static java.io.File getVolumePath(@NonNull String) throws java.io.FileNotFoundException;
-    method @NonNull public static java.util.Collection<java.io.File> getVolumeScanPaths(@NonNull String) throws java.io.FileNotFoundException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE) public static java.util.Collection<java.io.File> getVolumeScanPaths(@NonNull String) throws java.io.FileNotFoundException;
     method public static android.net.Uri scanFile(android.content.Context, java.io.File);
     method public static android.net.Uri scanFileFromShell(android.content.Context, java.io.File);
     method public static void scanVolume(android.content.Context, java.io.File);
@@ -2462,6 +2465,7 @@
 
   public final class Settings {
     field public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
+    field public static final String ACTION_MANAGE_APP_OVERLAY_PERMISSION = "android.settings.MANAGE_APP_OVERLAY_PERMISSION";
     field public static final String ACTION_REQUEST_ENABLE_CONTENT_CAPTURE = "android.settings.REQUEST_ENABLE_CONTENT_CAPTURE";
     field public static final int RESET_MODE_PACKAGE_DEFAULTS = 1; // 0x1
   }
@@ -2943,7 +2947,7 @@
   }
 
   public static class CallScreeningService.CallResponse.Builder {
-    method public android.telecom.CallScreeningService.CallResponse.Builder setShouldScreenCallFurther(boolean);
+    method @NonNull public android.telecom.CallScreeningService.CallResponse.Builder setShouldScreenCallViaAudioProcessing(boolean);
   }
 
   public abstract class Conference extends android.telecom.Conferenceable {
@@ -2975,6 +2979,23 @@
     field public static final int PROPERTY_REMOTELY_HOSTED = 2048; // 0x800
   }
 
+  public final class ConnectionRequest implements android.os.Parcelable {
+    method @Nullable public String getTelecomCallId();
+  }
+
+  public static final class ConnectionRequest.Builder {
+    ctor public ConnectionRequest.Builder();
+    method @NonNull public android.telecom.ConnectionRequest build();
+    method @NonNull public android.telecom.ConnectionRequest.Builder setAccountHandle(@NonNull android.telecom.PhoneAccountHandle);
+    method @NonNull public android.telecom.ConnectionRequest.Builder setAddress(@NonNull android.net.Uri);
+    method @NonNull public android.telecom.ConnectionRequest.Builder setExtras(@NonNull android.os.Bundle);
+    method @NonNull public android.telecom.ConnectionRequest.Builder setRttPipeFromInCall(@NonNull android.os.ParcelFileDescriptor);
+    method @NonNull public android.telecom.ConnectionRequest.Builder setRttPipeToInCall(@NonNull android.os.ParcelFileDescriptor);
+    method @NonNull public android.telecom.ConnectionRequest.Builder setShouldShowIncomingCallUi(boolean);
+    method @NonNull public android.telecom.ConnectionRequest.Builder setTelecomCallId(@NonNull String);
+    method @NonNull public android.telecom.ConnectionRequest.Builder setVideoState(int);
+  }
+
   public static class PhoneAccount.Builder {
     method @NonNull public android.telecom.PhoneAccount.Builder setGroupId(@NonNull String);
   }
@@ -2988,6 +3009,7 @@
   }
 
   public class TelecomManager {
+    method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts(boolean);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getCurrentTtyMode();
     method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getDefaultDialerPackage(int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall();
@@ -3435,190 +3457,6 @@
     ctor @Deprecated public ImsMmTelManager.RegistrationCallback();
   }
 
-  public final class ImsReasonInfo implements android.os.Parcelable {
-    ctor public ImsReasonInfo(int, int, String);
-    method public int describeContents();
-    method public int getCode();
-    method public int getExtraCode();
-    method public String getExtraMessage();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final int CODE_ACCESS_CLASS_BLOCKED = 1512; // 0x5e8
-    field public static final int CODE_ANSWERED_ELSEWHERE = 1014; // 0x3f6
-    field public static final int CODE_BLACKLISTED_CALL_ID = 506; // 0x1fa
-    field public static final int CODE_CALL_BARRED = 240; // 0xf0
-    field public static final int CODE_CALL_DROP_IWLAN_TO_LTE_UNAVAILABLE = 1100; // 0x44c
-    field public static final int CODE_CALL_END_CAUSE_CALL_PULL = 1016; // 0x3f8
-    field public static final int CODE_CALL_PULL_OUT_OF_SYNC = 1015; // 0x3f7
-    field public static final int CODE_DATA_DISABLED = 1406; // 0x57e
-    field public static final int CODE_DATA_LIMIT_REACHED = 1405; // 0x57d
-    field public static final int CODE_DIAL_MODIFIED_TO_DIAL = 246; // 0xf6
-    field public static final int CODE_DIAL_MODIFIED_TO_DIAL_VIDEO = 247; // 0xf7
-    field public static final int CODE_DIAL_MODIFIED_TO_SS = 245; // 0xf5
-    field public static final int CODE_DIAL_MODIFIED_TO_USSD = 244; // 0xf4
-    field public static final int CODE_DIAL_VIDEO_MODIFIED_TO_DIAL = 248; // 0xf8
-    field public static final int CODE_DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO = 249; // 0xf9
-    field public static final int CODE_DIAL_VIDEO_MODIFIED_TO_SS = 250; // 0xfa
-    field public static final int CODE_DIAL_VIDEO_MODIFIED_TO_USSD = 251; // 0xfb
-    field public static final int CODE_ECBM_NOT_SUPPORTED = 901; // 0x385
-    field public static final int CODE_EMERGENCY_PERM_FAILURE = 364; // 0x16c
-    field public static final int CODE_EMERGENCY_TEMP_FAILURE = 363; // 0x16b
-    field public static final int CODE_EPDG_TUNNEL_ESTABLISH_FAILURE = 1400; // 0x578
-    field public static final int CODE_EPDG_TUNNEL_LOST_CONNECTION = 1402; // 0x57a
-    field public static final int CODE_EPDG_TUNNEL_REKEY_FAILURE = 1401; // 0x579
-    field public static final int CODE_FDN_BLOCKED = 241; // 0xf1
-    field public static final int CODE_IKEV2_AUTH_FAILURE = 1408; // 0x580
-    field public static final int CODE_IMEI_NOT_ACCEPTED = 243; // 0xf3
-    field public static final int CODE_IWLAN_DPD_FAILURE = 1300; // 0x514
-    field public static final int CODE_LOCAL_CALL_BUSY = 142; // 0x8e
-    field public static final int CODE_LOCAL_CALL_CS_RETRY_REQUIRED = 146; // 0x92
-    field public static final int CODE_LOCAL_CALL_DECLINE = 143; // 0x8f
-    field public static final int CODE_LOCAL_CALL_EXCEEDED = 141; // 0x8d
-    field public static final int CODE_LOCAL_CALL_RESOURCE_RESERVATION_FAILED = 145; // 0x91
-    field public static final int CODE_LOCAL_CALL_TERMINATED = 148; // 0x94
-    field public static final int CODE_LOCAL_CALL_VCC_ON_PROGRESSING = 144; // 0x90
-    field public static final int CODE_LOCAL_CALL_VOLTE_RETRY_REQUIRED = 147; // 0x93
-    field public static final int CODE_LOCAL_ENDED_BY_CONFERENCE_MERGE = 108; // 0x6c
-    field public static final int CODE_LOCAL_HO_NOT_FEASIBLE = 149; // 0x95
-    field public static final int CODE_LOCAL_ILLEGAL_ARGUMENT = 101; // 0x65
-    field public static final int CODE_LOCAL_ILLEGAL_STATE = 102; // 0x66
-    field public static final int CODE_LOCAL_IMS_SERVICE_DOWN = 106; // 0x6a
-    field public static final int CODE_LOCAL_INTERNAL_ERROR = 103; // 0x67
-    field public static final int CODE_LOCAL_LOW_BATTERY = 112; // 0x70
-    field public static final int CODE_LOCAL_NETWORK_IP_CHANGED = 124; // 0x7c
-    field public static final int CODE_LOCAL_NETWORK_NO_LTE_COVERAGE = 122; // 0x7a
-    field public static final int CODE_LOCAL_NETWORK_NO_SERVICE = 121; // 0x79
-    field public static final int CODE_LOCAL_NETWORK_ROAMING = 123; // 0x7b
-    field public static final int CODE_LOCAL_NOT_REGISTERED = 132; // 0x84
-    field public static final int CODE_LOCAL_NO_PENDING_CALL = 107; // 0x6b
-    field public static final int CODE_LOCAL_POWER_OFF = 111; // 0x6f
-    field public static final int CODE_LOCAL_SERVICE_UNAVAILABLE = 131; // 0x83
-    field public static final int CODE_LOW_BATTERY = 505; // 0x1f9
-    field public static final int CODE_MAXIMUM_NUMBER_OF_CALLS_REACHED = 1403; // 0x57b
-    field public static final int CODE_MEDIA_INIT_FAILED = 401; // 0x191
-    field public static final int CODE_MEDIA_NOT_ACCEPTABLE = 403; // 0x193
-    field public static final int CODE_MEDIA_NO_DATA = 402; // 0x192
-    field public static final int CODE_MEDIA_UNSPECIFIED = 404; // 0x194
-    field public static final int CODE_MULTIENDPOINT_NOT_SUPPORTED = 902; // 0x386
-    field public static final int CODE_NETWORK_DETACH = 1513; // 0x5e9
-    field public static final int CODE_NETWORK_REJECT = 1504; // 0x5e0
-    field public static final int CODE_NETWORK_RESP_TIMEOUT = 1503; // 0x5df
-    field public static final int CODE_NO_CSFB_IN_CS_ROAM = 1516; // 0x5ec
-    field public static final int CODE_NO_VALID_SIM = 1501; // 0x5dd
-    field public static final int CODE_OEM_CAUSE_1 = 61441; // 0xf001
-    field public static final int CODE_OEM_CAUSE_10 = 61450; // 0xf00a
-    field public static final int CODE_OEM_CAUSE_11 = 61451; // 0xf00b
-    field public static final int CODE_OEM_CAUSE_12 = 61452; // 0xf00c
-    field public static final int CODE_OEM_CAUSE_13 = 61453; // 0xf00d
-    field public static final int CODE_OEM_CAUSE_14 = 61454; // 0xf00e
-    field public static final int CODE_OEM_CAUSE_15 = 61455; // 0xf00f
-    field public static final int CODE_OEM_CAUSE_2 = 61442; // 0xf002
-    field public static final int CODE_OEM_CAUSE_3 = 61443; // 0xf003
-    field public static final int CODE_OEM_CAUSE_4 = 61444; // 0xf004
-    field public static final int CODE_OEM_CAUSE_5 = 61445; // 0xf005
-    field public static final int CODE_OEM_CAUSE_6 = 61446; // 0xf006
-    field public static final int CODE_OEM_CAUSE_7 = 61447; // 0xf007
-    field public static final int CODE_OEM_CAUSE_8 = 61448; // 0xf008
-    field public static final int CODE_OEM_CAUSE_9 = 61449; // 0xf009
-    field public static final int CODE_RADIO_ACCESS_FAILURE = 1505; // 0x5e1
-    field public static final int CODE_RADIO_INTERNAL_ERROR = 1502; // 0x5de
-    field public static final int CODE_RADIO_LINK_FAILURE = 1506; // 0x5e2
-    field public static final int CODE_RADIO_LINK_LOST = 1507; // 0x5e3
-    field public static final int CODE_RADIO_OFF = 1500; // 0x5dc
-    field public static final int CODE_RADIO_RELEASE_ABNORMAL = 1511; // 0x5e7
-    field public static final int CODE_RADIO_RELEASE_NORMAL = 1510; // 0x5e6
-    field public static final int CODE_RADIO_SETUP_FAILURE = 1509; // 0x5e5
-    field public static final int CODE_RADIO_UPLINK_FAILURE = 1508; // 0x5e4
-    field public static final int CODE_REGISTRATION_ERROR = 1000; // 0x3e8
-    field public static final int CODE_REJECTED_ELSEWHERE = 1017; // 0x3f9
-    field public static final int CODE_REJECT_1X_COLLISION = 1603; // 0x643
-    field public static final int CODE_REJECT_CALL_ON_OTHER_SUB = 1602; // 0x642
-    field public static final int CODE_REJECT_CALL_TYPE_NOT_ALLOWED = 1605; // 0x645
-    field public static final int CODE_REJECT_CONFERENCE_TTY_NOT_ALLOWED = 1617; // 0x651
-    field public static final int CODE_REJECT_INTERNAL_ERROR = 1612; // 0x64c
-    field public static final int CODE_REJECT_MAX_CALL_LIMIT_REACHED = 1608; // 0x648
-    field public static final int CODE_REJECT_ONGOING_CALL_SETUP = 1607; // 0x647
-    field public static final int CODE_REJECT_ONGOING_CALL_TRANSFER = 1611; // 0x64b
-    field public static final int CODE_REJECT_ONGOING_CALL_UPGRADE = 1616; // 0x650
-    field public static final int CODE_REJECT_ONGOING_CALL_WAITING_DISABLED = 1601; // 0x641
-    field public static final int CODE_REJECT_ONGOING_CONFERENCE_CALL = 1618; // 0x652
-    field public static final int CODE_REJECT_ONGOING_CS_CALL = 1621; // 0x655
-    field public static final int CODE_REJECT_ONGOING_E911_CALL = 1606; // 0x646
-    field public static final int CODE_REJECT_ONGOING_ENCRYPTED_CALL = 1620; // 0x654
-    field public static final int CODE_REJECT_ONGOING_HANDOVER = 1614; // 0x64e
-    field public static final int CODE_REJECT_QOS_FAILURE = 1613; // 0x64d
-    field public static final int CODE_REJECT_SERVICE_NOT_REGISTERED = 1604; // 0x644
-    field public static final int CODE_REJECT_UNKNOWN = 1600; // 0x640
-    field public static final int CODE_REJECT_UNSUPPORTED_SDP_HEADERS = 1610; // 0x64a
-    field public static final int CODE_REJECT_UNSUPPORTED_SIP_HEADERS = 1609; // 0x649
-    field public static final int CODE_REJECT_VT_AVPF_NOT_ALLOWED = 1619; // 0x653
-    field public static final int CODE_REJECT_VT_TTY_NOT_ALLOWED = 1615; // 0x64f
-    field public static final int CODE_REMOTE_CALL_DECLINE = 1404; // 0x57c
-    field public static final int CODE_SESSION_MODIFICATION_FAILED = 1517; // 0x5ed
-    field public static final int CODE_SIP_ALTERNATE_EMERGENCY_CALL = 1514; // 0x5ea
-    field public static final int CODE_SIP_AMBIGUOUS = 376; // 0x178
-    field public static final int CODE_SIP_BAD_ADDRESS = 337; // 0x151
-    field public static final int CODE_SIP_BAD_REQUEST = 331; // 0x14b
-    field public static final int CODE_SIP_BUSY = 338; // 0x152
-    field public static final int CODE_SIP_CALL_OR_TRANS_DOES_NOT_EXIST = 372; // 0x174
-    field public static final int CODE_SIP_CLIENT_ERROR = 342; // 0x156
-    field public static final int CODE_SIP_EXTENSION_REQUIRED = 370; // 0x172
-    field public static final int CODE_SIP_FORBIDDEN = 332; // 0x14c
-    field public static final int CODE_SIP_GLOBAL_ERROR = 362; // 0x16a
-    field public static final int CODE_SIP_INTERVAL_TOO_BRIEF = 371; // 0x173
-    field public static final int CODE_SIP_LOOP_DETECTED = 373; // 0x175
-    field public static final int CODE_SIP_METHOD_NOT_ALLOWED = 366; // 0x16e
-    field public static final int CODE_SIP_NOT_ACCEPTABLE = 340; // 0x154
-    field public static final int CODE_SIP_NOT_FOUND = 333; // 0x14d
-    field public static final int CODE_SIP_NOT_REACHABLE = 341; // 0x155
-    field public static final int CODE_SIP_NOT_SUPPORTED = 334; // 0x14e
-    field public static final int CODE_SIP_PROXY_AUTHENTICATION_REQUIRED = 367; // 0x16f
-    field public static final int CODE_SIP_REDIRECTED = 321; // 0x141
-    field public static final int CODE_SIP_REQUEST_CANCELLED = 339; // 0x153
-    field public static final int CODE_SIP_REQUEST_ENTITY_TOO_LARGE = 368; // 0x170
-    field public static final int CODE_SIP_REQUEST_PENDING = 377; // 0x179
-    field public static final int CODE_SIP_REQUEST_TIMEOUT = 335; // 0x14f
-    field public static final int CODE_SIP_REQUEST_URI_TOO_LARGE = 369; // 0x171
-    field public static final int CODE_SIP_SERVER_ERROR = 354; // 0x162
-    field public static final int CODE_SIP_SERVER_INTERNAL_ERROR = 351; // 0x15f
-    field public static final int CODE_SIP_SERVER_TIMEOUT = 353; // 0x161
-    field public static final int CODE_SIP_SERVICE_UNAVAILABLE = 352; // 0x160
-    field public static final int CODE_SIP_TEMPRARILY_UNAVAILABLE = 336; // 0x150
-    field public static final int CODE_SIP_TOO_MANY_HOPS = 374; // 0x176
-    field public static final int CODE_SIP_TRANSACTION_DOES_NOT_EXIST = 343; // 0x157
-    field public static final int CODE_SIP_UNDECIPHERABLE = 378; // 0x17a
-    field public static final int CODE_SIP_USER_MARKED_UNWANTED = 365; // 0x16d
-    field public static final int CODE_SIP_USER_REJECTED = 361; // 0x169
-    field public static final int CODE_SUPP_SVC_CANCELLED = 1202; // 0x4b2
-    field public static final int CODE_SUPP_SVC_FAILED = 1201; // 0x4b1
-    field public static final int CODE_SUPP_SVC_REINVITE_COLLISION = 1203; // 0x4b3
-    field public static final int CODE_TIMEOUT_1XX_WAITING = 201; // 0xc9
-    field public static final int CODE_TIMEOUT_NO_ANSWER = 202; // 0xca
-    field public static final int CODE_TIMEOUT_NO_ANSWER_CALL_UPDATE = 203; // 0xcb
-    field public static final int CODE_UNSPECIFIED = 0; // 0x0
-    field public static final int CODE_USER_CANCELLED_SESSION_MODIFICATION = 512; // 0x200
-    field public static final int CODE_USER_DECLINE = 504; // 0x1f8
-    field public static final int CODE_USER_IGNORE = 503; // 0x1f7
-    field public static final int CODE_USER_NOANSWER = 502; // 0x1f6
-    field public static final int CODE_USER_REJECTED_SESSION_MODIFICATION = 511; // 0x1ff
-    field public static final int CODE_USER_TERMINATED = 501; // 0x1f5
-    field public static final int CODE_USER_TERMINATED_BY_REMOTE = 510; // 0x1fe
-    field public static final int CODE_UT_CB_PASSWORD_MISMATCH = 821; // 0x335
-    field public static final int CODE_UT_NETWORK_ERROR = 804; // 0x324
-    field public static final int CODE_UT_NOT_SUPPORTED = 801; // 0x321
-    field public static final int CODE_UT_OPERATION_NOT_ALLOWED = 803; // 0x323
-    field public static final int CODE_UT_SERVICE_UNAVAILABLE = 802; // 0x322
-    field public static final int CODE_UT_SS_MODIFIED_TO_DIAL = 822; // 0x336
-    field public static final int CODE_UT_SS_MODIFIED_TO_DIAL_VIDEO = 825; // 0x339
-    field public static final int CODE_UT_SS_MODIFIED_TO_SS = 824; // 0x338
-    field public static final int CODE_UT_SS_MODIFIED_TO_USSD = 823; // 0x337
-    field public static final int CODE_WIFI_LOST = 1407; // 0x57f
-    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsReasonInfo> CREATOR;
-    field public static final int EXTRA_CODE_CALL_RETRY_BY_SETTINGS = 3; // 0x3
-    field public static final int EXTRA_CODE_CALL_RETRY_NORMAL = 1; // 0x1
-    field public static final int EXTRA_CODE_CALL_RETRY_SILENT_REDIAL = 2; // 0x2
-    field public static final String EXTRA_MSG_SERVICE_NOT_AUTHORIZED = "Forbidden. Not Authorized for Service";
-  }
-
   public class ImsService extends android.app.Service {
     ctor public ImsService();
     method public android.telephony.ims.feature.MmTelFeature createMmTelFeature(int);
@@ -4275,6 +4113,7 @@
     field public static final String PERSIST_PREFIX = "persist.sys.fflag.override.";
     field public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
     field public static final String SEAMLESS_TRANSFER = "settings_seamless_transfer";
+    field public static final String SETTINGS_FUSE_FLAG = "settings_fuse";
     field public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
   }
 
diff --git a/api/test-lint-baseline.txt b/api/test-lint-baseline.txt
index ba85ae6..ef8165f 100644
--- a/api/test-lint-baseline.txt
+++ b/api/test-lint-baseline.txt
@@ -8,35 +8,35 @@
 ActionValue: android.location.Location#EXTRA_NO_GPS_LOCATION:
     
 ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_ADDITIONAL_CALL_INFO:
-    Inconsistent extra value; expected `android.telephony.ims.extra.ADDITIONAL_CALL_INFO`, was `AdditionalCallInfo`
+    
 ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_CALL_RAT_TYPE:
-    Inconsistent extra value; expected `android.telephony.ims.extra.CALL_RAT_TYPE`, was `CallRadioTech`
+    
 ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_CHILD_NUMBER:
-    Inconsistent extra value; expected `android.telephony.ims.extra.CHILD_NUMBER`, was `ChildNum`
+    
 ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_CNA:
-    Inconsistent extra value; expected `android.telephony.ims.extra.CNA`, was `cna`
+    
 ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_CNAP:
-    Inconsistent extra value; expected `android.telephony.ims.extra.CNAP`, was `cnap`
+    
 ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_CODEC:
-    Inconsistent extra value; expected `android.telephony.ims.extra.CODEC`, was `Codec`
+    
 ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_DIALSTRING:
-    Inconsistent extra value; expected `android.telephony.ims.extra.DIALSTRING`, was `dialstring`
+    
 ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_DISPLAY_TEXT:
-    Inconsistent extra value; expected `android.telephony.ims.extra.DISPLAY_TEXT`, was `DisplayText`
+    
 ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_EMERGENCY_CALL:
-    Inconsistent extra value; expected `android.telephony.ims.extra.EMERGENCY_CALL`, was `e_call`
+    
 ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_IS_CALL_PULL:
-    Inconsistent extra value; expected `android.telephony.ims.extra.IS_CALL_PULL`, was `CallPull`
+    
 ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_OI:
-    Inconsistent extra value; expected `android.telephony.ims.extra.OI`, was `oi`
+    
 ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_OIR:
-    Inconsistent extra value; expected `android.telephony.ims.extra.OIR`, was `oir`
+    
 ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_REMOTE_URI:
-    Inconsistent extra value; expected `android.telephony.ims.extra.REMOTE_URI`, was `remote_uri`
+    
 ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_USSD:
-    Inconsistent extra value; expected `android.telephony.ims.extra.USSD`, was `ussd`
+    
 ActionValue: android.telephony.ims.ImsReasonInfo#EXTRA_MSG_SERVICE_NOT_AUTHORIZED:
-    Inconsistent extra value; expected `android.telephony.ims.extra.MSG_SERVICE_NOT_AUTHORIZED`, was `Forbidden. Not Authorized for Service`
+    
 ActionValue: android.telephony.mbms.vendor.VendorUtils#ACTION_CLEANUP:
     
 ActionValue: android.telephony.mbms.vendor.VendorUtils#ACTION_DOWNLOAD_RESULT_INTERNAL:
@@ -100,13 +100,13 @@
 ArrayReturn: android.security.keystore.AttestationUtils#attestDeviceIds(android.content.Context, int[], byte[]):
     
 ArrayReturn: android.telephony.ims.ImsUtListener#onUtConfigurationCallBarringQueried(int, android.telephony.ims.ImsSsInfo[]) parameter #1:
-    Method parameter should be Collection<ImsSsInfo> (or subclass) instead of raw array; was `android.telephony.ims.ImsSsInfo[]`
+    
 ArrayReturn: android.telephony.ims.ImsUtListener#onUtConfigurationCallForwardQueried(int, android.telephony.ims.ImsCallForwardInfo[]) parameter #1:
-    Method parameter should be Collection<ImsCallForwardInfo> (or subclass) instead of raw array; was `android.telephony.ims.ImsCallForwardInfo[]`
+    
 ArrayReturn: android.telephony.ims.ImsUtListener#onUtConfigurationCallWaitingQueried(int, android.telephony.ims.ImsSsInfo[]) parameter #1:
-    Method parameter should be Collection<ImsSsInfo> (or subclass) instead of raw array; was `android.telephony.ims.ImsSsInfo[]`
+    
 ArrayReturn: android.telephony.ims.stub.ImsRegistrationImplBase#onSubscriberAssociatedUriChanged(android.net.Uri[]) parameter #0:
-    Method parameter should be Collection<Uri> (or subclass) instead of raw array; was `android.net.Uri[]`
+    
 ArrayReturn: android.view.FocusFinder#sort(android.view.View[], int, int, android.view.ViewGroup, boolean) parameter #0:
     
 ArrayReturn: android.view.contentcapture.ViewNode#getAutofillOptions():
@@ -268,7 +268,7 @@
 ConcreteCollection: android.service.autofill.UserData#getFieldClassificationAlgorithms():
     
 ConcreteCollection: android.telephony.ims.ImsConferenceState#mParticipants:
-    Field type is concrete collection (`java.util.HashMap`); must be higher-level interface
+    
 
 
 ContextFirst: android.os.VibrationEffect#get(android.net.Uri, android.content.Context) parameter #1:
@@ -338,9 +338,9 @@
 ExecutorRegistration: android.permission.PermissionControllerManager#getAppPermissions(String, android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback, android.os.Handler):
     
 ExecutorRegistration: android.telephony.ims.stub.ImsCallSessionImplBase#setListener(android.telephony.ims.ImsCallSessionListener):
-    Registration methods should have overload that accepts delivery Executor: `setListener`
+    
 ExecutorRegistration: android.telephony.ims.stub.ImsUtImplBase#setListener(android.telephony.ims.ImsUtListener):
-    Registration methods should have overload that accepts delivery Executor: `setListener`
+    
 ExecutorRegistration: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener):
     
 ExecutorRegistration: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener):
@@ -399,6 +399,8 @@
     
 GetterSetterNames: android.location.GnssClock#setTimeUncertaintyNanos(double):
     
+GetterSetterNames: android.location.GnssMeasurement#setBasebandCn0DbHz(double):
+
 GetterSetterNames: android.location.GnssMeasurement#setCarrierFrequencyHz(float):
     
 GetterSetterNames: android.location.GnssMeasurement#setCodeType(String):
@@ -458,11 +460,13 @@
 
 
 InternalField: android.telephony.ims.ImsConferenceState#mParticipants:
-    Internal field mParticipants must not be exposed
+    
 
 
 KotlinOperator: android.os.WorkSource#get(int):
     
+KotlinOperator: android.util.SparseArrayMap#get(int, String):
+    Method can be invoked with an indexing operator from Kotlin: `get` (this is usually desirable; just make sure it makes sense for this type of object)
 
 
 ListenerInterface: android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener:
@@ -472,9 +476,9 @@
 ListenerInterface: android.os.IncidentManager.AuthListener:
     
 ListenerInterface: android.telephony.ims.ImsCallSessionListener:
-    Listeners should be an interface, or otherwise renamed Callback: ImsCallSessionListener
+    
 ListenerInterface: android.telephony.ims.ImsUtListener:
-    Listeners should be an interface, or otherwise renamed Callback: ImsUtListener
+    
 
 
 ListenerLast: android.hardware.camera2.CameraDevice#createCustomCaptureSession(android.hardware.camera2.params.InputConfiguration, java.util.List<android.hardware.camera2.params.OutputConfiguration>, int, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) parameter #4:
@@ -494,17 +498,17 @@
 
 
 ManagerLookup: android.telephony.ims.ImsMmTelManager#createForSubscriptionId(int):
-    Managers must always be obtained from Context (`createForSubscriptionId`)
+    
 ManagerLookup: android.telephony.ims.ProvisioningManager#createForSubscriptionId(int):
-    Managers must always be obtained from Context (`createForSubscriptionId`)
+    
 
 
 MethodNameTense: android.telephony.ims.feature.CapabilityChangeRequest#getCapabilitiesToEnable():
-    Unexpected tense; probably meant `enabled`, was `getCapabilitiesToEnable`
+    
 
 
 MethodNameUnits: android.telephony.ims.ImsCallForwardInfo#getTimeSeconds():
-    Returned time values must be in milliseconds, was `getTimeSeconds`
+    
 
 
 MinMaxConstant: android.os.UserHandle#MIN_SECONDARY_USER_ID:
@@ -1458,7 +1462,7 @@
 MissingNullability: android.telecom.PhoneAccountSuggestionService#onBind(android.content.Intent) parameter #0:
     
 MissingNullability: android.telephony.CallQuality#writeToParcel(android.os.Parcel, int) parameter #0:
-    Missing nullability on parameter `dest` in method `writeToParcel`
+    
 MissingNullability: android.telephony.DataSpecificRegistrationInfo#writeToParcel(android.os.Parcel, int) parameter #0:
     
 MissingNullability: android.telephony.LteVopsSupportInfo#writeToParcel(android.os.Parcel, int) parameter #0:
@@ -1476,9 +1480,9 @@
 MissingNullability: android.telephony.TelephonyManager#checkCarrierPrivilegesForPackage(String) parameter #0:
     
 MissingNullability: android.telephony.TelephonyManager#getCarrierPackageNamesForIntent(android.content.Intent):
-    Missing nullability on method `getCarrierPackageNamesForIntent` return
+    
 MissingNullability: android.telephony.TelephonyManager#getCarrierPackageNamesForIntent(android.content.Intent) parameter #0:
-    Missing nullability on parameter `intent` in method `getCarrierPackageNamesForIntent`
+    
 MissingNullability: android.telephony.TelephonyManager#getLine1AlphaTag():
     
 MissingNullability: android.telephony.TelephonyManager#getRadioHalVersion():
@@ -1516,315 +1520,315 @@
 MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #8:
     
 MissingNullability: android.telephony.ims.ImsCallForwardInfo#getNumber():
-    Missing nullability on method `getNumber` return
+    
 MissingNullability: android.telephony.ims.ImsCallForwardInfo#writeToParcel(android.os.Parcel, int) parameter #0:
-    Missing nullability on parameter `out` in method `writeToParcel`
+    
 MissingNullability: android.telephony.ims.ImsCallProfile#ImsCallProfile(int, int, android.os.Bundle, android.telephony.ims.ImsStreamMediaProfile) parameter #2:
-    Missing nullability on parameter `callExtras` in method `ImsCallProfile`
+    
 MissingNullability: android.telephony.ims.ImsCallProfile#ImsCallProfile(int, int, android.os.Bundle, android.telephony.ims.ImsStreamMediaProfile) parameter #3:
-    Missing nullability on parameter `mediaProfile` in method `ImsCallProfile`
+    
 MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtra(String):
-    Missing nullability on method `getCallExtra` return
+    
 MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtra(String) parameter #0:
-    Missing nullability on parameter `name` in method `getCallExtra`
+    
 MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtra(String, String):
-    Missing nullability on method `getCallExtra` return
+    
 MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtra(String, String) parameter #0:
-    Missing nullability on parameter `name` in method `getCallExtra`
+    
 MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtra(String, String) parameter #1:
-    Missing nullability on parameter `defaultValue` in method `getCallExtra`
+    
 MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtraBoolean(String) parameter #0:
-    Missing nullability on parameter `name` in method `getCallExtraBoolean`
+    
 MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtraBoolean(String, boolean) parameter #0:
-    Missing nullability on parameter `name` in method `getCallExtraBoolean`
+    
 MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtraInt(String) parameter #0:
-    Missing nullability on parameter `name` in method `getCallExtraInt`
+    
 MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtraInt(String, int) parameter #0:
-    Missing nullability on parameter `name` in method `getCallExtraInt`
+    
 MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtras():
-    Missing nullability on method `getCallExtras` return
+    
 MissingNullability: android.telephony.ims.ImsCallProfile#getMediaProfile():
-    Missing nullability on method `getMediaProfile` return
+    
 MissingNullability: android.telephony.ims.ImsCallProfile#getVideoStateFromImsCallProfile(android.telephony.ims.ImsCallProfile) parameter #0:
-    Missing nullability on parameter `callProfile` in method `getVideoStateFromImsCallProfile`
+    
 MissingNullability: android.telephony.ims.ImsCallProfile#setCallExtra(String, String) parameter #0:
-    Missing nullability on parameter `name` in method `setCallExtra`
+    
 MissingNullability: android.telephony.ims.ImsCallProfile#setCallExtra(String, String) parameter #1:
-    Missing nullability on parameter `value` in method `setCallExtra`
+    
 MissingNullability: android.telephony.ims.ImsCallProfile#setCallExtraBoolean(String, boolean) parameter #0:
-    Missing nullability on parameter `name` in method `setCallExtraBoolean`
+    
 MissingNullability: android.telephony.ims.ImsCallProfile#setCallExtraInt(String, int) parameter #0:
-    Missing nullability on parameter `name` in method `setCallExtraInt`
+    
 MissingNullability: android.telephony.ims.ImsCallProfile#updateCallExtras(android.telephony.ims.ImsCallProfile) parameter #0:
-    Missing nullability on parameter `profile` in method `updateCallExtras`
+    
 MissingNullability: android.telephony.ims.ImsCallProfile#updateCallType(android.telephony.ims.ImsCallProfile) parameter #0:
-    Missing nullability on parameter `profile` in method `updateCallType`
+    
 MissingNullability: android.telephony.ims.ImsCallProfile#updateMediaProfile(android.telephony.ims.ImsCallProfile) parameter #0:
-    Missing nullability on parameter `profile` in method `updateMediaProfile`
+    
 MissingNullability: android.telephony.ims.ImsCallProfile#writeToParcel(android.os.Parcel, int) parameter #0:
-    Missing nullability on parameter `out` in method `writeToParcel`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionConferenceExtendFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
-    Missing nullability on parameter `reasonInfo` in method `callSessionConferenceExtendFailed`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionConferenceExtendReceived(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile) parameter #0:
-    Missing nullability on parameter `newSession` in method `callSessionConferenceExtendReceived`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionConferenceExtendReceived(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile) parameter #1:
-    Missing nullability on parameter `profile` in method `callSessionConferenceExtendReceived`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionConferenceExtended(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile) parameter #0:
-    Missing nullability on parameter `newSession` in method `callSessionConferenceExtended`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionConferenceExtended(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile) parameter #1:
-    Missing nullability on parameter `profile` in method `callSessionConferenceExtended`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionConferenceStateUpdated(android.telephony.ims.ImsConferenceState) parameter #0:
-    Missing nullability on parameter `state` in method `callSessionConferenceStateUpdated`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionHandover(int, int, android.telephony.ims.ImsReasonInfo) parameter #2:
-    Missing nullability on parameter `reasonInfo` in method `callSessionHandover`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionHandoverFailed(int, int, android.telephony.ims.ImsReasonInfo) parameter #2:
-    Missing nullability on parameter `reasonInfo` in method `callSessionHandoverFailed`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionHeld(android.telephony.ims.ImsCallProfile) parameter #0:
-    Missing nullability on parameter `profile` in method `callSessionHeld`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionHoldFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
-    Missing nullability on parameter `reasonInfo` in method `callSessionHoldFailed`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionHoldReceived(android.telephony.ims.ImsCallProfile) parameter #0:
-    Missing nullability on parameter `profile` in method `callSessionHoldReceived`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionInitiated(android.telephony.ims.ImsCallProfile) parameter #0:
-    Missing nullability on parameter `profile` in method `callSessionInitiated`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionInitiatedFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
-    Missing nullability on parameter `reasonInfo` in method `callSessionInitiatedFailed`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionInviteParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
-    Missing nullability on parameter `reasonInfo` in method `callSessionInviteParticipantsRequestFailed`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionMergeComplete(android.telephony.ims.stub.ImsCallSessionImplBase) parameter #0:
-    Missing nullability on parameter `newSession` in method `callSessionMergeComplete`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionMergeFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
-    Missing nullability on parameter `reasonInfo` in method `callSessionMergeFailed`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionMergeStarted(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile) parameter #0:
-    Missing nullability on parameter `newSession` in method `callSessionMergeStarted`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionMergeStarted(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile) parameter #1:
-    Missing nullability on parameter `profile` in method `callSessionMergeStarted`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionProgressing(android.telephony.ims.ImsStreamMediaProfile) parameter #0:
-    Missing nullability on parameter `profile` in method `callSessionProgressing`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionRemoveParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
-    Missing nullability on parameter `reasonInfo` in method `callSessionRemoveParticipantsRequestFailed`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionResumeFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
-    Missing nullability on parameter `reasonInfo` in method `callSessionResumeFailed`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionResumeReceived(android.telephony.ims.ImsCallProfile) parameter #0:
-    Missing nullability on parameter `profile` in method `callSessionResumeReceived`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionResumed(android.telephony.ims.ImsCallProfile) parameter #0:
-    Missing nullability on parameter `profile` in method `callSessionResumed`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionRttMessageReceived(String) parameter #0:
-    Missing nullability on parameter `rttMessage` in method `callSessionRttMessageReceived`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionRttModifyRequestReceived(android.telephony.ims.ImsCallProfile) parameter #0:
-    Missing nullability on parameter `callProfile` in method `callSessionRttModifyRequestReceived`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionSuppServiceReceived(android.telephony.ims.ImsSuppServiceNotification) parameter #0:
-    Missing nullability on parameter `suppSrvNotification` in method `callSessionSuppServiceReceived`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionTerminated(android.telephony.ims.ImsReasonInfo) parameter #0:
-    Missing nullability on parameter `reasonInfo` in method `callSessionTerminated`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionUpdateFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
-    Missing nullability on parameter `reasonInfo` in method `callSessionUpdateFailed`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionUpdateReceived(android.telephony.ims.ImsCallProfile) parameter #0:
-    Missing nullability on parameter `profile` in method `callSessionUpdateReceived`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionUpdated(android.telephony.ims.ImsCallProfile) parameter #0:
-    Missing nullability on parameter `profile` in method `callSessionUpdated`
+    
 MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionUssdMessageReceived(int, String) parameter #1:
-    Missing nullability on parameter `ussdMessage` in method `callSessionUssdMessageReceived`
+    
 MissingNullability: android.telephony.ims.ImsConferenceState#getConnectionStateForStatus(String) parameter #0:
-    Missing nullability on parameter `status` in method `getConnectionStateForStatus`
+    
 MissingNullability: android.telephony.ims.ImsConferenceState#mParticipants:
-    Missing nullability on field `mParticipants` in class `class android.telephony.ims.ImsConferenceState`
+    
 MissingNullability: android.telephony.ims.ImsConferenceState#writeToParcel(android.os.Parcel, int) parameter #0:
-    Missing nullability on parameter `out` in method `writeToParcel`
+    
 MissingNullability: android.telephony.ims.ImsExternalCallState#writeToParcel(android.os.Parcel, int) parameter #0:
-    Missing nullability on parameter `out` in method `writeToParcel`
+    
 MissingNullability: android.telephony.ims.ImsReasonInfo#ImsReasonInfo(int, int, String) parameter #2:
-    Missing nullability on parameter `extraMessage` in method `ImsReasonInfo`
+    
 MissingNullability: android.telephony.ims.ImsReasonInfo#getExtraMessage():
-    Missing nullability on method `getExtraMessage` return
+    
 MissingNullability: android.telephony.ims.ImsReasonInfo#writeToParcel(android.os.Parcel, int) parameter #0:
-    Missing nullability on parameter `out` in method `writeToParcel`
+    
 MissingNullability: android.telephony.ims.ImsService#createMmTelFeature(int):
-    Missing nullability on method `createMmTelFeature` return
+    
 MissingNullability: android.telephony.ims.ImsService#createRcsFeature(int):
-    Missing nullability on method `createRcsFeature` return
+    
 MissingNullability: android.telephony.ims.ImsService#getConfig(int):
-    Missing nullability on method `getConfig` return
+    
 MissingNullability: android.telephony.ims.ImsService#getRegistration(int):
-    Missing nullability on method `getRegistration` return
+    
 MissingNullability: android.telephony.ims.ImsService#onUpdateSupportedImsFeatures(android.telephony.ims.stub.ImsFeatureConfiguration) parameter #0:
-    Missing nullability on parameter `c` in method `onUpdateSupportedImsFeatures`
+    
 MissingNullability: android.telephony.ims.ImsService#querySupportedImsFeatures():
-    Missing nullability on method `querySupportedImsFeatures` return
+    
 MissingNullability: android.telephony.ims.ImsSsData#writeToParcel(android.os.Parcel, int) parameter #0:
-    Missing nullability on parameter `out` in method `writeToParcel`
+    
 MissingNullability: android.telephony.ims.ImsSsInfo#writeToParcel(android.os.Parcel, int) parameter #0:
-    Missing nullability on parameter `out` in method `writeToParcel`
+    
 MissingNullability: android.telephony.ims.ImsStreamMediaProfile#copyFrom(android.telephony.ims.ImsStreamMediaProfile) parameter #0:
-    Missing nullability on parameter `profile` in method `copyFrom`
+    
 MissingNullability: android.telephony.ims.ImsStreamMediaProfile#writeToParcel(android.os.Parcel, int) parameter #0:
-    Missing nullability on parameter `out` in method `writeToParcel`
+    
 MissingNullability: android.telephony.ims.ImsSuppServiceNotification#ImsSuppServiceNotification(int, int, int, int, String, String[]) parameter #4:
-    Missing nullability on parameter `number` in method `ImsSuppServiceNotification`
+    
 MissingNullability: android.telephony.ims.ImsSuppServiceNotification#ImsSuppServiceNotification(int, int, int, int, String, String[]) parameter #5:
-    Missing nullability on parameter `history` in method `ImsSuppServiceNotification`
+    
 MissingNullability: android.telephony.ims.ImsSuppServiceNotification#history:
-    Missing nullability on field `history` in class `class android.telephony.ims.ImsSuppServiceNotification`
+    
 MissingNullability: android.telephony.ims.ImsSuppServiceNotification#number:
-    Missing nullability on field `number` in class `class android.telephony.ims.ImsSuppServiceNotification`
+    
 MissingNullability: android.telephony.ims.ImsSuppServiceNotification#writeToParcel(android.os.Parcel, int) parameter #0:
-    Missing nullability on parameter `out` in method `writeToParcel`
+    
 MissingNullability: android.telephony.ims.ImsUtListener#onSupplementaryServiceIndication(android.telephony.ims.ImsSsData) parameter #0:
-    Missing nullability on parameter `ssData` in method `onSupplementaryServiceIndication`
+    
 MissingNullability: android.telephony.ims.ImsUtListener#onUtConfigurationCallBarringQueried(int, android.telephony.ims.ImsSsInfo[]) parameter #1:
-    Missing nullability on parameter `cbInfo` in method `onUtConfigurationCallBarringQueried`
+    
 MissingNullability: android.telephony.ims.ImsUtListener#onUtConfigurationCallForwardQueried(int, android.telephony.ims.ImsCallForwardInfo[]) parameter #1:
-    Missing nullability on parameter `cfInfo` in method `onUtConfigurationCallForwardQueried`
+    
 MissingNullability: android.telephony.ims.ImsUtListener#onUtConfigurationCallWaitingQueried(int, android.telephony.ims.ImsSsInfo[]) parameter #1:
-    Missing nullability on parameter `cwInfo` in method `onUtConfigurationCallWaitingQueried`
+    
 MissingNullability: android.telephony.ims.ImsUtListener#onUtConfigurationQueried(int, android.os.Bundle) parameter #1:
-    Missing nullability on parameter `configuration` in method `onUtConfigurationQueried`
+    
 MissingNullability: android.telephony.ims.ImsUtListener#onUtConfigurationQueryFailed(int, android.telephony.ims.ImsReasonInfo) parameter #1:
-    Missing nullability on parameter `error` in method `onUtConfigurationQueryFailed`
+    
 MissingNullability: android.telephony.ims.ImsUtListener#onUtConfigurationUpdateFailed(int, android.telephony.ims.ImsReasonInfo) parameter #1:
-    Missing nullability on parameter `error` in method `onUtConfigurationUpdateFailed`
+    
 MissingNullability: android.telephony.ims.ImsVideoCallProvider#changeCameraCapabilities(android.telecom.VideoProfile.CameraCapabilities) parameter #0:
-    Missing nullability on parameter `CameraCapabilities` in method `changeCameraCapabilities`
+    
 MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSendSessionModifyRequest(android.telecom.VideoProfile, android.telecom.VideoProfile) parameter #0:
-    Missing nullability on parameter `fromProfile` in method `onSendSessionModifyRequest`
+    
 MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSendSessionModifyRequest(android.telecom.VideoProfile, android.telecom.VideoProfile) parameter #1:
-    Missing nullability on parameter `toProfile` in method `onSendSessionModifyRequest`
+    
 MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSendSessionModifyResponse(android.telecom.VideoProfile) parameter #0:
-    Missing nullability on parameter `responseProfile` in method `onSendSessionModifyResponse`
+    
 MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSetCamera(String) parameter #0:
-    Missing nullability on parameter `cameraId` in method `onSetCamera`
+    
 MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSetCamera(String, int) parameter #0:
-    Missing nullability on parameter `cameraId` in method `onSetCamera`
+    
 MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSetDisplaySurface(android.view.Surface) parameter #0:
-    Missing nullability on parameter `surface` in method `onSetDisplaySurface`
+    
 MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSetPauseImage(android.net.Uri) parameter #0:
-    Missing nullability on parameter `uri` in method `onSetPauseImage`
+    
 MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSetPreviewSurface(android.view.Surface) parameter #0:
-    Missing nullability on parameter `surface` in method `onSetPreviewSurface`
+    
 MissingNullability: android.telephony.ims.ImsVideoCallProvider#receiveSessionModifyRequest(android.telecom.VideoProfile) parameter #0:
-    Missing nullability on parameter `VideoProfile` in method `receiveSessionModifyRequest`
+    
 MissingNullability: android.telephony.ims.ImsVideoCallProvider#receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile) parameter #1:
-    Missing nullability on parameter `requestedProfile` in method `receiveSessionModifyResponse`
+    
 MissingNullability: android.telephony.ims.ImsVideoCallProvider#receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile) parameter #2:
-    Missing nullability on parameter `responseProfile` in method `receiveSessionModifyResponse`
+    
 MissingNullability: android.telephony.ims.feature.CapabilityChangeRequest#getCapabilitiesToDisable():
-    Missing nullability on method `getCapabilitiesToDisable` return
+    
 MissingNullability: android.telephony.ims.feature.CapabilityChangeRequest#getCapabilitiesToEnable():
-    Missing nullability on method `getCapabilitiesToEnable` return
+    
 MissingNullability: android.telephony.ims.feature.CapabilityChangeRequest#writeToParcel(android.os.Parcel, int) parameter #0:
-    Missing nullability on parameter `dest` in method `writeToParcel`
+    
 MissingNullability: android.telephony.ims.feature.ImsFeature#changeEnabledCapabilities(android.telephony.ims.feature.CapabilityChangeRequest, android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy) parameter #0:
-    Missing nullability on parameter `request` in method `changeEnabledCapabilities`
+    
 MissingNullability: android.telephony.ims.feature.ImsFeature#changeEnabledCapabilities(android.telephony.ims.feature.CapabilityChangeRequest, android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy) parameter #1:
-    Missing nullability on parameter `c` in method `changeEnabledCapabilities`
+    
 MissingNullability: android.telephony.ims.feature.MmTelFeature#queryCapabilityStatus():
-    Missing nullability on method `queryCapabilityStatus` return
+    
 MissingNullability: android.telephony.ims.feature.MmTelFeature.MmTelCapabilities#MmTelCapabilities(android.telephony.ims.feature.ImsFeature.Capabilities) parameter #0:
-    Missing nullability on parameter `c` in method `MmTelCapabilities`
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#accept(int, android.telephony.ims.ImsStreamMediaProfile) parameter #1:
-    Missing nullability on parameter `profile` in method `accept`
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#deflect(String) parameter #0:
-    Missing nullability on parameter `deflectNumber` in method `deflect`
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#extendToConference(String[]) parameter #0:
-    Missing nullability on parameter `participants` in method `extendToConference`
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#getCallId():
-    Missing nullability on method `getCallId` return
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#getCallProfile():
-    Missing nullability on method `getCallProfile` return
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#getImsVideoCallProvider():
-    Missing nullability on method `getImsVideoCallProvider` return
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#getLocalCallProfile():
-    Missing nullability on method `getLocalCallProfile` return
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#getProperty(String):
-    Missing nullability on method `getProperty` return
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#getProperty(String) parameter #0:
-    Missing nullability on parameter `name` in method `getProperty`
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#getRemoteCallProfile():
-    Missing nullability on method `getRemoteCallProfile` return
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#hold(android.telephony.ims.ImsStreamMediaProfile) parameter #0:
-    Missing nullability on parameter `profile` in method `hold`
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#inviteParticipants(String[]) parameter #0:
-    Missing nullability on parameter `participants` in method `inviteParticipants`
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#removeParticipants(String[]) parameter #0:
-    Missing nullability on parameter `participants` in method `removeParticipants`
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#resume(android.telephony.ims.ImsStreamMediaProfile) parameter #0:
-    Missing nullability on parameter `profile` in method `resume`
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#sendDtmf(char, android.os.Message) parameter #1:
-    Missing nullability on parameter `result` in method `sendDtmf`
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#sendRttMessage(String) parameter #0:
-    Missing nullability on parameter `rttMessage` in method `sendRttMessage`
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#sendRttModifyRequest(android.telephony.ims.ImsCallProfile) parameter #0:
-    Missing nullability on parameter `toProfile` in method `sendRttModifyRequest`
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#sendUssd(String) parameter #0:
-    Missing nullability on parameter `ussdMessage` in method `sendUssd`
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#setListener(android.telephony.ims.ImsCallSessionListener) parameter #0:
-    Missing nullability on parameter `listener` in method `setListener`
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#start(String, android.telephony.ims.ImsCallProfile) parameter #0:
-    Missing nullability on parameter `callee` in method `start`
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#start(String, android.telephony.ims.ImsCallProfile) parameter #1:
-    Missing nullability on parameter `profile` in method `start`
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#startConference(String[], android.telephony.ims.ImsCallProfile) parameter #0:
-    Missing nullability on parameter `participants` in method `startConference`
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#startConference(String[], android.telephony.ims.ImsCallProfile) parameter #1:
-    Missing nullability on parameter `profile` in method `startConference`
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#update(int, android.telephony.ims.ImsStreamMediaProfile) parameter #1:
-    Missing nullability on parameter `profile` in method `update`
+    
 MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase.State#toString(int):
-    Missing nullability on method `toString` return
+    
 MissingNullability: android.telephony.ims.stub.ImsConfigImplBase#getConfigString(int):
-    Missing nullability on method `getConfigString` return
+    
 MissingNullability: android.telephony.ims.stub.ImsConfigImplBase#notifyProvisionedValueChanged(int, String) parameter #1:
-    Missing nullability on parameter `value` in method `notifyProvisionedValueChanged`
+    
 MissingNullability: android.telephony.ims.stub.ImsConfigImplBase#setConfig(int, String) parameter #1:
-    Missing nullability on parameter `value` in method `setConfig`
+    
 MissingNullability: android.telephony.ims.stub.ImsFeatureConfiguration#getServiceFeatures():
-    Missing nullability on method `getServiceFeatures` return
+    
 MissingNullability: android.telephony.ims.stub.ImsFeatureConfiguration#writeToParcel(android.os.Parcel, int) parameter #0:
-    Missing nullability on parameter `dest` in method `writeToParcel`
+    
 MissingNullability: android.telephony.ims.stub.ImsFeatureConfiguration.Builder#addFeature(int, int):
-    Missing nullability on method `addFeature` return
+    
 MissingNullability: android.telephony.ims.stub.ImsFeatureConfiguration.Builder#build():
-    Missing nullability on method `build` return
+    
 MissingNullability: android.telephony.ims.stub.ImsMultiEndpointImplBase#onImsExternalCallStateUpdate(java.util.List<android.telephony.ims.ImsExternalCallState>) parameter #0:
-    Missing nullability on parameter `externalCallDialogs` in method `onImsExternalCallStateUpdate`
+    
 MissingNullability: android.telephony.ims.stub.ImsRegistrationImplBase#onDeregistered(android.telephony.ims.ImsReasonInfo) parameter #0:
-    Missing nullability on parameter `info` in method `onDeregistered`
+    
 MissingNullability: android.telephony.ims.stub.ImsRegistrationImplBase#onSubscriberAssociatedUriChanged(android.net.Uri[]) parameter #0:
-    Missing nullability on parameter `uris` in method `onSubscriberAssociatedUriChanged`
+    
 MissingNullability: android.telephony.ims.stub.ImsRegistrationImplBase#onTechnologyChangeFailed(int, android.telephony.ims.ImsReasonInfo) parameter #1:
-    Missing nullability on parameter `info` in method `onTechnologyChangeFailed`
+    
 MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#getSmsFormat():
-    Missing nullability on method `getSmsFormat` return
+    
 MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#onSmsReceived(int, String, byte[]) parameter #1:
-    Missing nullability on parameter `format` in method `onSmsReceived`
+    
 MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#onSmsReceived(int, String, byte[]) parameter #2:
-    Missing nullability on parameter `pdu` in method `onSmsReceived`
+    
 MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#onSmsStatusReportReceived(int, String, byte[]) parameter #1:
-    Missing nullability on parameter `format` in method `onSmsStatusReportReceived`
+    
 MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#onSmsStatusReportReceived(int, String, byte[]) parameter #2:
-    Missing nullability on parameter `pdu` in method `onSmsStatusReportReceived`
+    
 MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#onSmsStatusReportReceived(int, int, String, byte[]) parameter #2:
-    Missing nullability on parameter `format` in method `onSmsStatusReportReceived`
+    
 MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#onSmsStatusReportReceived(int, int, String, byte[]) parameter #3:
-    Missing nullability on parameter `pdu` in method `onSmsStatusReportReceived`
+    
 MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#sendSms(int, int, String, String, boolean, byte[]) parameter #2:
-    Missing nullability on parameter `format` in method `sendSms`
+    
 MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#sendSms(int, int, String, String, boolean, byte[]) parameter #3:
-    Missing nullability on parameter `smsc` in method `sendSms`
+    
 MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#sendSms(int, int, String, String, boolean, byte[]) parameter #5:
-    Missing nullability on parameter `pdu` in method `sendSms`
+    
 MissingNullability: android.telephony.ims.stub.ImsUtImplBase#queryCallForward(int, String) parameter #1:
-    Missing nullability on parameter `number` in method `queryCallForward`
+    
 MissingNullability: android.telephony.ims.stub.ImsUtImplBase#setListener(android.telephony.ims.ImsUtListener) parameter #0:
-    Missing nullability on parameter `listener` in method `setListener`
+    
 MissingNullability: android.telephony.ims.stub.ImsUtImplBase#transact(android.os.Bundle) parameter #0:
-    Missing nullability on parameter `ssInfo` in method `transact`
+    
 MissingNullability: android.telephony.ims.stub.ImsUtImplBase#updateCallBarring(int, int, String[]) parameter #2:
-    Missing nullability on parameter `barrList` in method `updateCallBarring`
+    
 MissingNullability: android.telephony.ims.stub.ImsUtImplBase#updateCallBarringForServiceClass(int, int, String[], int) parameter #2:
-    Missing nullability on parameter `barrList` in method `updateCallBarringForServiceClass`
+    
 MissingNullability: android.telephony.ims.stub.ImsUtImplBase#updateCallForward(int, int, String, int, int) parameter #2:
-    Missing nullability on parameter `number` in method `updateCallForward`
+    
 MissingNullability: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String):
     
 MissingNullability: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String) parameter #0:
@@ -2276,7 +2280,7 @@
 NotCloseable: android.os.HwParcel:
     
 NotCloseable: android.telephony.ims.stub.ImsUtImplBase:
-    Classes that release resources (close()) should implement AutoClosable and CloseGuard: class android.telephony.ims.stub.ImsUtImplBase
+    
 
 
 OnNameExpected: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.PrintWriter, String[]):
@@ -2290,21 +2294,21 @@
 OnNameExpected: android.service.quicksettings.TileService#isQuickSettingsSupported():
     
 OnNameExpected: android.telephony.ims.ImsService#createMmTelFeature(int):
-    If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+    
 OnNameExpected: android.telephony.ims.ImsService#createRcsFeature(int):
-    If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+    
 OnNameExpected: android.telephony.ims.ImsService#disableIms(int):
-    If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+    
 OnNameExpected: android.telephony.ims.ImsService#enableIms(int):
-    If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+    
 OnNameExpected: android.telephony.ims.ImsService#getConfig(int):
-    If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+    
 OnNameExpected: android.telephony.ims.ImsService#getRegistration(int):
-    If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+    
 OnNameExpected: android.telephony.ims.ImsService#querySupportedImsFeatures():
-    If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+    
 OnNameExpected: android.telephony.ims.ImsService#readyForFeatureCreation():
-    If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+    
 OnNameExpected: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#dispose(int):
     
 OnNameExpected: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int):
@@ -2422,6 +2426,12 @@
 ProtectedMember: android.view.ViewGroup#resetResolvedDrawables():
     
 
+PublicTypedef: android.os.HwParcel.Status: Don't expose @IntDef: @Status must be hidden.
+
+PublicTypedef: android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability: Don't expose @IntDef: @MmTelCapability must be hidden.
+
+PublicTypedef: android.telephony.ims.feature.MmTelFeature.ProcessCallResult: Don't expose @IntDef: @ProcessCallResult must be hidden.
+
 
 RawAidl: android.telephony.mbms.vendor.MbmsDownloadServiceBase:
     
@@ -2444,7 +2454,7 @@
 RethrowRemoteException: android.os.IHwBinder#transact(int, android.os.HwParcel, android.os.HwParcel, int):
     
 RethrowRemoteException: android.telephony.ims.ImsService#onUpdateSupportedImsFeatures(android.telephony.ims.stub.ImsFeatureConfiguration):
-    Methods calling system APIs should rethrow `RemoteException` as `RuntimeException` (but do not list it in the throws clause)
+    
 RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener):
     
 RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener):
@@ -2524,7 +2534,7 @@
 SamShouldBeLast: android.service.autofill.InternalTransformation#batchApply(android.service.autofill.ValueFinder, android.widget.RemoteViews, java.util.ArrayList<android.util.Pair<java.lang.Integer,android.service.autofill.InternalTransformation>>):
     
 SamShouldBeLast: android.telephony.ims.ImsMmTelManager#getFeatureState(java.util.function.Consumer<java.lang.Integer>, java.util.concurrent.Executor):
-    SAM-compatible parameters (such as parameter 1, "callback", in android.telephony.ims.ImsMmTelManager.getFeatureState) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+    
 SamShouldBeLast: android.view.Choreographer#postCallback(int, Runnable, Object):
     
 SamShouldBeLast: android.view.Choreographer#postCallbackDelayed(int, Runnable, Object, long):
@@ -2597,6 +2607,8 @@
     
 UserHandle: android.app.role.RoleManager#removeRoleHolderAsUser(String, String, int, android.os.UserHandle, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Boolean>):
     
+UserHandle: android.companion.CompanionDeviceManager#isDeviceAssociated(String, android.net.MacAddress, android.os.UserHandle):
+    When a method overload is needed to target a specific UserHandle, callers should be directed to use Context.createPackageContextAsUser() and re-obtain the relevant Manager, and no new API should be added
 UserHandle: android.content.pm.PackageManager#getInstallReason(String, android.os.UserHandle):
     
 UserHandle: android.content.pm.PackageManager#getPermissionFlags(String, String, android.os.UserHandle):
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 22e1d01..bdb8380 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -175,7 +175,11 @@
             } else if (opt.equals("--no-hidden-api-checks")) {
                 instrument.disableHiddenApiChecks = true;
             } else if (opt.equals("--no-test-api-checks")) {
-                instrument.disableTestApiChecks = true;
+                // TODO(satayev): remove this option, only kept for backwards compatibility with
+                // cached tradefed instance
+                instrument.disableTestApiChecks = false;
+            } else if (opt.equals("--no-test-api-access")) {
+                instrument.disableTestApiChecks = false;
             } else if (opt.equals("--no-isolated-storage")) {
                 instrument.disableIsolatedStorage = true;
             } else if (opt.equals("--user")) {
diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java
index 6afd7c4..2adbc1f 100644
--- a/cmds/am/src/com/android/commands/am/Instrument.java
+++ b/cmds/am/src/com/android/commands/am/Instrument.java
@@ -86,7 +86,7 @@
     String logPath = null;
     public boolean noWindowAnimation = false;
     public boolean disableHiddenApiChecks = false;
-    public boolean disableTestApiChecks = false;
+    public boolean disableTestApiChecks = true;
     public boolean disableIsolatedStorage = false;
     public String abi = null;
     public int userId = UserHandle.USER_CURRENT;
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index e1cb7ca..459520a 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -1157,10 +1157,10 @@
 
     parseAnimationDesc(*animation);
     if (!preloadZip(*animation)) {
+        releaseAnimation(animation);
         return nullptr;
     }
 
-
     mLoadedFiles.remove(fn);
     return animation;
 }
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 1fd3abf..3c5ad42 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1275,7 +1275,7 @@
     // Permission check not necessary as it's meant for applications to write to
     // statsd.
     android::util::stats_write(util::APP_BREADCRUMB_REPORTED,
-                               IPCThreadState::self()->getCallingUid(), label,
+                               (int32_t) IPCThreadState::self()->getCallingUid(), label,
                                state);
     return Status::ok();
 }
@@ -1295,7 +1295,18 @@
                                     const sp<android::os::IPullAtomCallback>& pullerCallback) {
     ENFORCE_UID(AID_SYSTEM);
 
-    VLOG("StatsService::registerPuller called.");
+    VLOG("StatsService::registerPullAtomCallback called.");
+    mPullerManager->RegisterPullAtomCallback(uid, atomTag, coolDownNs, timeoutNs, additiveFields,
+                                             pullerCallback);
+    return Status::ok();
+}
+
+Status StatsService::registerNativePullAtomCallback(int32_t atomTag, int64_t coolDownNs,
+                                    int64_t timeoutNs, const std::vector<int32_t>& additiveFields,
+                                    const sp<android::os::IPullAtomCallback>& pullerCallback) {
+
+    VLOG("StatsService::registerNativePullAtomCallback called.");
+    int32_t uid = IPCThreadState::self()->getCallingUid();
     mPullerManager->RegisterPullAtomCallback(uid, atomTag, coolDownNs, timeoutNs, additiveFields,
                                              pullerCallback);
     return Status::ok();
@@ -1406,7 +1417,10 @@
 
 Status StatsService::sendWatchdogRollbackOccurredAtom(const int32_t rollbackTypeIn,
                                                       const android::String16& packageNameIn,
-                                                      const int64_t packageVersionCodeIn) {
+                                                      const int64_t packageVersionCodeIn,
+                                                      const int32_t rollbackReasonIn,
+                                                      const android::String16&
+                                                       failingPackageNameIn) {
     // Note: We skip the usage stats op check here since we do not have a package name.
     // This is ok since we are overloading the usage_stats permission.
     // This method only sends data, it does not receive it.
@@ -1428,7 +1442,8 @@
     }
 
     android::util::stats_write(android::util::WATCHDOG_ROLLBACK_OCCURRED,
-            rollbackTypeIn, String8(packageNameIn).string(), packageVersionCodeIn);
+            rollbackTypeIn, String8(packageNameIn).string(), packageVersionCodeIn,
+            rollbackReasonIn, String8(failingPackageNameIn).string());
 
     // Fast return to save disk read.
     if (rollbackTypeIn != android::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 6d40007..50b1014 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -187,6 +187,13 @@
             const sp<android::os::IPullAtomCallback>& pullerCallback) override;
 
     /**
+     * Binder call to register a callback function for a pulled atom.
+     */
+    virtual Status registerNativePullAtomCallback(int32_t atomTag, int64_t coolDownNs,
+            int64_t timeoutNs, const std::vector<int32_t>& additiveFields,
+            const sp<android::os::IPullAtomCallback>& pullerCallback) override;
+
+    /**
      * Binder call to unregister any existing callback function for a vendor pulled atom.
      */
     virtual Status unregisterPullerCallback(int32_t atomTag, const String16& packageName) override;
@@ -207,7 +214,9 @@
     virtual Status sendWatchdogRollbackOccurredAtom(
             const int32_t rollbackTypeIn,
             const android::String16& packageNameIn,
-            const int64_t packageVersionCodeIn) override;
+            const int64_t packageVersionCodeIn,
+            const int32_t rollbackReasonIn,
+            const android::String16& failingPackageNameIn) override;
 
     /**
      * Binder call to get registered experiment IDs.
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 49cc3c4..77ff707 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -50,6 +50,7 @@
 import "frameworks/base/core/proto/android/stats/launcher/launcher.proto";
 import "frameworks/base/core/proto/android/stats/location/location_enums.proto";
 import "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.proto";
+import "frameworks/base/core/proto/android/stats/mediaprovider/mediaprovider_enums.proto";
 import "frameworks/base/core/proto/android/stats/storage/storage_enums.proto";
 import "frameworks/base/core/proto/android/stats/style/style_enums.proto";
 import "frameworks/base/core/proto/android/telecomm/enums.proto";
@@ -111,7 +112,7 @@
         TouchEventReported touch_event_reported = 34;
         WakeupAlarmOccurred wakeup_alarm_occurred = 35;
         KernelWakeupReported kernel_wakeup_reported = 36;
-        WifiLockStateChanged wifi_lock_state_changed = 37;
+        WifiLockStateChanged wifi_lock_state_changed = 37 [(log_from_module) = "wifi"];
         WifiSignalStrengthChanged wifi_signal_strength_changed = 38;
         WifiScanStateChanged wifi_scan_state_changed = 39;
         PhoneSignalStrengthChanged phone_signal_strength_changed = 40;
@@ -342,10 +343,20 @@
         VmsClientConnectionStateChanged vms_client_connection_state_changed = 230;
         GpsLocationStatusReported gps_location_status_reported = 231;
         GpsTimeToFirstFixReported gps_time_to_first_fix_reported = 232;
+        MediaProviderScanEvent media_provider_scan_event =
+            233 [(log_from_module) = "mediaprovider"];
+        MediaProviderDeletionEvent media_provider_deletion_event =
+            234 [(log_from_module) = "mediaprovider"];
+        MediaProviderPermissionEvent media_provider_permission_event =
+            235 [(log_from_module) = "mediaprovider"];
+        MediaProviderSchemaChange media_provider_schema_change =
+            236 [(log_from_module) = "mediaprovider"];
+        MediaProviderIdleMaintenance media_provider_idle_maintenance =
+            237 [(log_from_module) = "mediaprovider"];
     }
 
     // Pulled events will start at field 10000.
-    // Next: 10065
+    // Next: 10067
     oneof pulled {
         WifiBytesTransfer wifi_bytes_transfer = 10000;
         WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001;
@@ -412,6 +423,7 @@
         SurfaceflingerStatsLayerInfo surfaceflinger_stats_layer_info = 10063;
         ProcessMemorySnapshot process_memory_snapshot = 10064;
         VmsClientStats vms_client_stats = 10065;
+        NotificationRemoteViews notification_remote_views = 10066;
     }
 
     // DO NOT USE field numbers above 100,000 in AOSP.
@@ -1731,6 +1743,19 @@
     optional string package_name = 2;
 
     optional int32 package_version_code = 3;
+
+    enum RollbackReasonType {
+        REASON_UNKNOWN = 0;
+        REASON_NATIVE_CRASH = 1;
+        REASON_EXPLICIT_HEALTH_CHECK = 2;
+        REASON_APP_CRASH = 3;
+        REASON_APP_NOT_RESPONDING = 4;
+    }
+    optional RollbackReasonType rollback_reason = 4;
+
+    // Set by RollbackPackageHealthObserver to be the package that is failing when a rollback
+    // is initiated. Empty if the package is unknown.
+    optional string failing_package_name = 5;
 }
 
 /**
@@ -3799,6 +3824,124 @@
     optional State state  = 2;
 }
 
+/**
+ * Logs when MediaProvider has successfully finished scanning a storage volume.
+ *
+ * Logged from:
+ *   packages/providers/MediaProvider/src/com/android/providers/media/scan/ModernMediaScanner.java
+ */
+message MediaProviderScanEvent {
+    enum Reason {
+        // Scan triggered due to unknown reason
+        UNKNOWN = 0;
+        // Scan triggered due to storage volume being mounted
+        MOUNTED = 1;
+        // Scan triggered due to explicit user action or app request
+        DEMAND = 2;
+        // Scan triggered due to idle maintenance
+        IDLE = 3;
+    }
+
+    // Volume type that this event pertains to
+    optional android.stats.mediaprovider.VolumeType volume_type = 1;
+    // Reason why this scan was triggered
+    optional Reason reason = 2;
+    // Total number of files scanned
+    optional int64 item_count = 3;
+    // Duration of scan, normalized per file
+    optional float normalized_duration_millis = 4;
+    // Number of database inserts, normalized per file
+    optional float normalized_insert_count = 5;
+    // Number of database updates, normalized per file
+    optional float normalized_update_count = 6;
+    // Number of database deletes, normalized per file
+    optional float normalized_delete_count = 7;
+}
+
+/**
+ * Logs when an app has asked MediaProvider to delete media belonging to the user.
+ *
+ * Logged from:
+ *   packages/providers/MediaProvider/src/com/android/providers/media/MediaProvider.java
+ */
+message MediaProviderDeletionEvent {
+    // Volume type that this event pertains to
+    optional android.stats.mediaprovider.VolumeType volume_type = 1;
+    // Device timestamp when this deletion event occurred
+    optional int64 timestamp_millis = 2;
+    // App that requested deletion
+    optional string package_name = 3;
+    // Number of items that were deleted
+    optional int32 item_count = 4;
+}
+
+/**
+ * Logs when an app has asked MediaProvider to grant them access to media belonging to the user.
+ *
+ * Logged from:
+ *   packages/providers/MediaProvider/src/com/android/providers/media/PermissionActivity.java
+ */
+message MediaProviderPermissionEvent {
+    enum Result {
+        UNKNOWN = 0;
+        USER_GRANTED = 1;
+        AUTO_GRANTED = 2;
+        USER_DENIED = 3;
+        USER_DENIED_WITH_PREJUDICE = 4;
+        AUTO_DENIED = 5;
+    }
+
+    // Volume type that this event pertains to
+    optional android.stats.mediaprovider.VolumeType volume_type = 1;
+    // Device timestamp when this permission event occurred
+    optional int64 timestamp_millis = 2;
+    // App that requested permission
+    optional string package_name = 3;
+    // Number of items that were requested
+    optional int32 item_count = 4;
+    // Result of this request
+    optional Result result = 5;
+}
+
+/**
+ * Logs when MediaProvider has finished upgrading or downgrading its database schema.
+ *
+ * Logged from:
+ *   packages/providers/MediaProvider/src/com/android/providers/media/DatabaseHelper.java
+ */
+message MediaProviderSchemaChange {
+    // Volume type that this event pertains to
+    optional android.stats.mediaprovider.VolumeType volume_type = 1;
+    // Old database version code
+    optional int32 version_from = 2;
+    // New database version code
+    optional int32 version_to = 3;
+    // Total number of files in database
+    optional int64 item_count = 4;
+    // Duration of schema change, normalized per file
+    optional float normalized_duration_millis = 5;
+}
+
+/**
+ * Logs when MediaProvider has finished an idle maintenance job.
+ *
+ * Logged from:
+ *   packages/providers/MediaProvider/src/com/android/providers/media/MediaProvider.java
+ */
+message MediaProviderIdleMaintenance {
+    // Volume type that this event pertains to
+    optional android.stats.mediaprovider.VolumeType volume_type = 1;
+
+    // Total number of files in database
+    optional int64 item_count = 2;
+    // Duration of idle maintenance, normalized per file
+    optional float normalized_duration_millis = 3;
+    // Number of thumbnails found to be stale, normalized per file
+    optional float normalized_stale_thumbnails = 4;
+    // Number of items found to be expired, normalized per file
+    optional float normalized_expired_media = 5;
+}
+
 //////////////////////////////////////////////////////////////////////
 // Pulled atoms below this line //
 //////////////////////////////////////////////////////////////////////
@@ -4818,6 +4961,24 @@
     optional ProcessStatsSectionProto proc_stats_section = 1;
 }
 
+// Next Tag: 2
+message PackageRemoteViewInfoProto {
+    optional string package_name = 1;
+    // add per-package additional info here (like channels)
+}
+
+// Next Tag: 2
+message NotificationRemoteViewsProto {
+    repeated PackageRemoteViewInfoProto package_remote_view_info = 1;
+}
+
+/**
+ * Pulled from NotificationManagerService.java
+ */
+message NotificationRemoteViews {
+    optional NotificationRemoteViewsProto notification_remote_views = 1;
+}
+
 message PowerProfileProto {
     optional double cpu_suspend = 1;
 
@@ -5798,10 +5959,10 @@
     optional int64 request_id = 1;
 
     // UID of package requesting the permission grant
-    optional int32 requesting_uid = 2 [(is_uid) = true];
+    optional int32 uid = 2 [(is_uid) = true];
 
     // Name of package requesting the permission grant
-    optional string requesting_package_name = 3;
+    optional string package_name = 3;
 
     // The permission to be granted
     optional string permission_name = 4;
@@ -5831,6 +5992,8 @@
         IGNORED_RESTRICTED_PERMISSION = 9;
         // one time permission was granted by user action
         USER_GRANTED_ONE_TIME = 10;
+        // user ignored request by leaving the request screen without choosing any option
+        USER_IGNORED = 11;
     }
     // The result of the permission grant
     optional Result result = 6;
@@ -6362,7 +6525,8 @@
     optional bool is_preinstalled = 3;
 
     // True if the package is privileged.
-    optional bool is_priv_app = 4;
+    // Starting from Android 11, this boolean is not set and will always be false.
+    optional bool is_priv_app = 4 [deprecated = true];
 }
 
 /**
@@ -6716,6 +6880,9 @@
     // For long-running operations, total duration of the operation
     // while the app was in the background (only for trusted requests)
     optional int64 trusted_background_duration_millis = 9;
+
+    // Whether AppOps is guarded by Runtime permission
+    optional bool is_runtime_permission = 10;
 }
 
 /**
@@ -6974,7 +7141,7 @@
     // Event type of this event.
     optional android.stats.textclassifier.EventType event_type = 2;
 
-    // Name of the model that is involved in this event.
+    // Name of the annotator model that is involved in this event.
     optional string model_name = 3;
 
     // Type of widget that was involved in triggering this event.
@@ -7014,7 +7181,7 @@
     // Event type of this event.
     optional android.stats.textclassifier.EventType event_type = 2;
 
-    // Name of the model that is involved in this event.
+    // Name of the annotator model that is involved in this event.
     optional string model_name = 3;
 
     // Type of widget that was involved in triggering this event.
@@ -7054,7 +7221,7 @@
     // Event type of this event.
     optional android.stats.textclassifier.EventType event_type = 2;
 
-    // Name of the model that is involved in this event.
+    // Name of the actions model that is involved in this event.
     optional string model_name = 3;
 
     // Type of widget that was involved in triggering this event.
@@ -7074,6 +7241,9 @@
 
     // Name of source package.
     optional string package_name = 9;
+
+    // Name of the annotator model that is involved in this event.
+    optional string annotator_model_name = 10;
 }
 
 /**
@@ -7088,7 +7258,7 @@
     // Event type of this event.
     optional android.stats.textclassifier.EventType event_type = 2;
 
-    // Name of the model that is involved in this event.
+    // Name of the language detection model that is involved in this event.
     optional string model_name = 3;
 
     // Type of widget that was involved in triggering this event.
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
index 52a1269..69aae3d 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
@@ -86,7 +86,7 @@
             ALOGW("Child initialization failed %lld ", (long long)child);
             return false;
         } else {
-            ALOGW("Child initialization success %lld ", (long long)child);
+            VLOG("Child initialization success %lld ", (long long)child);
         }
 
         if (allConditionTrackers[childIndex]->isSliced()) {
diff --git a/cmds/statsd/src/external/PullResultReceiver.cpp b/cmds/statsd/src/external/PullResultReceiver.cpp
index 6bd0545..6b6fe7d 100644
--- a/cmds/statsd/src/external/PullResultReceiver.cpp
+++ b/cmds/statsd/src/external/PullResultReceiver.cpp
@@ -25,12 +25,13 @@
 namespace statsd {
 
 PullResultReceiver::PullResultReceiver(
-        std::function<void(int32_t, bool, const vector<android::util::StatsEvent>&)> pullFinishCb)
+        std::function<void(int32_t, bool, const vector<android::util::StatsEventParcel>&)>
+             pullFinishCb)
     : pullFinishCallback(std::move(pullFinishCb)) {
 }
 
 Status PullResultReceiver::pullFinished(int32_t atomTag, bool success,
-                                        const vector<StatsEvent>& output) {
+                                        const vector<StatsEventParcel>& output) {
     pullFinishCallback(atomTag, success, output);
     return Status::ok();
 }
@@ -40,4 +41,4 @@
 
 }  // namespace statsd
 }  // namespace os
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/cmds/statsd/src/external/PullResultReceiver.h b/cmds/statsd/src/external/PullResultReceiver.h
index f731f77..17d06e4 100644
--- a/cmds/statsd/src/external/PullResultReceiver.h
+++ b/cmds/statsd/src/external/PullResultReceiver.h
@@ -24,7 +24,7 @@
 
 class PullResultReceiver : public BnPullAtomResultReceiver {
 public:
-    PullResultReceiver(function<void(int32_t, bool, const vector<android::util::StatsEvent>&)>
+    PullResultReceiver(function<void(int32_t, bool, const vector<android::util::StatsEventParcel>&)>
                                pullFinishCallback);
     ~PullResultReceiver();
 
@@ -32,10 +32,11 @@
      * Binder call for finishing a pull.
      */
     binder::Status pullFinished(int32_t atomTag, bool success,
-                                        const vector<android::util::StatsEvent>& output) override;
+                                const vector<android::util::StatsEventParcel>& output) override;
 
 private:
-    function<void(int32_t, bool, const vector<android::util::StatsEvent>&)> pullFinishCallback;
+    function<void(int32_t, bool, const vector<android::util::StatsEventParcel>&)>
+            pullFinishCallback;
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/external/StatsCallbackPuller.cpp b/cmds/statsd/src/external/StatsCallbackPuller.cpp
index 92db684..f5b1e7f 100644
--- a/cmds/statsd/src/external/StatsCallbackPuller.cpp
+++ b/cmds/statsd/src/external/StatsCallbackPuller.cpp
@@ -20,7 +20,7 @@
 #include "StatsCallbackPuller.h"
 
 #include <android/os/IPullAtomCallback.h>
-#include <android/util/StatsEvent.h>
+#include <android/util/StatsEventParcel.h>
 
 #include "PullResultReceiver.h"
 #include "StatsPullerManager.h"
@@ -57,13 +57,19 @@
 
     sp<PullResultReceiver> resultReceiver = new PullResultReceiver(
             [cv_mutex, cv, pullFinish, pullSuccess, sharedData](
-                    int32_t atomTag, bool success, const vector<StatsEvent>& output) {
+                    int32_t atomTag, bool success, const vector<StatsEventParcel>& output) {
                 // This is the result of the pull, executing in a statsd binder thread.
                 // The pull could have taken a long time, and we should only modify
                 // data (the output param) if the pointer is in scope and the pull did not time out.
                 {
                     lock_guard<mutex> lk(*cv_mutex);
-                    // TODO: fill the shared vector of LogEvents once StatsEvent is complete.
+                    for (const StatsEventParcel& parcel: output) {
+                        shared_ptr<LogEvent> event =
+                              make_shared<LogEvent>(const_cast<uint8_t*>(parcel.buffer.data()),
+                                                    parcel.buffer.size(),
+                                                    /*uid=*/ -1);
+                        sharedData->push_back(event);
+                    }
                     *pullSuccess = success;
                     *pullFinish = true;
                 }
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index b5bad05..615af89 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -281,6 +281,9 @@
         {{.atomTag = android::util::VMS_CLIENT_STATS},
          {.additiveFields = {5, 6, 7, 8, 9, 10},
           .puller = new CarStatsPuller(android::util::VMS_CLIENT_STATS)}},
+        // NotiifcationRemoteViews.
+        {{.atomTag = android::util::NOTIFICATION_REMOTE_VIEWS},
+         {.puller = new StatsCompanionServicePuller(android::util::NOTIFICATION_REMOTE_VIEWS)}},
 };
 
 StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index c29b32c..c1f95ee 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -121,10 +121,12 @@
     VLOG("~CountMetricProducer() called");
 }
 
-void CountMetricProducer::onStateChanged(int atomId, const HashableDimensionKey& primaryKey,
-                                         int oldState, int newState) {
-    VLOG("CountMetric %lld onStateChanged State%d, key %s, %d -> %d", (long long)mMetricId, atomId,
-         primaryKey.toString().c_str(), oldState, newState);
+void CountMetricProducer::onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
+                                         const HashableDimensionKey& primaryKey, int oldState,
+                                         int newState) {
+    VLOG("CountMetric %lld onStateChanged time %lld, State%d, key %s, %d -> %d",
+         (long long)mMetricId, (long long)eventTimeNs, atomId, primaryKey.toString().c_str(),
+         oldState, newState);
 }
 
 void CountMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 8b17d88..7b6c7e0 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -52,7 +52,8 @@
 
     virtual ~CountMetricProducer();
 
-    void onStateChanged(int32_t atomId, const HashableDimensionKey& primaryKey, int oldState,
+    void onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
+                        const HashableDimensionKey& primaryKey, int oldState,
                         int newState) override;
 
 protected:
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index a513db6..3512f18 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -149,8 +149,8 @@
         return mConditionSliced;
     };
 
-    void onStateChanged(int atomId, const HashableDimensionKey& primaryKey, int oldState,
-                        int newState){};
+    void onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
+                        const HashableDimensionKey& primaryKey, int oldState, int newState){};
 
     // Output the metrics data to [protoOutput]. All metrics reports end with the same timestamp.
     // This method clears all the past buckets.
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index eb78ebc..2c99911 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -159,7 +159,7 @@
 
      // Kicks off the puller immediately if condition is true and diff based.
     if (mIsActive && mIsPulled && mCondition == ConditionState::kTrue && mUseDiff) {
-        pullAndMatchEventsLocked(mCurrentBucketStartTimeNs, mCondition);
+        pullAndMatchEventsLocked(mCurrentBucketStartTimeNs);
     }
     // Now that activations are processed, start the condition timer if needed.
     mConditionTimer.onConditionChanged(mIsActive && mCondition == ConditionState::kTrue,
@@ -183,11 +183,9 @@
 
 void ValueMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
     StatsdStats::getInstance().noteBucketDropped(mMetricId);
-    // We are going to flush the data without doing a pull first so we need to invalidte the data.
-    bool pullNeeded = mIsPulled && mCondition == ConditionState::kTrue;
-    if (pullNeeded) {
-        invalidateCurrentBucket();
-    }
+
+    // The current partial bucket is not flushed and does not require a pull,
+    // so the data is still valid.
     flushIfNeededLocked(dropTimeNs);
     clearPastBucketsLocked(dropTimeNs);
 }
@@ -216,7 +214,7 @@
                     invalidateCurrentBucket();
                     break;
                 case NO_TIME_CONSTRAINTS:
-                    pullAndMatchEventsLocked(dumpTimeNs, mCondition);
+                    pullAndMatchEventsLocked(dumpTimeNs);
                     break;
             }
         }
@@ -366,7 +364,7 @@
     // Pull on active state changes.
     if (!isEventTooLate) {
         if (mIsPulled) {
-            pullAndMatchEventsLocked(eventTimeNs, mCondition);
+            pullAndMatchEventsLocked(eventTimeNs);
         }
         // When active state changes from true to false, clear diff base but don't
         // reset other counters as we may accumulate more value in the bucket.
@@ -425,7 +423,7 @@
     // called before #onDataPulled.
     if (mIsPulled &&
         (newCondition == ConditionState::kTrue || mCondition == ConditionState::kTrue)) {
-        pullAndMatchEventsLocked(eventTimeNs, newCondition);
+        pullAndMatchEventsLocked(eventTimeNs);
     }
 
     // For metrics that use diff, when condition changes from true to false,
@@ -443,8 +441,7 @@
     mConditionTimer.onConditionChanged(mCondition, eventTimeNs);
 }
 
-void ValueMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs,
-        ConditionState condition) {
+void ValueMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) {
     vector<std::shared_ptr<LogEvent>> allData;
     if (!mPullerManager->Pull(mPullTagId, &allData)) {
         ALOGE("Stats puller failed for tag: %d at %lld", mPullTagId, (long long)timestampNs);
@@ -452,7 +449,7 @@
         return;
     }
 
-    accumulateEvents(allData, timestampNs, timestampNs, condition);
+    accumulateEvents(allData, timestampNs, timestampNs);
 }
 
 int64_t ValueMetricProducer::calcPreviousBucketEndTime(const int64_t currentTimeNs) {
@@ -474,7 +471,7 @@
             if (isEventLate) {
                 // If the event is late, we are in the middle of a bucket. Just
                 // process the data without trying to snap the data to the nearest bucket.
-                accumulateEvents(allData, originalPullTimeNs, originalPullTimeNs, mCondition);
+                accumulateEvents(allData, originalPullTimeNs, originalPullTimeNs);
             } else {
                 // For scheduled pulled data, the effective event time is snap to the nearest
                 // bucket end. In the case of waking up from a deep sleep state, we will
@@ -488,7 +485,7 @@
                 int64_t bucketEndTime = calcPreviousBucketEndTime(originalPullTimeNs) - 1;
                 StatsdStats::getInstance().noteBucketBoundaryDelayNs(
                         mMetricId, originalPullTimeNs - bucketEndTime);
-                accumulateEvents(allData, originalPullTimeNs, bucketEndTime, mCondition);
+                accumulateEvents(allData, originalPullTimeNs, bucketEndTime);
             }
         }
     }
@@ -499,8 +496,7 @@
 }
 
 void ValueMetricProducer::accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData,
-                                           int64_t originalPullTimeNs, int64_t eventElapsedTimeNs,
-                                           ConditionState condition) {
+                                           int64_t originalPullTimeNs, int64_t eventElapsedTimeNs) {
     bool isEventLate = eventElapsedTimeNs < mCurrentBucketStartTimeNs;
     if (isEventLate) {
         VLOG("Skip bucket end pull due to late arrival: %lld vs %lld",
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 206e602..2033a2a 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -78,7 +78,7 @@
             return;
         }
         if (mIsPulled && mCondition) {
-            pullAndMatchEventsLocked(eventTimeNs, mCondition);
+            pullAndMatchEventsLocked(eventTimeNs);
         }
         flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
     };
@@ -188,11 +188,10 @@
 
     bool hitFullBucketGuardRailLocked(const MetricDimensionKey& newKey);
 
-    void pullAndMatchEventsLocked(const int64_t timestampNs, ConditionState condition);
+    void pullAndMatchEventsLocked(const int64_t timestampNs);
 
     void accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData,
-                          int64_t originalPullTimeNs, int64_t eventElapsedTimeNs,
-                          ConditionState condition);
+                          int64_t originalPullTimeNs, int64_t eventElapsedTimeNs);
 
     ValueBucket buildPartialBucket(int64_t bucketEndTime,
                                    const std::vector<Interval>& intervals);
diff --git a/cmds/statsd/src/state/StateListener.h b/cmds/statsd/src/state/StateListener.h
index f2b9a6b..d1af196 100644
--- a/cmds/statsd/src/state/StateListener.h
+++ b/cmds/statsd/src/state/StateListener.h
@@ -38,13 +38,15 @@
      * state groups and are responsible for mapping original state values to
      * the correct state group.
      *
+     * [eventTimeNs]: Time of the state change log event.
      * [atomId]: The id of the state atom
      * [primaryKey]: The primary field values of the state atom
      * [oldState]: Previous state value before state change
      * [newState]: Current state value after state change
      */
-    virtual void onStateChanged(int32_t atomId, const HashableDimensionKey& primaryKey,
-                                int oldState, int newState) = 0;
+    virtual void onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
+                                const HashableDimensionKey& primaryKey, int oldState,
+                                int newState) = 0;
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/state/StateTracker.cpp b/cmds/statsd/src/state/StateTracker.cpp
index e6f6122..ef59c92 100644
--- a/cmds/statsd/src/state/StateTracker.cpp
+++ b/cmds/statsd/src/state/StateTracker.cpp
@@ -38,49 +38,51 @@
 }
 
 void StateTracker::onLogEvent(const LogEvent& event) {
-    // parse event for primary field values i.e. primary key
+    int64_t eventTimeNs = event.GetElapsedTimestampNs();
+
+    // Parse event for primary field values i.e. primary key.
     HashableDimensionKey primaryKey;
     if (mPrimaryFields.size() > 0) {
         if (!filterValues(mPrimaryFields, event.getValues(), &primaryKey) ||
             primaryKey.getValues().size() != mPrimaryFields.size()) {
             ALOGE("StateTracker error extracting primary key from log event.");
-            handleReset();
+            handleReset(eventTimeNs);
             return;
         }
     } else {
-        // atom has no primary fields
+        // Use an empty HashableDimensionKey if atom has no primary fields.
         primaryKey = DEFAULT_DIMENSION_KEY;
     }
 
-    // parse event for state value
+    // Parse event for state value.
     FieldValue stateValue;
     int32_t state;
     if (!filterValues(mStateField, event.getValues(), &stateValue) ||
         stateValue.mValue.getType() != INT) {
         ALOGE("StateTracker error extracting state from log event. Type: %d",
               stateValue.mValue.getType());
-        handlePartialReset(primaryKey);
+        handlePartialReset(eventTimeNs, primaryKey);
         return;
     }
     state = stateValue.mValue.int_value;
 
     if (state == mResetState) {
         VLOG("StateTracker Reset state: %s", stateValue.mValue.toString().c_str());
-        handleReset();
+        handleReset(eventTimeNs);
     }
 
-    // track and update state
+    // Track and update state.
     int32_t oldState = 0;
     int32_t newState = 0;
     updateState(primaryKey, state, &oldState, &newState);
 
-    // notify all listeners if state has changed
+    // Notify all listeners if state has changed.
     if (oldState != newState) {
         VLOG("StateTracker updated state");
         for (auto listener : mListeners) {
             auto sListener = listener.promote();  // safe access to wp<>
             if (sListener != nullptr) {
-                sListener->onStateChanged(mAtomId, primaryKey, oldState, newState);
+                sListener->onStateChanged(eventTimeNs, mAtomId, primaryKey, oldState, newState);
             }
         }
     } else {
@@ -119,22 +121,31 @@
     return false;
 }
 
-void StateTracker::handleReset() {
+void StateTracker::handleReset(const int64_t eventTimeNs) {
     VLOG("StateTracker handle reset");
     for (const auto pair : mStateMap) {
         for (auto l : mListeners) {
             auto sl = l.promote();
             if (sl != nullptr) {
-                sl->onStateChanged(mAtomId, pair.first, pair.second.state, mDefaultState);
+                sl->onStateChanged(eventTimeNs, mAtomId, pair.first, pair.second.state,
+                                   mDefaultState);
             }
         }
     }
     mStateMap.clear();
 }
 
-void StateTracker::handlePartialReset(const HashableDimensionKey& primaryKey) {
+void StateTracker::handlePartialReset(const int64_t eventTimeNs,
+                                      const HashableDimensionKey& primaryKey) {
     VLOG("StateTracker handle partial reset");
     if (mStateMap.find(primaryKey) != mStateMap.end()) {
+        for (auto l : mListeners) {
+            auto sl = l.promote();
+            if (sl != nullptr) {
+                sl->onStateChanged(eventTimeNs, mAtomId, primaryKey,
+                                   mStateMap.find(primaryKey)->second.state, mDefaultState);
+            }
+        }
         mStateMap.erase(primaryKey);
     }
 }
diff --git a/cmds/statsd/src/state/StateTracker.h b/cmds/statsd/src/state/StateTracker.h
index 450412d..e65325a 100644
--- a/cmds/statsd/src/state/StateTracker.h
+++ b/cmds/statsd/src/state/StateTracker.h
@@ -80,11 +80,13 @@
     // Set of all StateListeners (objects listening for state changes)
     std::set<wp<StateListener>> mListeners;
 
-    // Reset all state values in map to default state
-    void handleReset();
+    // Reset all state values in map to default state.
+    void handleReset(const int64_t eventTimeNs);
 
-    // Reset only the state value mapped to primary key to default state
-    void handlePartialReset(const HashableDimensionKey& primaryKey);
+    // Reset only the state value mapped to the given primary key to default state.
+    // Partial resets are used when we only need to update the state of one primary
+    // key instead of clearing/reseting every key in the map.
+    void handlePartialReset(const int64_t eventTimeNs, const HashableDimensionKey& primaryKey);
 
     // Update the StateMap based on the received state value.
     // Store the old and new states.
diff --git a/cmds/statsd/tests/state/StateTracker_test.cpp b/cmds/statsd/tests/state/StateTracker_test.cpp
index 4208fef..395167b 100644
--- a/cmds/statsd/tests/state/StateTracker_test.cpp
+++ b/cmds/statsd/tests/state/StateTracker_test.cpp
@@ -44,8 +44,8 @@
 
     std::vector<Update> updates;
 
-    void onStateChanged(int atomId, const HashableDimensionKey& primaryKey, int oldState,
-                        int newState) {
+    void onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
+                        const HashableDimensionKey& primaryKey, int oldState, int newState) {
         updates.emplace_back(primaryKey, newState);
     }
 };
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index a4b3058..1987440 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -16,10 +16,12 @@
 
 package com.android.commands.telecom;
 
+import android.app.ActivityThread;
 import android.content.ComponentName;
 import android.content.Context;
 import android.net.Uri;
 import android.os.IUserManager;
+import android.os.Looper;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -33,7 +35,6 @@
 
 import com.android.internal.os.BaseCommand;
 import com.android.internal.telecom.ITelecomService;
-import com.android.internal.telephony.ITelephony;
 
 import java.io.PrintStream;
 
@@ -58,7 +59,6 @@
     private static final String COMMAND_SET_TEST_CALL_SCREENING_APP = "set-test-call-screening-app";
     private static final String COMMAND_ADD_OR_REMOVE_CALL_COMPANION_APP =
             "add-or-remove-call-companion-app";
-    private static final String COMMAND_SET_TEST_AUTO_MODE_APP = "set-test-auto-mode-app";
     private static final String COMMAND_SET_PHONE_ACCOUNT_SUGGESTION_COMPONENT =
             "set-phone-acct-suggestion-component";
     private static final String COMMAND_UNREGISTER_PHONE_ACCOUNT = "unregister-phone-account";
@@ -83,7 +83,7 @@
     private ComponentName mComponent;
     private String mAccountId;
     private ITelecomService mTelecomService;
-    private ITelephony mTelephonyService;
+    private TelephonyManager mTelephonyManager;
     private IUserManager mUserManager;
 
     @Override
@@ -99,7 +99,6 @@
                 + "<USER_SN>\n"
                 + "usage: telecom set-test-call-redirection-app <PACKAGE>\n"
                 + "usage: telecom set-test-call-screening-app <PACKAGE>\n"
-                + "usage: telecom set-test-auto-mode-app <PACKAGE>\n"
                 + "usage: telecom set-phone-acct-suggestion-component <COMPONENT>\n"
                 + "usage: telecom add-or-remove-call-companion-app <PACKAGE> <1/0>\n"
                 + "usage: telecom register-sim-phone-account <COMPONENT> <ID> <USER_SN>"
@@ -155,9 +154,10 @@
             return;
         }
 
-        mTelephonyService = ITelephony.Stub.asInterface(
-                ServiceManager.getService(Context.TELEPHONY_SERVICE));
-        if (mTelephonyService == null) {
+        Looper.prepareMainLooper();
+        Context context = ActivityThread.systemMain().getSystemContext();
+        mTelephonyManager = context.getSystemService(TelephonyManager.class);
+        if (mTelephonyManager == null) {
             Log.w(this, "onRun: Can't access telephony service.");
             showError("Error: Could not access the Telephony Service. Is the system running?");
             return;
@@ -191,9 +191,6 @@
             case COMMAND_ADD_OR_REMOVE_CALL_COMPANION_APP:
                 runAddOrRemoveCallCompanionApp();
                 break;
-            case COMMAND_SET_TEST_AUTO_MODE_APP:
-                runSetTestAutoModeApp();
-                break;
             case COMMAND_SET_PHONE_ACCOUNT_SUGGESTION_COMPONENT:
                 runSetTestPhoneAcctSuggestionComponent();
                 break;
@@ -305,11 +302,6 @@
         mTelecomService.addOrRemoveTestCallCompanionApp(packageName, isAddedBool);
     }
 
-    private void runSetTestAutoModeApp() throws RemoteException {
-        final String packageName = nextArg();
-        mTelecomService.setTestAutoModeApp(packageName);
-    }
-
     private void runSetTestPhoneAcctSuggestionComponent() throws RemoteException {
         final String componentName = nextArg();
         mTelecomService.setTestPhoneAcctSuggestionComponent(componentName);
@@ -361,7 +353,7 @@
         }
         int numSims = Integer.parseInt(nextArgRequired());
         System.out.println("Setting sim count to " + numSims + ". Device may reboot");
-        mTelephonyService.switchMultiSimConfig(numSims);
+        mTelephonyManager.switchMultiSimConfig(numSims);
     }
 
     /**
@@ -375,8 +367,7 @@
 
     private void runGetMaxPhones() throws RemoteException {
         // This assumes the max number of SIMs is 2, which it currently is
-        if (TelephonyManager.MULTISIM_ALLOWED
-                == mTelephonyService.isMultiSimSupported("com.android.commands.telecom", null)) {
+        if (TelephonyManager.MULTISIM_ALLOWED == mTelephonyManager.isMultiSimSupported()) {
             System.out.println("2");
         } else {
             System.out.println("1");
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 0394a7a..97f009c 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -878,7 +878,7 @@
 android.content.pm.ActivityInfo$1
 android.content.pm.ActivityInfo$WindowLayout
 android.content.pm.ActivityInfo
-android.content.pm.AndroidHidlUpdater
+android.content.pm.parsing.library.AndroidHidlUpdater
 android.content.pm.ApplicationInfo$1
 android.content.pm.ApplicationInfo
 android.content.pm.BaseParceledListSlice
@@ -922,10 +922,10 @@
 android.content.pm.LauncherApps
 android.content.pm.ModuleInfo$1
 android.content.pm.ModuleInfo
-android.content.pm.OrgApacheHttpLegacyUpdater
-android.content.pm.PackageBackwardCompatibility$AndroidTestRunnerSplitUpdater
-android.content.pm.PackageBackwardCompatibility$RemoveUnnecessaryAndroidTestBaseLibrary
-android.content.pm.PackageBackwardCompatibility
+android.content.pm.parsing.library.OrgApacheHttpLegacyUpdater
+android.content.pm.parsing.library.PackageBackwardCompatibility$AndroidTestRunnerSplitUpdater
+android.content.pm.parsing.library.PackageBackwardCompatibility$RemoveUnnecessaryAndroidTestBaseLibrary
+android.content.pm.parsing.library.PackageBackwardCompatibility
 android.content.pm.PackageInfo$1
 android.content.pm.PackageInfo
 android.content.pm.PackageInstaller$Session
@@ -960,7 +960,7 @@
 android.content.pm.PackageParser$SigningDetails
 android.content.pm.PackageParser$SplitNameComparator
 android.content.pm.PackageParser
-android.content.pm.PackageSharedLibraryUpdater
+android.content.pm.parsing.library.PackageSharedLibraryUpdater
 android.content.pm.PackageStats$1
 android.content.pm.PackageStats
 android.content.pm.PackageUserState
diff --git a/core/TEST_MAPPING b/core/TEST_MAPPING
new file mode 100644
index 0000000..fd571c9
--- /dev/null
+++ b/core/TEST_MAPPING
@@ -0,0 +1,24 @@
+{
+  "presubmit": [
+    {
+      "name": "FrameworksCoreTests",
+      "options": [
+        {
+          "include-filter": "android.view.inputmethod"
+        },
+        {
+          "include-filter": "com.android.internal.inputmethod"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ],
+      "file_patterns": [
+        "core/java/com/android/internal/inputmethod/.*",
+        "core/java/android/view/inputmethod/.*",
+        "core/tests/coretests/src/android/view/inputmethod/.*",
+        "core/tests/coretests/src/com/android/internal/inputmethod/.*"
+      ]
+    }
+  ]
+}
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 3db0b26..7fd01db 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -20,6 +20,8 @@
 
 import android.annotation.IntDef;
 import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledAfter;
@@ -512,6 +514,21 @@
     private static final long REQUEST_ACCESSIBILITY_BUTTON_CHANGE = 136293963L;
 
     /**
+     * Resource id of the animated image of the accessibility service.
+     */
+    private int mAnimatedImageRes;
+
+    /**
+     * Resource id of the html description of the accessibility service.
+     */
+    private int mHtmlDescriptionRes;
+
+    /**
+     * Non localized html description of the accessibility service.
+     */
+    private String mNonLocalizedHtmlDescription;
+
+    /**
      * Creates a new instance.
      */
     public AccessibilityServiceInfo() {
@@ -626,6 +643,20 @@
                     mNonLocalizedSummary = nonLocalizedSummary.toString().trim();
                 }
             }
+            peekedValue = asAttributes.peekValue(
+                    com.android.internal.R.styleable.AccessibilityService_animatedImageDrawable);
+            if (peekedValue != null) {
+                mAnimatedImageRes = peekedValue.resourceId;
+            }
+            peekedValue = asAttributes.peekValue(
+                    com.android.internal.R.styleable.AccessibilityService_htmlDescription);
+            if (peekedValue != null) {
+                mHtmlDescriptionRes = peekedValue.resourceId;
+                final CharSequence nonLocalizedHtmlDescription = peekedValue.coerceToString();
+                if (nonLocalizedHtmlDescription != null) {
+                    mNonLocalizedHtmlDescription = nonLocalizedHtmlDescription.toString().trim();
+                }
+            }
             asAttributes.recycle();
         } catch (NameNotFoundException e) {
             throw new XmlPullParserException( "Unable to create context for: "
@@ -727,6 +758,18 @@
     }
 
     /**
+     * The animated image resource id.
+     * <p>
+     *    <strong>Statically set from
+     *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
+     * </p>
+     * @return The animated image resource id.
+     */
+    public int getAnimatedImageRes() {
+        return mAnimatedImageRes;
+    }
+
+    /**
      * Whether this service can retrieve the current window's content.
      * <p>
      *    <strong>Statically set from
@@ -833,6 +876,29 @@
     }
 
     /**
+     * The localized html description of the accessibility service.
+     * <p>
+     *    <strong>Statically set from
+     *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
+     * </p>
+     * @return The localized html description.
+     */
+    @Nullable
+    public String loadHtmlDescription(@NonNull PackageManager packageManager) {
+        if (mHtmlDescriptionRes == 0) {
+            return mNonLocalizedHtmlDescription;
+        }
+
+        final ServiceInfo serviceInfo = mResolveInfo.serviceInfo;
+        final CharSequence htmlDescription = packageManager.getText(serviceInfo.packageName,
+                mHtmlDescriptionRes, serviceInfo.applicationInfo);
+        if (htmlDescription != null) {
+            return htmlDescription.toString().trim();
+        }
+        return null;
+    }
+
+    /**
      * Set the recommended time that non-interactive controls need to remain on the screen to
      * support the user.
      * <p>
@@ -915,7 +981,10 @@
         parcel.writeInt(mSummaryResId);
         parcel.writeString(mNonLocalizedSummary);
         parcel.writeInt(mDescriptionResId);
+        parcel.writeInt(mAnimatedImageRes);
+        parcel.writeInt(mHtmlDescriptionRes);
         parcel.writeString(mNonLocalizedDescription);
+        parcel.writeString(mNonLocalizedHtmlDescription);
     }
 
     private void initFromParcel(Parcel parcel) {
@@ -934,7 +1003,10 @@
         mSummaryResId = parcel.readInt();
         mNonLocalizedSummary = parcel.readString();
         mDescriptionResId = parcel.readInt();
+        mAnimatedImageRes = parcel.readInt();
+        mHtmlDescriptionRes = parcel.readInt();
         mNonLocalizedDescription = parcel.readString();
+        mNonLocalizedHtmlDescription = parcel.readString();
     }
 
     @Override
diff --git a/core/java/android/annotation/Hide.java b/core/java/android/annotation/Hide.java
new file mode 100644
index 0000000..c8e5a4a
--- /dev/null
+++ b/core/java/android/annotation/Hide.java
@@ -0,0 +1,41 @@
+/*
+ * 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.annotation;
+
+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.METHOD;
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that an API is hidden by default, in a similar fashion to the
+ * <pre>@hide</pre> javadoc tag.
+ *
+ * <p>Note that, in order for this to work, metalava has to be invoked with
+ * the flag {@code --hide-annotation android.annotation.Hide}.
+ * @hide
+ */
+@Target({TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE})
+@Retention(RetentionPolicy.CLASS)
+public @interface Hide {
+}
diff --git a/core/java/android/annotation/UnsupportedAppUsage.java b/core/java/android/annotation/UnsupportedAppUsage.java
index 204d71d..1af48cb 100644
--- a/core/java/android/annotation/UnsupportedAppUsage.java
+++ b/core/java/android/annotation/UnsupportedAppUsage.java
@@ -148,6 +148,18 @@
     String publicAlternatives() default "";
 
     /**
+     * Override the default source position when generating an index of the annotations.
+     *
+     * <p>This is intended for use by tools that generate java source code, to point to the
+     * original source position of the annotation, rather than the position within the generated
+     * code. It should never be set manually.
+     *
+     * <p>The format of the value is "path/to/file:startline:startcol:endline:endcol" indicating
+     * the position of the annotation itself.
+     */
+    String overrideSourcePosition() default "";
+
+    /**
      * Container for {@link UnsupportedAppUsage} that allows it to be applied repeatedly to types.
      */
     @Retention(CLASS)
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index f54e841..577272e 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -726,7 +726,7 @@
         implements LayoutInflater.Factory2,
         Window.Callback, KeyEvent.Callback,
         OnCreateContextMenuListener, ComponentCallbacks2,
-        Window.OnWindowDismissedCallback, WindowControllerCallback,
+        Window.OnWindowDismissedCallback,
         AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {
     private static final String TAG = "Activity";
     private static final boolean DEBUG_LIFECYCLE = false;
@@ -769,17 +769,6 @@
 
     private static final String KEYBOARD_SHORTCUTS_RECEIVER_PKG_NAME = "com.android.systemui";
 
-    private static final int LOG_AM_ON_CREATE_CALLED = 30057;
-    private static final int LOG_AM_ON_START_CALLED = 30059;
-    private static final int LOG_AM_ON_RESUME_CALLED = 30022;
-    private static final int LOG_AM_ON_PAUSE_CALLED = 30021;
-    private static final int LOG_AM_ON_STOP_CALLED = 30049;
-    private static final int LOG_AM_ON_RESTART_CALLED = 30058;
-    private static final int LOG_AM_ON_DESTROY_CALLED = 30060;
-    private static final int LOG_AM_ON_ACTIVITY_RESULT_CALLED = 30062;
-    private static final int LOG_AM_ON_TOP_RESUMED_GAINED_CALLED = 30064;
-    private static final int LOG_AM_ON_TOP_RESUMED_LOST_CALLED = 30065;
-
     private static class ManagedDialog {
         Dialog mDialog;
         Bundle mArgs;
@@ -949,6 +938,62 @@
     private Boolean mLastDispatchedIsInMultiWindowMode;
     private Boolean mLastDispatchedIsInPictureInPictureMode;
 
+    private final WindowControllerCallback mWindowControllerCallback =
+            new WindowControllerCallback() {
+        /**
+         * Moves the activity between {@link WindowConfiguration#WINDOWING_MODE_FREEFORM} windowing
+         * mode and {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN}.
+         *
+         * @hide
+         */
+        @Override
+        public void toggleFreeformWindowingMode() throws RemoteException {
+            ActivityTaskManager.getService().toggleFreeformWindowingMode(mToken);
+        }
+
+        /**
+         * Puts the activity in picture-in-picture mode if the activity supports.
+         * @see android.R.attr#supportsPictureInPicture
+         * @hide
+         */
+        @Override
+        public void enterPictureInPictureModeIfPossible() {
+            if (mActivityInfo.supportsPictureInPicture()) {
+                enterPictureInPictureMode();
+            }
+        }
+
+        @Override
+        public boolean isTaskRoot() {
+            try {
+                return ActivityTaskManager.getService().getTaskForActivity(mToken, true) >= 0;
+            } catch (RemoteException e) {
+                return false;
+            }
+        }
+
+        /**
+         * Update the forced status bar color.
+         * @hide
+         */
+        @Override
+        public void updateStatusBarColor(int color) {
+            mTaskDescription.setStatusBarColor(color);
+            setTaskDescription(mTaskDescription);
+        }
+
+        /**
+         * Update the forced navigation bar color.
+         * @hide
+         */
+        @Override
+        public void updateNavigationBarColor(int color) {
+            mTaskDescription.setNavigationBarColor(color);
+            setTaskDescription(mTaskDescription);
+        }
+
+    };
+
     private static native String getDlWarning();
 
     /** Return the intent that started this activity. */
@@ -1863,8 +1908,13 @@
     final void performTopResumedActivityChanged(boolean isTopResumedActivity, String reason) {
         onTopResumedActivityChanged(isTopResumedActivity);
 
-        writeEventLog(isTopResumedActivity
-                ? LOG_AM_ON_TOP_RESUMED_GAINED_CALLED : LOG_AM_ON_TOP_RESUMED_LOST_CALLED, reason);
+        if (isTopResumedActivity) {
+            EventLogTags.writeWmOnTopResumedGainedCalled(mIdent, getComponentName().getClassName(),
+                    reason);
+        } else {
+            EventLogTags.writeWmOnTopResumedLostCalled(mIdent, getComponentName().getClassName(),
+                    reason);
+        }
     }
 
     void setVoiceInteractor(IVoiceInteractor voiceInteractor) {
@@ -3921,49 +3971,6 @@
 
 
     /**
-     * Moves the activity between {@link WindowConfiguration#WINDOWING_MODE_FREEFORM} windowing mode
-     * and {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN}.
-     *
-     * @hide
-     */
-    @Override
-    public void toggleFreeformWindowingMode() throws RemoteException {
-        ActivityTaskManager.getService().toggleFreeformWindowingMode(mToken);
-    }
-
-    /**
-     * Update the forced status bar color.
-     * @hide
-     */
-    @Override
-    public void updateStatusBarColor(int color) {
-        mTaskDescription.setStatusBarColor(color);
-        setTaskDescription(mTaskDescription);
-    }
-
-    /**
-     * Update the forced navigation bar color.
-     * @hide
-     */
-    @Override
-    public void updateNavigationBarColor(int color) {
-        mTaskDescription.setNavigationBarColor(color);
-        setTaskDescription(mTaskDescription);
-    }
-
-    /**
-     * Puts the activity in picture-in-picture mode if the activity supports.
-     * @see android.R.attr#supportsPictureInPicture
-     * @hide
-     */
-    @Override
-    public void enterPictureInPictureModeIfPossible() {
-        if (mActivityInfo.supportsPictureInPicture()) {
-            enterPictureInPictureMode();
-        }
-    }
-
-    /**
      * Called to process key events.  You can override this to intercept all
      * key events before they are dispatched to the window.  Be sure to call
      * this implementation for key events that should be handled normally.
@@ -6609,13 +6616,8 @@
      *
      * @return True if this is the root activity, else false.
      */
-    @Override
     public boolean isTaskRoot() {
-        try {
-            return ActivityTaskManager.getService().getTaskForActivity(mToken, true) >= 0;
-        } catch (RemoteException e) {
-            return false;
-        }
+        return mWindowControllerCallback.isTaskRoot();
     }
 
     /**
@@ -7807,7 +7809,7 @@
         mFragments.attachHost(null /*parent*/);
 
         mWindow = new PhoneWindow(this, window, activityConfigCallback);
-        mWindow.setWindowControllerCallback(this);
+        mWindow.setWindowControllerCallback(mWindowControllerCallback);
         mWindow.setCallback(this);
         mWindow.setOnWindowDismissedCallback(this);
         mWindow.getLayoutInflater().setPrivateFactory(this);
@@ -7898,7 +7900,8 @@
         } else {
             onCreate(icicle);
         }
-        writeEventLog(LOG_AM_ON_CREATE_CALLED, "performCreate");
+        EventLogTags.writeWmOnCreateCalled(mIdent, getComponentName().getClassName(),
+                "performCreate");
         mActivityTransitionState.readState(icicle);
 
         mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
@@ -7920,7 +7923,7 @@
         mCalled = false;
         mFragments.execPendingActions();
         mInstrumentation.callActivityOnStart(this);
-        writeEventLog(LOG_AM_ON_START_CALLED, reason);
+        EventLogTags.writeWmOnStartCalled(mIdent, getComponentName().getClassName(), reason);
 
         if (!mCalled) {
             throw new SuperNotCalledException(
@@ -7998,7 +8001,7 @@
 
             mCalled = false;
             mInstrumentation.callActivityOnRestart(this);
-            writeEventLog(LOG_AM_ON_RESTART_CALLED, reason);
+            EventLogTags.writeWmOnRestartCalled(mIdent, getComponentName().getClassName(), reason);
             if (!mCalled) {
                 throw new SuperNotCalledException(
                     "Activity " + mComponent.toShortString() +
@@ -8031,7 +8034,7 @@
         mCalled = false;
         // mResumed is set by the instrumentation
         mInstrumentation.callActivityOnResume(this);
-        writeEventLog(LOG_AM_ON_RESUME_CALLED, reason);
+        EventLogTags.writeWmOnResumeCalled(mIdent, getComponentName().getClassName(), reason);
         if (!mCalled) {
             throw new SuperNotCalledException(
                 "Activity " + mComponent.toShortString() +
@@ -8070,7 +8073,8 @@
         mFragments.dispatchPause();
         mCalled = false;
         onPause();
-        writeEventLog(LOG_AM_ON_PAUSE_CALLED, "performPause");
+        EventLogTags.writeWmOnPausedCalled(mIdent, getComponentName().getClassName(),
+                "performPause");
         mResumed = false;
         if (!mCalled && getApplicationInfo().targetSdkVersion
                 >= android.os.Build.VERSION_CODES.GINGERBREAD) {
@@ -8110,7 +8114,7 @@
 
             mCalled = false;
             mInstrumentation.callActivityOnStop(this);
-            writeEventLog(LOG_AM_ON_STOP_CALLED, reason);
+            EventLogTags.writeWmOnStopCalled(mIdent, getComponentName().getClassName(), reason);
             if (!mCalled) {
                 throw new SuperNotCalledException(
                     "Activity " + mComponent.toShortString() +
@@ -8140,7 +8144,8 @@
         mWindow.destroy();
         mFragments.dispatchDestroy();
         onDestroy();
-        writeEventLog(LOG_AM_ON_DESTROY_CALLED, "performDestroy");
+        EventLogTags.writeWmOnDestroyCalled(mIdent, getComponentName().getClassName(),
+                "performDestroy");
         mFragments.doLoaderDestroy();
         if (mVoiceInteractor != null) {
             mVoiceInteractor.detachActivity();
@@ -8233,7 +8238,9 @@
                 frag.onActivityResult(requestCode, resultCode, data);
             }
         }
-        writeEventLog(LOG_AM_ON_ACTIVITY_RESULT_CALLED, reason);
+
+        EventLogTags.writeWmOnActivityResultCalled(mIdent, getComponentName().getClassName(),
+                reason);
     }
 
     /**
@@ -8660,11 +8667,6 @@
         }
     }
 
-    /** Log a lifecycle event for current user id and component class. */
-    private void writeEventLog(int event, String reason) {
-        EventLog.writeEvent(event, mIdent, getComponentName().getClassName(), reason);
-    }
-
     class HostCallbacks extends FragmentHostCallback<Activity> {
         public HostCallbacks() {
             super(Activity.this /*activity*/);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 35a48a8..49a8e2f3 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -6254,6 +6254,7 @@
         // send up app name; do this *before* waiting for debugger
         Process.setArgV0(data.processName);
         android.ddm.DdmHandleAppName.setAppName(data.processName,
+                                                data.appInfo.packageName,
                                                 UserHandle.myUserId());
         VMRuntime.setProcessPackageName(data.appInfo.packageName);
 
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 91f8a3c..aaab6b4 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -22,11 +22,14 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutInfo;
 import android.graphics.Insets;
 import android.graphics.Matrix;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.os.Bundle;
 import android.os.UserHandle;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -209,6 +212,32 @@
     }
 
     /**
+     * Launch an activity represented by {@link ShortcutInfo} into this container.
+     * <p>The owner of this container must be allowed to access the shortcut information,
+     * as defined in {@link LauncherApps#hasShortcutHostPermission()} to use this method.
+     * <p>Activity resolved by the provided {@link ShortcutInfo} must have
+     * {@link android.R.attr#resizeableActivity} attribute set to {@code true} in order to be
+     * launched here. Also, if activity is not owned by the owner of this container, it must allow
+     * embedding and the caller must have permission to embed.
+     * <p>Note: This class must finish initializing and
+     * {@link StateCallback#onActivityViewReady(ActivityView)} callback must be triggered before
+     * this method can be called.
+     *
+     * @param shortcut the shortcut used to launch the activity.
+     * @param options for the activity.
+     * @param sourceBounds the rect containing the source bounds of the clicked icon to open
+     *                     this shortcut.
+     * @see StateCallback
+     * @see LauncherApps#startShortcut(ShortcutInfo, Rect, Bundle)
+     *
+     * @hide
+     */
+    public void startShortcutActivity(@NonNull ShortcutInfo shortcut,
+            @NonNull ActivityOptions options, @Nullable Rect sourceBounds) {
+        mTaskEmbedder.startShortcutActivity(shortcut, options, sourceBounds);
+    }
+
+    /**
      * Launch a new activity into this container.
      * <p>Activity resolved by the provided {@link Intent} must have
      * {@link android.R.attr#resizeableActivity} attribute set to {@code true} in order to be
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index 3a34b79..d8ddf218 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -1148,11 +1148,11 @@
         };
 
         /** @hide */
-        public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        public void dumpDebug(ProtoOutputStream proto, long fieldId) {
             final long token = proto.start(fieldId);
             proto.write(AlarmClockInfoProto.TRIGGER_TIME_MS, mTriggerTime);
             if (mShowIntent != null) {
-                mShowIntent.writeToProto(proto, AlarmClockInfoProto.SHOW_INTENT);
+                mShowIntent.dumpDebug(proto, AlarmClockInfoProto.SHOW_INTENT);
             }
             proto.end(token);
         }
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 0113f69..034826a 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -39,6 +39,7 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.IPackageMoveObserver;
 import android.content.pm.IPackageStatsObserver;
+import android.content.pm.InstallSourceInfo;
 import android.content.pm.InstantAppInfo;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.IntentFilterVerificationInfo;
@@ -2085,6 +2086,21 @@
     }
 
     @Override
+    @NonNull
+    public InstallSourceInfo getInstallSourceInfo(String packageName) throws NameNotFoundException {
+        final InstallSourceInfo installSourceInfo;
+        try {
+            installSourceInfo = mPM.getInstallSourceInfo(packageName);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+        if (installSourceInfo == null) {
+            throw new NameNotFoundException(packageName);
+        }
+        return installSourceInfo;
+    }
+
+    @Override
     public int getMoveStatus(int moveId) {
         try {
             return mPM.getMoveStatus(moveId);
@@ -2782,7 +2798,7 @@
     public Drawable loadUnbadgedItemIcon(@NonNull PackageItemInfo itemInfo,
             @Nullable ApplicationInfo appInfo) {
         if (itemInfo.showUserIcon != UserHandle.USER_NULL) {
-            // Indicates itemInfo is for a different user (e.g. a profile's parent), so use a 
+            // Indicates itemInfo is for a different user (e.g. a profile's parent), so use a
             // generic user icon (users generally lack permission to view each other's actual icons)
             int targetUserId = itemInfo.showUserIcon;
             return UserIcons.getDefaultUserIcon(
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 1c8f494..46f88d5 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1362,6 +1362,18 @@
     }
 
     @Override
+    public void sendOrderedBroadcast(Intent intent, String receiverPermission, String receiverAppOp,
+            Bundle options, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
+            String initialData, @Nullable Bundle initialExtras) {
+        int intAppOp = AppOpsManager.OP_NONE;
+        if (!TextUtils.isEmpty(receiverAppOp)) {
+            intAppOp = AppOpsManager.strOpToOp(receiverAppOp);
+        }
+        sendOrderedBroadcastAsUser(intent, getUser(), receiverPermission, intAppOp, options,
+                resultReceiver, scheduler, initialCode, initialData, initialExtras);
+    }
+
+    @Override
     @Deprecated
     public void sendStickyBroadcast(Intent intent) {
         warnIfCallingFromSystemProcess();
diff --git a/core/java/android/app/EventLogTags.logtags b/core/java/android/app/EventLogTags.logtags
new file mode 100644
index 0000000..6296a68
--- /dev/null
+++ b/core/java/android/app/EventLogTags.logtags
@@ -0,0 +1,36 @@
+# See system/core/logcat/event.logtags for a description of the format of this file.
+
+option java_package android.app
+
+# Do not change these names without updating the checkin_events setting in
+# google3/googledata/wireless/android/provisioning/gservices.config !!
+#
+# The activity's onPause has been called.
+30021 wm_on_paused_called (Token|1|5),(Component Name|3),(Reason|3)
+# The activity's onResume has been called.
+30022 wm_on_resume_called (Token|1|5),(Component Name|3),(Reason|3)
+
+# Attempting to stop an activity
+30048 wm_stop_activity (User|1|5),(Token|1|5),(Component Name|3)
+# The activity's onStop has been called.
+30049 wm_on_stop_called (Token|1|5),(Component Name|3),(Reason|3)
+
+# The activity's onCreate has been called.
+30057 wm_on_create_called (Token|1|5),(Component Name|3),(Reason|3)
+# The activity's onRestart has been called.
+30058 wm_on_restart_called (Token|1|5),(Component Name|3),(Reason|3)
+# The activity's onStart has been called.
+30059 wm_on_start_called (Token|1|5),(Component Name|3),(Reason|3)
+# The activity's onDestroy has been called.
+30060 wm_on_destroy_called (Token|1|5),(Component Name|3),(Reason|3)
+# The activity's onActivityResult has been called.
+30062 wm_on_activity_result_called (Token|1|5),(Component Name|3),(Reason|3)
+
+# The activity's onTopResumedActivityChanged(true) has been called.
+30064 wm_on_top_resumed_gained_called (Token|1|5),(Component Name|3),(Reason|3)
+# The activity's onTopResumedActivityChanged(false) has been called.
+30065 wm_on_top_resumed_lost_called (Token|1|5),(Component Name|3),(Reason|3)
+
+# An activity been add into stopping list
+30066 wm_add_to_stopping (User|1|5),(Token|1|5),(Component Name|3),(Reason|3)
+
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 50d0dab..aa8a302 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -387,6 +387,7 @@
     void requestInteractiveBugReport();
     void requestFullBugReport();
     void requestRemoteBugReport();
+    boolean launchBugReportHandlerApp();
 
     @UnsupportedAppUsage
     Intent getIntentForIntentSender(in IIntentSender sender);
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 9aca223..86f52af 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -21,6 +21,7 @@
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationChannelGroup;
+import android.app.NotificationHistory;
 import android.app.NotificationManager;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -119,6 +120,8 @@
     @UnsupportedAppUsage
     StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count);
 
+    NotificationHistory getNotificationHistory(String callingPkg);
+
     void registerListener(in INotificationListener listener, in ComponentName component, int userid);
     void unregisterListener(in INotificationListener listener, int userid);
 
@@ -204,4 +207,6 @@
 
     void setPrivateNotificationsAllowed(boolean allow);
     boolean getPrivateNotificationsAllowed();
+
+    long pullStats(long startNs, int report, boolean doAgg, out List<ParcelFileDescriptor> stats);
 }
diff --git a/core/java/android/app/IntentService.java b/core/java/android/app/IntentService.java
index 11c747f..74fb99a 100644
--- a/core/java/android/app/IntentService.java
+++ b/core/java/android/app/IntentService.java
@@ -44,13 +44,6 @@
  * long as necessary (and will not block the application's main loop), but
  * only one request will be processed at a time.
  *
- * <p class="note"><b>Note:</b> IntentService is subject to all the
- * <a href="/preview/features/background.html">background execution limits</a>
- * imposed with Android 8.0 (API level 26). In most cases, you are better off
- * using {@link android.support.v4.app.JobIntentService}, which uses jobs
- * instead of services when running on Android 8.0 or higher.
- * </p>
- *
  * <div class="special reference">
  * <h3>Developer Guides</h3>
  * <p>For a detailed discussion about how to create services, read the
@@ -59,8 +52,14 @@
  * </div>
  *
  * @see android.support.v4.app.JobIntentService
- * @see android.os.AsyncTask
+ *
+ * @deprecated IntentService is subject to all the
+ *   <a href="/preview/features/background.html">background execution limits</a>
+ *   imposed with Android 8.0 (API level 26). Consider using {@link androidx.work.WorkManager}
+ *   or {@link androidx.core.app.JobIntentService}, which uses jobs
+ *   instead of services when running on Android 8.0 or higher.
  */
+@Deprecated
 public abstract class IntentService extends Service {
     private volatile Looper mServiceLooper;
     @UnsupportedAppUsage
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index b37cc26..e307142 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2977,7 +2977,7 @@
     /**
      * @hide
      */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         long token = proto.start(fieldId);
         proto.write(NotificationProto.CHANNEL_ID, getChannelId());
         proto.write(NotificationProto.HAS_TICKER_TEXT, this.tickerText != null);
@@ -2993,7 +2993,7 @@
             proto.write(NotificationProto.VISIBILITY, this.visibility);
         }
         if (publicVersion != null) {
-            publicVersion.writeToProto(proto, NotificationProto.PUBLIC_VERSION);
+            publicVersion.dumpDebug(proto, NotificationProto.PUBLIC_VERSION);
         }
         proto.end(token);
     }
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 20d977b..1fc8a2b 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -1116,7 +1116,7 @@
     }
 
     /** @hide */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
 
         proto.write(NotificationChannelProto.ID, mId);
@@ -1142,7 +1142,7 @@
         proto.write(NotificationChannelProto.IS_DELETED, mDeleted);
         proto.write(NotificationChannelProto.GROUP, mGroup);
         if (mAudioAttributes != null) {
-            mAudioAttributes.writeToProto(proto, NotificationChannelProto.AUDIO_ATTRIBUTES);
+            mAudioAttributes.dumpDebug(proto, NotificationChannelProto.AUDIO_ATTRIBUTES);
         }
         proto.write(NotificationChannelProto.IS_BLOCKABLE_SYSTEM, mBlockableSystem);
         proto.write(NotificationChannelProto.ALLOW_APP_OVERLAY, mAllowBubbles);
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index a8ee414..c4c1e4f 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -332,7 +332,7 @@
     }
 
     /** @hide */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
 
         proto.write(NotificationChannelGroupProto.ID, mId);
@@ -340,7 +340,7 @@
         proto.write(NotificationChannelGroupProto.DESCRIPTION, mDescription);
         proto.write(NotificationChannelGroupProto.IS_BLOCKED, mBlocked);
         for (NotificationChannel channel : mChannels) {
-            channel.writeToProto(proto, NotificationChannelGroupProto.CHANNELS);
+            channel.dumpDebug(proto, NotificationChannelGroupProto.CHANNELS);
         }
         proto.end(token);
     }
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 03ee1e9..850645d 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1855,7 +1855,7 @@
         }
 
         /** @hide */
-        public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        public void dumpDebug(ProtoOutputStream proto, long fieldId) {
             final long pToken = proto.start(fieldId);
 
             bitwiseToProtoEnum(proto, PolicyProto.PRIORITY_CATEGORIES, priorityCategories);
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 06b9506..0407a8a 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -1204,7 +1204,7 @@
     }
 
     /** @hide */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         if (mTarget != null) {
             proto.write(PendingIntentProto.TARGET, mTarget.asBinder().toString());
diff --git a/core/java/android/app/ProfilerInfo.java b/core/java/android/app/ProfilerInfo.java
index 25589f8..d6eb4a8 100644
--- a/core/java/android/app/ProfilerInfo.java
+++ b/core/java/android/app/ProfilerInfo.java
@@ -135,7 +135,7 @@
     }
 
     /** @hide */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(ProfilerInfoProto.PROFILE_FILE, profileFile);
         if (profileFd != null) {
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
new file mode 100644
index 0000000..844e72e
--- /dev/null
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -0,0 +1,428 @@
+/*
+ * 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 android.annotation.NonNull;
+import android.os.SystemProperties;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * LRU cache that's invalidated when an opaque value in a property changes. Self-synchronizing,
+ * but doesn't hold a lock across data fetches on query misses.
+ *
+ * The intended use case is caching frequently-read, seldom-changed information normally
+ * retrieved across interprocess communication. Imagine that you've written a user birthday
+ * information daemon called "birthdayd" that exposes an {@code IUserBirthdayService} interface
+ * over binder. That binder interface looks something like this:
+ *
+ * <pre>
+ * parcelable Birthday {
+ *   int month;
+ *   int day;
+ * }
+ * interface IUserBirthdayService {
+ *   Birthday getUserBirthday(int userId);
+ * }
+ * </pre>
+ *
+ * Suppose the service implementation itself looks like this...
+ *
+ * <pre>
+ * public class UserBirthdayServiceImpl implements IUserBirthdayService {
+ *   private final HashMap<Integer, Birthday> mUidToBirthday;
+ *   @Override
+ *   public synchronized Birthday getUserBirthday(int userId) {
+ *     return mUidToBirthday.get(userId);
+ *   }
+ *   private synchronized void updateBirthdays(Map<Integer, Birthday> uidToBirthday) {
+ *     mUidToBirthday.clear();
+ *     mUidToBirthday.putAll(uidToBirthday);
+ *   }
+ * }
+ * </pre>
+ *
+ * ... and we have a client in frameworks (loaded into every app process) that looks
+ * like this:
+ *
+ * <pre>
+ * public class ActivityThread {
+ *   ...
+ *   public Birthday getUserBirthday(int userId) {
+ *     return GetService("birthdayd").getUserBirthday(userId);
+ *   }
+ *   ...
+ * }
+ * </pre>
+ *
+ * With this code, every time an app calls {@code getUserBirthday(uid)}, we make a binder call
+ * to the birthdayd process and consult its database of birthdays. If we query user birthdays
+ * frequently, we do a lot of work that we don't have to do, since user birthdays
+ * change infrequently.
+ *
+ * PropertyInvalidatedCache is part of a pattern for optimizing this kind of
+ * information-querying code. Using {@code PropertyInvalidatedCache}, you'd write the client
+ * this way:
+ *
+ * <pre>
+ * public class ActivityThread {
+ *   ...
+ *   private static final int BDAY_CACHE_MAX = 8;  // Maximum birthdays to cache
+ *   private static final String BDAY_CACHE_KEY = "cache_key.birthdayd";
+ *   private final PropertyInvalidatedCache<Integer, Birthday> mBirthdayCache = new
+ *     PropertyInvalidatedCache<Integer, Birthday>(BDAY_CACHE_MAX, BDAY_CACHE_KEY) {
+ *       @Override
+ *       protected Birthday recompute(Integer userId) {
+ *         return GetService("birthdayd").getUserBirthday(userId);
+ *       }
+ *     };
+ *   public void disableUserBirthdayCache() {
+ *     mBirthdayCache.disableLocal();
+ *   }
+ *   public void invalidateUserBirthdayCache() {
+ *     mBirthdayCache.invalidateCache();
+ *   }
+ *   public Birthday getUserBirthday(int userId) {
+ *     return mBirthdayCache.query(userId);
+ *   }
+ *   ...
+ * }
+ * </pre>
+ *
+ * With this cache, clients perform a binder call to birthdayd if asking for a user's birthday
+ * for the first time; on subsequent queries, we return the already-known Birthday object.
+ *
+ * User birthdays do occasionally change, so we have to modify the server to invalidate this
+ * cache when necessary. That invalidation code looks like this:
+ *
+ * <pre>
+ * public class UserBirthdayServiceImpl {
+ *   ...
+ *   public UserBirthdayServiceImpl() {
+ *     ...
+ *     ActivityThread.currentActivityThread().disableUserBirthdayCache();
+ *     ActivityThread.currentActivityThread().invalidateUserBirthdayCache();
+ *   }
+ *
+ *   private synchronized void updateBirthdays(Map<Integer, Birthday> uidToBirthday) {
+ *     mUidToBirthday.clear();
+ *     mUidToBirthday.putAll(uidToBirthday);
+ *     ActivityThread.currentActivityThread().invalidateUserBirthdayCache();
+ *   }
+ *   ...
+ * }
+ * </pre>
+ *
+ * The call to {@code PropertyInvalidatedCache.invalidateCache()} guarantees that all clients
+ * will re-fetch birthdays from binder during consequent calls to
+ * {@code ActivityThread.getUserBirthday()}. Because the invalidate call happens with the lock
+ * held, we maintain consistency between different client views of the birthday state. The use
+ * of PropertyInvalidatedCache in this idiomatic way introduces no new race conditions.
+ *
+ * PropertyInvalidatedCache has a few other features for doing things like incremental
+ * enhancement of cached values and invalidation of multiple caches (that all share the same
+ * property key) at once.
+ *
+ * {@code BDAY_CACHE_KEY} is the name of a property that we set to an opaque unique value each
+ * time we update the cache. SELinux configuration must allow everyone to read this property
+ * and it must allow any process that needs to invalidate the cache (here, birthdayd) to write
+ * the property. (These properties conventionally begin with the "cache_key." prefix.)
+ *
+ * The {@code UserBirthdayServiceImpl} constructor calls {@code disableUserBirthdayCache()} so
+ * that calls to {@code getUserBirthday} from inside birthdayd don't go through the cache. In
+ * this local case, there's no IPC, so use of the cache is (depending on exact
+ * circumstance) unnecessary.
+ *
+ * @param <Query> The class used to index cache entries: must be hashable and comparable
+ * @param <Result> The class holding cache entries; use a boxed primitive if possible
+ *
+ * {@hide}
+ */
+public abstract class PropertyInvalidatedCache<Query, Result> {
+    private static final long NONCE_UNSET = 0;
+    private static final long NONCE_DISABLED = -1;
+
+    private static final String TAG = "PropertyInvalidatedCache";
+    private static final boolean DEBUG = false;
+    private static final boolean ENABLE = true;
+
+    private final Object mLock = new Object();
+
+    /**
+     * Name of the property that holds the unique value that we use to invalidate the cache.
+     */
+    private final String mPropertyName;
+
+    /**
+     * Handle to the {@code mPropertyName} property, transitioning to non-{@code null} once the
+     * property exists on the system.
+     */
+    private volatile SystemProperties.Handle mPropertyHandle;
+
+    @GuardedBy("mLock")
+    private final LinkedHashMap<Query, Result> mCache;
+
+    /**
+     * The last value of the {@code mPropertyHandle} that we observed.
+     */
+    @GuardedBy("mLock")
+    private long mLastSeenNonce = NONCE_UNSET;
+
+    /**
+     * Whether we've disabled the cache in this process.
+     */
+    private boolean mDisabled = false;
+
+    /**
+     * Make a new property invalidated cache.
+     *
+     * @param maxEntries Maximum number of entries to cache; LRU discard
+     * @param propertyName Name of the system property holding the cache invalidation nonce
+     */
+    public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName) {
+        mPropertyName = propertyName;
+        mCache = new LinkedHashMap<Query, Result>(
+            2 /* start small */,
+            0.75f /* default load factor */,
+            true /* LRU access order */) {
+                @Override
+                protected boolean removeEldestEntry(Map.Entry eldest) {
+                    return size() > maxEntries;
+                }
+            };
+    }
+
+    /**
+     * Forget all cached values.
+     */
+    public final void clear() {
+        synchronized (mLock) {
+            mCache.clear();
+        }
+    }
+
+    /**
+     * Fetch a result from scratch in case it's not in the cache at all.  Called unlocked: may
+     * block. If this function returns null, the result of the cache query is null. There is no
+     * "negative cache" in the query: we don't cache null results at all.
+     */
+    protected abstract Result recompute(Query query);
+
+    /**
+     * Make result up-to-date on a cache hit.  Called unlocked;
+     * may block.
+     *
+     * Return either 1) oldResult itself (the same object, by reference equality), in which
+     * case we just return oldResult as the result of the cache query, 2) a new object, which
+     * replaces oldResult in the cache and which we return as the result of the cache query
+     * after performing another property read to make sure that the result hasn't changed in
+     * the meantime (if the nonce has changed in the meantime, we drop the cache and try the
+     * whole query again), or 3) null, which causes the old value to be removed from the cache
+     * and null to be returned as the result of the cache query.
+     */
+    protected Result refresh(Result oldResult, Query query) {
+        return oldResult;
+    }
+
+    private long getCurrentNonce() {
+        SystemProperties.Handle handle = mPropertyHandle;
+        if (handle == null) {
+            handle = SystemProperties.find(mPropertyName);
+            if (handle == null) {
+                return NONCE_UNSET;
+            }
+            mPropertyHandle = handle;
+        }
+        return handle.getLong(NONCE_UNSET);
+    }
+
+    /**
+     * Disable the use of this cache in this process.
+     */
+    public final void disableLocal() {
+        synchronized (mLock) {
+            mDisabled = true;
+            mCache.clear();
+        }
+    }
+
+    /**
+     * Return whether the cache is disabled in this process.
+     */
+    public final boolean isDisabledLocal() {
+        return mDisabled;
+    }
+
+    /**
+     * Get a value from the cache or recompute it.
+     */
+    public Result query(Query query) {
+        // Let access to mDisabled race: it's atomic anyway.
+        long currentNonce = (ENABLE && !mDisabled) ? getCurrentNonce() : NONCE_DISABLED;
+        for (;;) {
+            if (currentNonce == NONCE_DISABLED || currentNonce == NONCE_UNSET) {
+                if (DEBUG) {
+                    Log.d(TAG,
+                            String.format("cache %s for %s",
+                                currentNonce == NONCE_DISABLED ? "disabled" : "unset",
+                                query));
+                }
+                return recompute(query);
+            }
+            final Result cachedResult;
+            synchronized (mLock) {
+                if (currentNonce == mLastSeenNonce) {
+                    cachedResult = mCache.get(query);
+                } else {
+                    if (DEBUG) {
+                        Log.d(TAG,
+                                String.format("clearing cache because nonce changed [%s] -> [%s]",
+                                        mLastSeenNonce, currentNonce));
+                    }
+                    mCache.clear();
+                    mLastSeenNonce = currentNonce;
+                    cachedResult = null;
+                }
+            }
+            // Cache hit --- but we're not quite done yet.  A value in the cache might need to
+            // be augmented in a "refresh" operation.  The refresh operation can combine the
+            // old and the new nonce values.  In order to make sure the new parts of the value
+            // are consistent with the old, possibly-reused parts, we check the property value
+            // again after the refresh and do the whole fetch again if the property invalidated
+            // us while we were refreshing.
+            if (cachedResult != null) {
+                final Result refreshedResult = refresh(cachedResult, query);
+                if (refreshedResult != cachedResult) {
+                    if (DEBUG) {
+                        Log.d(TAG, "cache refresh for " + query);
+                    }
+                    final long afterRefreshNonce = getCurrentNonce();
+                    if (currentNonce != afterRefreshNonce) {
+                        currentNonce = afterRefreshNonce;
+                        if (DEBUG) {
+                            Log.d(TAG, "restarting query because nonce changed in refresh");
+                        }
+                        continue;
+                    }
+                    synchronized (mLock) {
+                        if (currentNonce != mLastSeenNonce) {
+                            // Do nothing: cache is already out of date. Just return the value
+                            // we already have: there's no guarantee that the contents of mCache
+                            // won't become invalid as soon as we return.
+                        } else if (refreshedResult == null) {
+                            mCache.remove(query);
+                        } else {
+                            mCache.put(query, refreshedResult);
+                        }
+                    }
+                    return refreshedResult;
+                }
+                if (DEBUG) {
+                    Log.d(TAG, "cache hit for " + query);
+                }
+                return cachedResult;
+            }
+            // Cache miss: make the value from scratch.
+            if (DEBUG) {
+                Log.d(TAG, "cache miss for " + query);
+            }
+            final Result result = recompute(query);
+            synchronized (mLock) {
+                // If someone else invalidated the cache while we did the recomputation, don't
+                // update the cache with a potentially stale result.
+                if (mLastSeenNonce == currentNonce && result != null) {
+                    mCache.put(query, result);
+                }
+            }
+            return result;
+        }
+    }
+
+    // Inner class avoids initialization in processes that don't do any invalidation
+    private static final class NoPreloadHolder {
+        private static final AtomicLong sNextNonce = new AtomicLong((new Random()).nextLong());
+        public static long next() {
+            return sNextNonce.getAndIncrement();
+        }
+    }
+
+    /**
+     * Non-static convenience version of disableSystemWide() for situations in which only a
+     * single PropertyInvalidatedCache is keyed on a particular property value.
+     *
+     * When multiple caches share a single property value, using an instance method on one of
+     * the cache objects to invalidate all of the cache objects becomes confusing and you should
+     * just use the static version of this function.
+     */
+    public final void disableSystemWide() {
+        disableSystemWide(mPropertyName);
+    }
+
+    /**
+     * Disable all caches system-wide that are keyed on {@var name}. This
+     * function is synchronous: caches are invalidated and disabled upon return.
+     *
+     * @param name Name of the cache-key property to invalidate
+     */
+    public static void disableSystemWide(@NonNull String name) {
+        SystemProperties.set(name, Long.toString(NONCE_DISABLED));
+    }
+
+    /**
+     * Non-static convenience version of invalidateCache() for situations in which only a single
+     * PropertyInvalidatedCache is keyed on a particular property value.
+     */
+    public final void invalidateCache() {
+        invalidateCache(mPropertyName);
+    }
+
+    /**
+     * Invalidate PropertyInvalidatedCache caches in all processes that are keyed on
+     * {@var name}. This function is synchronous: caches are invalidated upon return.
+     *
+     * @param name Name of the cache-key property to invalidate
+     */
+    public static void invalidateCache(@NonNull String name) {
+        // There's no race here: we don't require that values strictly increase, but instead
+        // only that each is unique in a single runtime-restart session.
+        final long nonce = SystemProperties.getLong(name, NONCE_UNSET);
+        if (nonce == NONCE_DISABLED) {
+            if (DEBUG) {
+                Log.d(TAG, "refusing to invalidate disabled cache: " + name);
+            }
+            return;
+        }
+        long newValue;
+        do {
+            newValue = NoPreloadHolder.next();
+        } while (newValue == NONCE_UNSET || newValue == NONCE_DISABLED);
+        final String newValueString = Long.toString(newValue);
+        if (DEBUG) {
+            Log.d(TAG,
+                    String.format("invalidating cache [%s]: [%s] -> [%s]",
+                            name,
+                            nonce,
+                            newValueString));
+        }
+        SystemProperties.set(name, newValueString);
+    }
+}
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 1f91b3f..9b62e3b 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -57,7 +57,7 @@
  * networking) operations, it should spawn its own thread in which to do that
  * work.  More information on this can be found in
  * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html">Processes and
- * Threads</a>.  The {@link IntentService} class is available
+ * Threads</a>.  The {@link androidx.core.app.JobIntentService} class is available
  * as a standard implementation of Service that has its own thread where it
  * schedules its work to be done.</p>
  * 
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index 11d6528a..90cd51f 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -34,6 +34,7 @@
 import android.util.AndroidException;
 import android.util.Slog;
 import android.util.StatsEvent;
+import android.util.StatsEventParcel;
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -51,12 +52,13 @@
     private static final String TAG = "StatsManager";
     private static final boolean DEBUG = false;
 
+    private static final Object sLock = new Object();
     private final Context mContext;
 
-    @GuardedBy("this")
+    @GuardedBy("sLock")
     private IStatsManager mService;
 
-    @GuardedBy("this")
+    @GuardedBy("sLock")
     private IStatsCompanionService mStatsCompanion;
 
     /**
@@ -125,7 +127,7 @@
      */
     @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
     public void addConfig(long configKey, byte[] config) throws StatsUnavailableException {
-        synchronized (this) {
+        synchronized (sLock) {
             try {
                 IStatsManager service = getIStatsManagerLocked();
                 // can throw IllegalArgumentException
@@ -162,7 +164,7 @@
      */
     @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
     public void removeConfig(long configKey) throws StatsUnavailableException {
-        synchronized (this) {
+        synchronized (sLock) {
             try {
                 IStatsManager service = getIStatsManagerLocked();
                 service.removeConfiguration(configKey, mContext.getOpPackageName());
@@ -223,7 +225,7 @@
     public void setBroadcastSubscriber(
             PendingIntent pendingIntent, long configKey, long subscriberId)
             throws StatsUnavailableException {
-        synchronized (this) {
+        synchronized (sLock) {
             try {
                 IStatsManager service = getIStatsManagerLocked();
                 if (pendingIntent != null) {
@@ -277,7 +279,7 @@
     @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
     public void setFetchReportsOperation(PendingIntent pendingIntent, long configKey)
             throws StatsUnavailableException {
-        synchronized (this) {
+        synchronized (sLock) {
             try {
                 IStatsManager service = getIStatsManagerLocked();
                 if (pendingIntent == null) {
@@ -315,7 +317,7 @@
     @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
     public @NonNull long[] setActiveConfigsChangedOperation(@Nullable PendingIntent pendingIntent)
             throws StatsUnavailableException {
-        synchronized (this) {
+        synchronized (sLock) {
             try {
                 IStatsManager service = getIStatsManagerLocked();
                 if (pendingIntent == null) {
@@ -363,7 +365,7 @@
      */
     @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
     public byte[] getReports(long configKey) throws StatsUnavailableException {
-        synchronized (this) {
+        synchronized (sLock) {
             try {
                 IStatsManager service = getIStatsManagerLocked();
                 return service.getData(configKey, mContext.getOpPackageName());
@@ -400,7 +402,7 @@
      */
     @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
     public byte[] getStatsMetadata() throws StatsUnavailableException {
-        synchronized (this) {
+        synchronized (sLock) {
             try {
                 IStatsManager service = getIStatsManagerLocked();
                 return service.getMetadata(mContext.getOpPackageName());
@@ -435,7 +437,7 @@
     @RequiresPermission(allOf = {DUMP, PACKAGE_USAGE_STATS})
     public long[] getRegisteredExperimentIds()
             throws StatsUnavailableException {
-        synchronized (this) {
+        synchronized (sLock) {
             try {
                 IStatsManager service = getIStatsManagerLocked();
                 if (service == null) {
@@ -472,7 +474,7 @@
     @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
     public void setPullerCallback(int atomTag, IStatsPullerCallback callback)
             throws StatsUnavailableException {
-        synchronized (this) {
+        synchronized (sLock) {
             try {
                 IStatsManager service = getIStatsManagerLocked();
                 if (callback == null) {
@@ -515,7 +517,7 @@
         if (additiveFields == null) {
             additiveFields = new int[0];
         }
-        synchronized (this) {
+        synchronized (sLock) {
             IStatsCompanionService service = getIStatsCompanionServiceLocked();
             PullAtomCallbackInternal rec =
                     new PullAtomCallbackInternal(atomTag, callback, executor);
@@ -539,10 +541,12 @@
             mExecutor.execute(() -> {
                 List<StatsEvent> data = new ArrayList<>();
                 boolean success = mCallback.onPullAtom(atomTag, data);
-                StatsEvent[] arr = new StatsEvent[data.size()];
-                arr = data.toArray(arr);
+                StatsEventParcel[] parcels = new StatsEventParcel[data.size()];
+                for (int i = 0; i < data.size(); i++) {
+                    parcels[i].buffer = data.get(i).getBytes();
+                }
                 try {
-                    resultReceiver.pullFinished(atomTag, success, arr);
+                    resultReceiver.pullFinished(atomTag, success, parcels);
                 } catch (RemoteException e) {
                     Slog.w(TAG, "StatsPullResultReceiver failed for tag " + mAtomId);
                 }
@@ -649,13 +653,13 @@
     private class StatsdDeathRecipient implements IBinder.DeathRecipient {
         @Override
         public void binderDied() {
-            synchronized (this) {
+            synchronized (sLock) {
                 mService = null;
             }
         }
     }
 
-    @GuardedBy("this")
+    @GuardedBy("sLock")
     private IStatsManager getIStatsManagerLocked() throws StatsUnavailableException {
         if (mService != null) {
             return mService;
@@ -672,7 +676,7 @@
         return mService;
     }
 
-    @GuardedBy("this")
+    @GuardedBy("sLock")
     private IStatsCompanionService getIStatsCompanionServiceLocked() {
         if (mStatsCompanion != null) {
             return mStatsCompanion;
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 0bfd2c6..601b658 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -19,6 +19,7 @@
 import android.accounts.AccountManager;
 import android.accounts.IAccountManager;
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.app.ContextImpl.ServiceInitializationState;
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.IDevicePolicyManager;
@@ -33,6 +34,7 @@
 import android.app.slice.SliceManager;
 import android.app.timedetector.TimeDetector;
 import android.app.timezone.RulesManager;
+import android.app.timezonedetector.TimeZoneDetector;
 import android.app.trust.TrustManager;
 import android.app.usage.IStorageStatsManager;
 import android.app.usage.IUsageStatsManager;
@@ -193,6 +195,7 @@
  *
  * @hide
  */
+@SystemApi
 public final class SystemServiceRegistry {
     private static final String TAG = "SystemServiceRegistry";
 
@@ -1123,10 +1126,19 @@
                         return new TimeDetector();
                     }});
 
+        registerService(Context.TIME_ZONE_DETECTOR_SERVICE, TimeZoneDetector.class,
+                new CachedServiceFetcher<TimeZoneDetector>() {
+                    @Override
+                    public TimeZoneDetector createService(ContextImpl ctx)
+                            throws ServiceNotFoundException {
+                        return new TimeZoneDetector();
+                    }});
+
         registerService(Context.PERMISSION_SERVICE, PermissionManager.class,
                 new CachedServiceFetcher<PermissionManager>() {
                     @Override
-                    public PermissionManager createService(ContextImpl ctx) {
+                    public PermissionManager createService(ContextImpl ctx)
+                            throws ServiceNotFoundException {
                         IPackageManager packageManager = AppGlobals.getPackageManager();
                         return new PermissionManager(ctx.getOuterContext(), packageManager);
                     }});
@@ -1191,7 +1203,6 @@
         try {
             // Note: the following functions need to be @SystemApis, once they become mainline
             // modules.
-
             JobSchedulerFrameworkInitializer.registerServiceWrappers();
             BlobStoreManagerFrameworkInitializer.initialize();
             TelephonyFrameworkInitializer.registerServiceWrappers();
@@ -1246,18 +1257,20 @@
 
     /**
      * Callback interface used as a parameter to {@link #registerStaticService(
-     * String, Class, StaticServiceProducerNoBinder)}, which generates a service wrapper instance
-     * that's not tied to any context and does not take a service binder object in the constructor.
+     * String, Class, StaticServiceProducerWithoutBinder)}, which generates a service wrapper
+     * instance that's not tied to any context and does not take a service binder object in the
+     * constructor.
      *
      * @param <TServiceClass> type of the service wrapper class.
      *
      * @hide
      */
-    //@SystemApi TODO Make it a system API.
-    public interface StaticServiceProducerNoBinder<TServiceClass> {
+    @SystemApi
+    public interface StaticServiceProducerWithoutBinder<TServiceClass> {
         /**
          * Return a new service wrapper of type {@code TServiceClass}.
          */
+        @NonNull
         TServiceClass createService();
     }
 
@@ -1270,18 +1283,19 @@
      *
      * @hide
      */
-    //@SystemApi TODO Make it a system API.
+    @SystemApi
     public interface StaticServiceProducerWithBinder<TServiceClass> {
         /**
          * Return a new service wrapper of type {@code TServiceClass} backed by a given
          * service binder object.
          */
-        TServiceClass createService(IBinder serviceBinder);
+        @NonNull
+        TServiceClass createService(@NonNull IBinder serviceBinder);
     }
 
     /**
      * Callback interface used as a parameter to {@link #registerContextAwareService(
-     * String, Class, ContextAwareServiceProducerNoBinder)},
+     * String, Class, ContextAwareServiceProducerWithoutBinder)},
      * which generates a service wrapper instance
      * that's tied to a specific context and does not take a service binder object in the
      * constructor.
@@ -1290,15 +1304,15 @@
      *
      * @hide
      */
-    //@SystemApi TODO Make it a system API.
-    public interface ContextAwareServiceProducerNoBinder<TServiceClass> {
+    @SystemApi
+    public interface ContextAwareServiceProducerWithoutBinder<TServiceClass> {
         /**
          * Return a new service wrapper of type {@code TServiceClass} tied to a given
          * {@code context}.
-         *
-         * TODO Do we need to pass the "base context" too?
          */
-        TServiceClass createService(Context context);
+        @NonNull
+        //TODO Do we need to pass the "base context" too?
+        TServiceClass createService(@NonNull Context context);
     }
 
     /**
@@ -1311,15 +1325,15 @@
      *
      * @hide
      */
-    //@SystemApi TODO Make it a system API.
+    @SystemApi
     public interface ContextAwareServiceProducerWithBinder<TServiceClass> {
         /**
          * Return a new service wrapper of type {@code TServiceClass} backed by a given
          * service binder object that's tied to a given {@code context}.
-         *
-         * TODO Do we need to pass the "base context" too?
          */
-        TServiceClass createService(Context context, IBinder serviceBinder);
+        @NonNull
+        //TODO Do we need to pass the "base context" too?
+        TServiceClass createService(@NonNull Context context, @NonNull IBinder serviceBinder);
     }
 
     /**
@@ -1337,7 +1351,7 @@
      *
      * @hide
      */
-    //@SystemApi TODO Make it a system API.
+    @SystemApi
     public static <TServiceClass> void registerStaticService(
             @NonNull String serviceName, @NonNull Class<TServiceClass> serviceWrapperClass,
             @NonNull StaticServiceProducerWithBinder<TServiceClass> serviceProducer) {
@@ -1361,10 +1375,10 @@
      *
      * @hide
      */
-    //@SystemApi TODO Make it a system API.
+    @SystemApi
     public static <TServiceClass> void registerStaticService(
             @NonNull String serviceName, @NonNull Class<TServiceClass> serviceWrapperClass,
-            @NonNull StaticServiceProducerNoBinder<TServiceClass> serviceProducer) {
+            @NonNull StaticServiceProducerWithoutBinder<TServiceClass> serviceProducer) {
         ensureInitializing("registerStaticService");
         Preconditions.checkStringNotEmpty(serviceName);
         Preconditions.checkNotNull(serviceWrapperClass);
@@ -1394,7 +1408,7 @@
      *
      * @hide
      */
-    //@SystemApi TODO Make it a system API.
+    @SystemApi
     public static <TServiceClass> void registerContextAwareService(
             @NonNull String serviceName, @NonNull Class<TServiceClass> serviceWrapperClass,
             @NonNull ContextAwareServiceProducerWithBinder<TServiceClass> serviceProducer) {
@@ -1422,10 +1436,10 @@
      *
      * @hide
      */
-    //@SystemApi TODO Make it a system API.
+    @SystemApi
     public static <TServiceClass> void registerContextAwareService(
             @NonNull String serviceName, @NonNull Class<TServiceClass> serviceWrapperClass,
-            @NonNull ContextAwareServiceProducerNoBinder<TServiceClass> serviceProducer) {
+            @NonNull ContextAwareServiceProducerWithoutBinder<TServiceClass> serviceProducer) {
         ensureInitializing("registerContextAwareService");
         Preconditions.checkStringNotEmpty(serviceName);
         Preconditions.checkNotNull(serviceWrapperClass);
diff --git a/core/java/android/app/TaskEmbedder.java b/core/java/android/app/TaskEmbedder.java
index a8dc7bc..79d88fd 100644
--- a/core/java/android/app/TaskEmbedder.java
+++ b/core/java/android/app/TaskEmbedder.java
@@ -25,9 +25,12 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutInfo;
 import android.graphics.Insets;
 import android.graphics.Matrix;
 import android.graphics.Point;
+import android.graphics.Rect;
 import android.graphics.Region;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.VirtualDisplay;
@@ -346,6 +349,26 @@
     }
 
     /**
+     * Launch an activity represented by {@link ShortcutInfo} into this container.
+     * <p>The owner of this container must be allowed to access the shortcut information,
+     * as defined in {@link LauncherApps#hasShortcutHostPermission()} to use this method.
+     *
+     * @param shortcut the shortcut used to launch the activity.
+     * @param options options for the activity.
+     * @param sourceBounds the rect containing the source bounds of the clicked icon to open
+     *                     this shortcut.
+     *
+     * @see #startActivity(Intent)
+     */
+    public void startShortcutActivity(@NonNull ShortcutInfo shortcut,
+            @NonNull ActivityOptions options, @Nullable Rect sourceBounds) {
+        LauncherApps service =
+                (LauncherApps) mContext.getSystemService(Context.LAUNCHER_APPS_SERVICE);
+        options.setLaunchDisplayId(mVirtualDisplay.getDisplay().getDisplayId());
+        service.startShortcut(shortcut, sourceBounds, options.toBundle());
+    }
+
+    /**
      * Check if container is ready to launch and create {@link ActivityOptions} to target the
      * virtual display.
      */
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 8cb094f..aa6492e 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -615,15 +615,15 @@
      * @param fieldId           Field Id of the WindowConfiguration as defined in the parent message
      * @hide
      */
-    public void writeToProto(ProtoOutputStream protoOutputStream, long fieldId) {
+    public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId) {
         final long token = protoOutputStream.start(fieldId);
         if (mAppBounds != null) {
-            mAppBounds.writeToProto(protoOutputStream, APP_BOUNDS);
+            mAppBounds.dumpDebug(protoOutputStream, APP_BOUNDS);
         }
         protoOutputStream.write(WINDOWING_MODE, mWindowingMode);
         protoOutputStream.write(ACTIVITY_TYPE, mActivityType);
         if (mBounds != null) {
-            mBounds.writeToProto(protoOutputStream, BOUNDS);
+            mBounds.dumpDebug(protoOutputStream, BOUNDS);
         }
         protoOutputStream.end(token);
     }
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index 00903c4..63bc40b 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -55,6 +55,14 @@
     static final String TAG = "DeviceAdminInfo";
 
     /**
+     * A type of policy that this device admin can use: profile owner on an organization-owned
+     * device.
+     *
+     * @hide
+     */
+    public static final int USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER = -3;
+
+    /**
      * A type of policy that this device admin can use: device owner meta-policy
      * for an admin that is designated as owner of the device.
      *
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 73980a5..915e457 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3742,17 +3742,35 @@
     /**
      * Force a new password for device unlock (the password needed to access the entire device) or
      * the work profile challenge on the current user. This takes effect immediately.
-     * <p>
-     * <em>For device owner and profile owners targeting SDK level
-     * {@link android.os.Build.VERSION_CODES#O} or above, this API is no longer available and will
-     * throw {@link SecurityException}. Please use the new API {@link #resetPasswordWithToken}
-     * instead. </em>
-     * <p>
-     * <em>Note: This API has been limited as of {@link android.os.Build.VERSION_CODES#N} for
-     * device admins that are not device owner and not profile owner.
-     * The password can now only be changed if there is currently no password set.  Device owner
-     * and profile owner can still do this when user is unlocked and does not have a managed
-     * profile.</em>
+     *
+     * <p> Before {@link android.os.Build.VERSION_CODES#N}, this API is available to device admin,
+     * profile owner and device owner. Starting from {@link android.os.Build.VERSION_CODES#N},
+     * legacy device admin (who is not also profile owner or device owner) can only call this
+     * API to set a new password if there is currently no password set. Profile owner and device
+     * owner can continue to force change an existing password as long as the target user is
+     * unlocked, although device owner will not be able to call this API at all if there is also a
+     * managed profile on the device.
+     *
+     * <p> Between {@link android.os.Build.VERSION_CODES#O},
+     * {@link android.os.Build.VERSION_CODES#P} and {@link android.os.Build.VERSION_CODES#Q},
+     * profile owner and devices owner targeting SDK level {@link android.os.Build.VERSION_CODES#O}
+     * or above who attempt to call this API will receive {@link SecurityException}; they are
+     * encouraged to migrate to the new {@link #resetPasswordWithToken} API instead.
+     * Profile owner and device owner targeting older SDK levels are not affected: they continue
+     * to experience the existing behaviour described in the previous paragraph.
+     *
+     * <p><em>Starting from {@link android.os.Build.VERSION_CODES#R}, this API is no longer
+     * supported in most cases.</em> Device owner and profile owner calling
+     * this API will receive {@link SecurityException} if they target SDK level
+     * {@link android.os.Build.VERSION_CODES#O} or above, or they will receive a silent failure
+     * (API returning {@code false}) if they target lower SDK level.
+     * For legacy device admins, this API throws {@link SecurityException} if they target SDK level
+     * {@link android.os.Build.VERSION_CODES#N} or above, and returns {@code false} otherwise. Only
+     * privileged apps holding RESET_PASSWORD permission which are part of
+     * the system factory image can still call this API to set a new password if there is currently
+     * no password set. In this case, if the device already has a password, this API will throw
+     * {@link SecurityException}.
+     *
      * <p>
      * The given password must be sufficient for the current password quality and length constraints
      * as returned by {@link #getPasswordQuality(ComponentName)} and
@@ -3760,12 +3778,7 @@
      * it will be rejected and false returned. Note that the password may be a stronger quality
      * (containing alphanumeric characters when the requested quality is only numeric), in which
      * case the currently active quality will be increased to match.
-     * <p>
-     * Calling with a null or empty password will clear any existing PIN, pattern or password if the
-     * current password constraints allow it. <em>Note: This will not work in
-     * {@link android.os.Build.VERSION_CODES#N} and later for managed profiles, or for device admins
-     * that are not device owner or profile owner.  Once set, the password cannot be changed to null
-     * or empty except by these admins.</em>
+     *
      * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, this
      * methods does nothing.
      * <p>
@@ -3777,11 +3790,13 @@
      * @param flags May be 0 or combination of {@link #RESET_PASSWORD_REQUIRE_ENTRY} and
      *            {@link #RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT}.
      * @return Returns true if the password was applied, or false if it is not acceptable for the
-     *         current constraints or if the user has not been decrypted yet.
+     *         current constraints.
      * @throws SecurityException if the calling application does not own an active administrator
      *             that uses {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD}
      * @throws IllegalStateException if the calling user is locked or has a managed profile.
+     * @deprecated Please use {@link #resetPasswordWithToken} instead.
      */
+    @Deprecated
     @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
     public boolean resetPassword(String password, int flags) {
         throwIfParentInstance("resetPassword");
@@ -5001,14 +5016,15 @@
      * <p>Device owner, profile owner and their delegated certificate installer can use
      * {@link #ID_TYPE_BASE_INFO} to request inclusion of the general device information
      * including manufacturer, model, brand, device and product in the attestation record.
-     * Only device owner and their delegated certificate installer can use
-     * {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI} and {@link #ID_TYPE_MEID} to request
-     * unique device identifiers to be attested (the serial number, IMEI and MEID correspondingly),
-     * if supported by the device (see {@link #isDeviceIdAttestationSupported()}).
-     * Additionally, device owner and their delegated certificate installer can also request the
-     * attestation record to be signed using an individual attestation certificate by specifying
-     * the {@link #ID_TYPE_INDIVIDUAL_ATTESTATION} flag (if supported by the device, see
-     * {@link #isUniqueDeviceAttestationSupported()}).
+     * Only device owner, profile owner on an organization-owned device and their delegated
+     * certificate installers can use {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI} and
+     * {@link #ID_TYPE_MEID} to request unique device identifiers to be attested (the serial number,
+     * IMEI and MEID correspondingly), if supported by the device
+     * (see {@link #isDeviceIdAttestationSupported()}).
+     * Additionally, device owner, profile owner on an organization-owned device and their delegated
+     * certificate installers can also request the attestation record to be signed using an
+     * individual attestation certificate by specifying the {@link #ID_TYPE_INDIVIDUAL_ATTESTATION}
+     * flag (if supported by the device, see {@link #isUniqueDeviceAttestationSupported()}).
      * <p>
      * If any of {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI} and {@link #ID_TYPE_MEID}
      * is set, it is implicitly assumed that {@link #ID_TYPE_BASE_INFO} is also set.
@@ -5554,7 +5570,12 @@
      * device, for this user. After setting this, no applications running as this user will be able
      * to access any cameras on the device.
      * <p>
-     * If the caller is device owner, then the restriction will be applied to all users.
+     * This method can be called on the {@link DevicePolicyManager} instance,
+     * returned by {@link #getParentProfileInstance(ComponentName)}, where the caller must be
+     * the profile owner of an organization-owned managed profile.
+     * <p>
+     * If the caller is device owner or called on the parent instance, then the
+     * restriction will be applied to all users.
      * <p>
      * The calling device admin must have requested
      * {@link DeviceAdminInfo#USES_POLICY_DISABLE_CAMERA} to be able to call this method; if it has
@@ -5566,10 +5587,9 @@
      *             {@link DeviceAdminInfo#USES_POLICY_DISABLE_CAMERA}.
      */
     public void setCameraDisabled(@NonNull ComponentName admin, boolean disabled) {
-        throwIfParentInstance("setCameraDisabled");
         if (mService != null) {
             try {
-                mService.setCameraDisabled(admin, disabled);
+                mService.setCameraDisabled(admin, disabled, mParentInstance);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -5579,11 +5599,15 @@
     /**
      * Determine whether or not the device's cameras have been disabled for this user,
      * either by the calling admin, if specified, or all admins.
+     * <p>
+     * This method can be called on the {@link DevicePolicyManager} instance,
+     * returned by {@link #getParentProfileInstance(ComponentName)}, where the caller must be
+     * the profile owner of an organization-owned managed profile.
+     *
      * @param admin The name of the admin component to check, or {@code null} to check whether any admins
      * have disabled the camera
      */
     public boolean getCameraDisabled(@Nullable ComponentName admin) {
-        throwIfParentInstance("getCameraDisabled");
         return getCameraDisabled(admin, myUserId());
     }
 
@@ -5592,7 +5616,7 @@
     public boolean getCameraDisabled(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getCameraDisabled(admin, userHandle);
+                return mService.getCameraDisabled(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -5696,11 +5720,21 @@
      * <p>
      * The calling device admin must be a device owner, or alternatively a profile owner from
      * Android 8.0 (API level 26) or higher. If it is not, a security exception will be thrown.
+     * <p>
+     * Staring from Android 11, this API switches to use
+     * {@link UserManager#DISALLOW_CONFIG_DATE_TIME} to enforce the auto time settings. Calling
+     * this API to enforce auto time will result in
+     * {@link UserManager#DISALLOW_CONFIG_DATE_TIME} being set, while calling this API to lift
+     * the requirement will result in {@link UserManager#DISALLOW_CONFIG_DATE_TIME} being cleared.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param required Whether auto time is set required or not.
      * @throws SecurityException if {@code admin} is not a device owner.
+     * @deprecated From {@link android.os.Build.VERSION_CODES#R}. Use {@link #setAutoTime}
+     * to turn auto time on or off and use {@link UserManager#DISALLOW_CONFIG_DATE_TIME}
+     * to prevent the user from changing this setting.
      */
+    @Deprecated
     public void setAutoTimeRequired(@NonNull ComponentName admin, boolean required) {
         throwIfParentInstance("setAutoTimeRequired");
         if (mService != null) {
@@ -5714,7 +5748,9 @@
 
     /**
      * @return true if auto time is required.
+     * @deprecated From {@link android.os.Build.VERSION_CODES#R}. Use {@link #getAutoTime}
      */
+    @Deprecated
     public boolean getAutoTimeRequired() {
         throwIfParentInstance("getAutoTimeRequired");
         if (mService != null) {
@@ -5728,6 +5764,47 @@
     }
 
     /**
+     * Called by a device owner, a profile owner for the primary user or a profile
+     * owner of an organization-owned managed profile to turn auto time on and off.
+     * Callers are recommended to use {@link UserManager#DISALLOW_CONFIG_DATE_TIME}
+     * to prevent the user from changing this setting.
+     * <p>
+     * If user restriction {@link UserManager#DISALLOW_CONFIG_DATE_TIME} is used,
+     * no user will be able set the date and time. Instead, the network date
+     * and time will be used.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param enabled Whether time should be obtained automatically from the network or not.
+     * @throws SecurityException if caller is not a device owner, a profile owner for the
+     * primary user, or a profile owner of an organization-owned managed profile.
+     */
+    public void setAutoTime(@NonNull ComponentName admin, boolean enabled) {
+        if (mService != null) {
+            try {
+                mService.setAutoTime(admin, enabled);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * @return true if auto time is enabled on the device.
+     * @throws SecurityException if caller is not a device owner, a profile owner for the
+     * primary user, or a profile owner of an organization-owned managed profile.
+     */
+    public boolean getAutoTime(@NonNull ComponentName admin) {
+        if (mService != null) {
+            try {
+                return mService.getAutoTime(admin);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return false;
+    }
+
+    /**
      * Called by a device owner to set whether all users created on the device should be ephemeral.
      * <p>
      * The system user is exempt from this policy - it is never ephemeral.
@@ -6363,6 +6440,9 @@
     /**
      * Sets the device owner information to be shown on the lock screen.
      * <p>
+     * Device owner information set using this method overrides any owner information manually set
+     * by the user and prevents the user from further changing it.
+     * <p>
      * If the device owner information is {@code null} or empty then the device owner info is
      * cleared and the user owner info is shown on the lock screen if it is set.
      * <p>
@@ -6372,6 +6452,8 @@
      * If the device owner information needs to be localized, it is the responsibility of the
      * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
      * and set a new version of this string accordingly.
+     * <p>
+     * May be called by the device owner or the profile owner of an organization-owned device.
      *
      * @param admin The name of the admin component to check.
      * @param info Device owner information which will be displayed instead of the user owner info.
@@ -7834,7 +7916,8 @@
      *            for the list of keys.
      * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
-    public void addUserRestriction(@NonNull ComponentName admin, String key) {
+    public void addUserRestriction(@NonNull ComponentName admin,
+            @UserManager.UserRestrictionKey String key) {
         throwIfParentInstance("addUserRestriction");
         if (mService != null) {
             try {
@@ -7856,7 +7939,8 @@
      *            for the list of keys.
      * @throws SecurityException if {@code admin} is not a device or profile owner.
      */
-    public void clearUserRestriction(@NonNull ComponentName admin, String key) {
+    public void clearUserRestriction(@NonNull ComponentName admin,
+            @UserManager.UserRestrictionKey String key) {
         throwIfParentInstance("clearUserRestriction");
         if (mService != null) {
             try {
@@ -9076,7 +9160,14 @@
     }
 
     /**
-     * Called by device owner to get the MAC address of the Wi-Fi device.
+     * Called by device owner, or profile owner on organization-owned device, to get the MAC
+     * address of the Wi-Fi device.
+     *
+     * NOTE: The MAC address returned here should only be used for inventory management and is
+     * not likely to be the MAC address used by the device to connect to Wi-Fi networks: MAC
+     * addresses used for scanning and connecting to Wi-Fi networks are randomized by default.
+     * To get the randomized MAC address used, call
+     * {@link android.net.wifi.WifiConfiguration#getRandomizedMacAddress}.
      *
      * @param admin Which device owner this request is associated with.
      * @return the MAC address of the Wi-Fi device, or null when the information is not available.
@@ -9278,7 +9369,6 @@
      * <li>{@link #setPasswordExpirationTimeout}</li>
      * <li>{@link #getPasswordExpiration}</li>
      * <li>{@link #getPasswordMaximumLength}</li>
-     * <li>{@link #getPasswordComplexity}</li>
      * <li>{@link #isActivePasswordSufficient}</li>
      * <li>{@link #getCurrentFailedPasswordAttempts}</li>
      * <li>{@link #getMaximumFailedPasswordsForWipe}</li>
@@ -9293,6 +9383,14 @@
      * <li>{@link #getRequiredStrongAuthTimeout}</li>
      * <li>{@link #setRequiredStrongAuthTimeout}</li>
      * </ul>
+     * <p>
+     * The following methods are supported for the parent instance but can only be called by the
+     * profile owner of a managed profile that was created during the device provisioning flow:
+     * <ul>
+     * <li>{@link #getPasswordComplexity}</li>
+     * <li>{@link #setCameraDisabled}</li>
+     * <li>{@link #getCameraDisabled}</li>
+     * </ul>
      *
      * <p>The following methods can be called by the profile owner of a managed profile
      * on an organization-owned device:
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index 713126e..f299d45 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -145,15 +145,6 @@
     public abstract void reportSeparateProfileChallengeChanged(@UserIdInt int userId);
 
     /**
-     * Check whether the user could have their password reset in an untrusted manor due to there
-     * being an admin which can call {@link #resetPassword} to reset the password without knowledge
-     * of the previous password.
-     *
-     * @param userId The user in question
-     */
-    public abstract boolean canUserHaveUntrustedCredentialReset(@UserIdInt int userId);
-
-    /**
      * Return text of error message if printing is disabled.
      * Called by Print Service when printing is disabled by PO or DO when printing is attempted.
      *
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index df4b554..34246fa 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -114,8 +114,8 @@
 
     boolean requestBugreport(in ComponentName who);
 
-    void setCameraDisabled(in ComponentName who, boolean disabled);
-    boolean getCameraDisabled(in ComponentName who, int userHandle);
+    void setCameraDisabled(in ComponentName who, boolean disabled, boolean parent);
+    boolean getCameraDisabled(in ComponentName who, int userHandle, boolean parent);
 
     void setScreenCaptureDisabled(in ComponentName who, boolean disabled);
     boolean getScreenCaptureDisabled(in ComponentName who, int userHandle);
@@ -295,6 +295,9 @@
     void setAutoTimeRequired(in ComponentName who, boolean required);
     boolean getAutoTimeRequired();
 
+    void setAutoTime(in ComponentName who, boolean enabled);
+    boolean getAutoTime(in ComponentName who);
+
     void setForceEphemeralUsers(in ComponentName who, boolean forceEpehemeralUsers);
     boolean getForceEphemeralUsers(in ComponentName who);
 
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 25caaaa..93d1e71 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -34,6 +34,8 @@
 import android.util.Log;
 import android.util.Pair;
 
+import java.util.List;
+
 /**
  * The interface through which an application interacts with the Android backup service to
  * request backup and restore operations.
@@ -948,6 +950,29 @@
         return null;
     }
 
+    /**
+     * Excludes keys from KV restore for a given package. The corresponding data will be excluded
+     * from the data set available the backup agent during restore. However,  final list  of keys
+     * that have been excluded will be passed to the agent to make it aware of the exclusions.
+     *
+     * @param packageName The name of the package for which to exclude keys.
+     * @param keys The list of keys to exclude.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.BACKUP)
+    public void excludeKeysFromRestore(@NonNull String packageName, @NonNull List<String> keys) {
+        checkServiceBinder();
+        if (sService != null) {
+            try {
+                sService.excludeKeysFromRestore(packageName, keys);
+            } catch (RemoteException e) {
+                Log.e(TAG, "excludeKeysFromRestore() couldn't connect");
+            }
+        }
+    }
+
     /*
      * We wrap incoming binder calls with a private class implementation that
      * redirects them into main-thread actions.  This serializes the backup
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index 2dfaad7..099272d 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -710,4 +710,10 @@
      */
     void setAncestralSerialNumber(in long ancestralSerialNumber);
 
+    /**
+     * Excludes keys from KV restore for a given package. The corresponding data will be excluded
+     * from the data set available the backup agent during restore. However,  final list  of keys
+     * that have been excluded will be passed to the agent to make it aware of the exclusions.
+     */
+    void excludeKeysFromRestore(String packageName, in List<String> keys);
 }
diff --git a/core/java/android/app/prediction/AppTargetEvent.java b/core/java/android/app/prediction/AppTargetEvent.java
index 26ff0c1..f519145 100644
--- a/core/java/android/app/prediction/AppTargetEvent.java
+++ b/core/java/android/app/prediction/AppTargetEvent.java
@@ -38,7 +38,7 @@
     /**
      * @hide
      */
-    @IntDef({ACTION_LAUNCH, ACTION_DISMISS, ACTION_PIN})
+    @IntDef({ACTION_LAUNCH, ACTION_DISMISS, ACTION_PIN, ACTION_UNPIN})
     @Retention(RetentionPolicy.SOURCE)
     public @interface ActionType {}
 
@@ -57,6 +57,11 @@
      */
     public static final int ACTION_PIN = 3;
 
+    /**
+     * Event type constant indicating an app target has been un-pinned.
+     */
+    public static final int ACTION_UNPIN = 4;
+
     private final AppTarget mTarget;
     private final String mLocation;
     private final int mAction;
diff --git a/core/java/android/app/timedetector/ITimeDetectorService.aidl b/core/java/android/app/timedetector/ITimeDetectorService.aidl
index ddc4932..9877fc7 100644
--- a/core/java/android/app/timedetector/ITimeDetectorService.aidl
+++ b/core/java/android/app/timedetector/ITimeDetectorService.aidl
@@ -16,6 +16,7 @@
 
 package android.app.timedetector;
 
+import android.app.timedetector.ManualTimeSuggestion;
 import android.app.timedetector.PhoneTimeSuggestion;
 
 /**
@@ -33,4 +34,5 @@
  */
 interface ITimeDetectorService {
   void suggestPhoneTime(in PhoneTimeSuggestion timeSuggestion);
+  void suggestManualTime(in ManualTimeSuggestion timeSuggestion);
 }
diff --git a/core/java/android/app/timedetector/ManualTimeSuggestion.aidl b/core/java/android/app/timedetector/ManualTimeSuggestion.aidl
new file mode 100644
index 0000000..2139404
--- /dev/null
+++ b/core/java/android/app/timedetector/ManualTimeSuggestion.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.timedetector;
+
+parcelable ManualTimeSuggestion;
diff --git a/core/java/android/app/timedetector/ManualTimeSuggestion.java b/core/java/android/app/timedetector/ManualTimeSuggestion.java
new file mode 100644
index 0000000..471606da
--- /dev/null
+++ b/core/java/android/app/timedetector/ManualTimeSuggestion.java
@@ -0,0 +1,128 @@
+/*
+ * 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.timedetector;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.TimestampedValue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A time signal from a manual (user provided) source. The value consists of the number of
+ * milliseconds elapsed since 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime
+ * clock when that number was established. The elapsed realtime clock is considered accurate but
+ * volatile, so time signals must not be persisted across device resets.
+ *
+ * @hide
+ */
+public final class ManualTimeSuggestion implements Parcelable {
+
+    public static final @NonNull Creator<ManualTimeSuggestion> CREATOR =
+            new Creator<ManualTimeSuggestion>() {
+                public ManualTimeSuggestion createFromParcel(Parcel in) {
+                    return ManualTimeSuggestion.createFromParcel(in);
+                }
+
+                public ManualTimeSuggestion[] newArray(int size) {
+                    return new ManualTimeSuggestion[size];
+                }
+            };
+
+    @NonNull
+    private final TimestampedValue<Long> mUtcTime;
+    @Nullable
+    private ArrayList<String> mDebugInfo;
+
+    public ManualTimeSuggestion(@NonNull TimestampedValue<Long> utcTime) {
+        mUtcTime = Objects.requireNonNull(utcTime);
+    }
+
+    private static ManualTimeSuggestion createFromParcel(Parcel in) {
+        TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */);
+        ManualTimeSuggestion suggestion = new ManualTimeSuggestion(utcTime);
+        @SuppressWarnings("unchecked")
+        ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
+        suggestion.mDebugInfo = debugInfo;
+        return suggestion;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeParcelable(mUtcTime, 0);
+        dest.writeList(mDebugInfo);
+    }
+
+    @NonNull
+    public TimestampedValue<Long> getUtcTime() {
+        return mUtcTime;
+    }
+
+    @NonNull
+    public List<String> getDebugInfo() {
+        return mDebugInfo == null
+                ? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo);
+    }
+
+    /**
+     * Associates information with the instance that can be useful for debugging / logging. The
+     * information is present in {@link #toString()} but is not considered for
+     * {@link #equals(Object)} and {@link #hashCode()}.
+     */
+    public void addDebugInfo(String... debugInfos) {
+        if (mDebugInfo == null) {
+            mDebugInfo = new ArrayList<>();
+        }
+        mDebugInfo.addAll(Arrays.asList(debugInfos));
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        ManualTimeSuggestion that = (ManualTimeSuggestion) o;
+        return Objects.equals(mUtcTime, that.mUtcTime);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mUtcTime);
+    }
+
+    @Override
+    public String toString() {
+        return "ManualTimeSuggestion{"
+                + "mUtcTime=" + mUtcTime
+                + ", mDebugInfo=" + mDebugInfo
+                + '}';
+    }
+}
diff --git a/core/java/android/app/timedetector/PhoneTimeSuggestion.java b/core/java/android/app/timedetector/PhoneTimeSuggestion.java
index 475a4aa..dd02af7 100644
--- a/core/java/android/app/timedetector/PhoneTimeSuggestion.java
+++ b/core/java/android/app/timedetector/PhoneTimeSuggestion.java
@@ -23,13 +23,14 @@
 import android.util.TimestampedValue;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 
 /**
- * A time signal from a telephony source. The value consists of the number of milliseconds elapsed
+ * A time signal from a telephony source. The value can be {@code null} to indicate that the
+ * telephony source has entered an "un-opinionated" state and any previously sent suggestions are
+ * being withdrawn. When not {@code null}, the value consists of the number of milliseconds elapsed
  * since 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime clock when that number
  * was established. The elapsed realtime clock is considered accurate but volatile, so time signals
  * must not be persisted across device resets.
@@ -50,23 +51,25 @@
             };
 
     private final int mPhoneId;
-    @NonNull
-    private final TimestampedValue<Long> mUtcTime;
-    @Nullable
-    private ArrayList<String> mDebugInfo;
+    @Nullable private final TimestampedValue<Long> mUtcTime;
+    @Nullable private ArrayList<String> mDebugInfo;
 
-    public PhoneTimeSuggestion(int phoneId, @NonNull TimestampedValue<Long> utcTime) {
-        mPhoneId = phoneId;
-        mUtcTime = Objects.requireNonNull(utcTime);
+    private PhoneTimeSuggestion(Builder builder) {
+        mPhoneId = builder.mPhoneId;
+        mUtcTime = builder.mUtcTime;
+        mDebugInfo = builder.mDebugInfo != null ? new ArrayList<>(builder.mDebugInfo) : null;
     }
 
     private static PhoneTimeSuggestion createFromParcel(Parcel in) {
         int phoneId = in.readInt();
-        TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */);
-        PhoneTimeSuggestion suggestion = new PhoneTimeSuggestion(phoneId, utcTime);
+        PhoneTimeSuggestion suggestion = new PhoneTimeSuggestion.Builder(phoneId)
+                .setUtcTime(in.readParcelable(null /* classLoader */))
+                .build();
         @SuppressWarnings("unchecked")
         ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
-        suggestion.mDebugInfo = debugInfo;
+        if (debugInfo != null) {
+            suggestion.addDebugInfo(debugInfo);
+        }
         return suggestion;
     }
 
@@ -86,14 +89,15 @@
         return mPhoneId;
     }
 
-    @NonNull
+    @Nullable
     public TimestampedValue<Long> getUtcTime() {
         return mUtcTime;
     }
 
     @NonNull
     public List<String> getDebugInfo() {
-        return Collections.unmodifiableList(mDebugInfo);
+        return mDebugInfo == null
+                ? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo);
     }
 
     /**
@@ -101,11 +105,23 @@
      * information is present in {@link #toString()} but is not considered for
      * {@link #equals(Object)} and {@link #hashCode()}.
      */
-    public void addDebugInfo(String... debugInfos) {
+    public void addDebugInfo(String debugInfo) {
         if (mDebugInfo == null) {
             mDebugInfo = new ArrayList<>();
         }
-        mDebugInfo.addAll(Arrays.asList(debugInfos));
+        mDebugInfo.add(debugInfo);
+    }
+
+    /**
+     * Associates information with the instance that can be useful for debugging / logging. The
+     * information is present in {@link #toString()} but is not considered for
+     * {@link #equals(Object)} and {@link #hashCode()}.
+     */
+    public void addDebugInfo(@NonNull List<String> debugInfo) {
+        if (mDebugInfo == null) {
+            mDebugInfo = new ArrayList<>(debugInfo.size());
+        }
+        mDebugInfo.addAll(debugInfo);
     }
 
     @Override
@@ -134,4 +150,39 @@
                 + ", mDebugInfo=" + mDebugInfo
                 + '}';
     }
+
+    /**
+     * Builds {@link PhoneTimeSuggestion} instances.
+     *
+     * @hide
+     */
+    public static class Builder {
+        private final int mPhoneId;
+        private TimestampedValue<Long> mUtcTime;
+        private List<String> mDebugInfo;
+
+        public Builder(int phoneId) {
+            mPhoneId = phoneId;
+        }
+
+        /** Returns the builder for call chaining. */
+        public Builder setUtcTime(TimestampedValue<Long> utcTime) {
+            mUtcTime = utcTime;
+            return this;
+        }
+
+        /** Returns the builder for call chaining. */
+        public Builder addDebugInfo(@NonNull String debugInfo) {
+            if (mDebugInfo == null) {
+                mDebugInfo = new ArrayList<>();
+            }
+            mDebugInfo.add(debugInfo);
+            return this;
+        }
+
+        /** Returns the {@link PhoneTimeSuggestion}. */
+        public PhoneTimeSuggestion build() {
+            return new PhoneTimeSuggestion(this);
+        }
+    }
 }
diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java
index 334e958..48d5cd2 100644
--- a/core/java/android/app/timedetector/TimeDetector.java
+++ b/core/java/android/app/timedetector/TimeDetector.java
@@ -17,19 +17,22 @@
 package android.app.timedetector;
 
 import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemService;
 import android.content.Context;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
+import android.os.SystemClock;
 import android.util.Log;
+import android.util.TimestampedValue;
 
 /**
  * The interface through which system components can send signals to the TimeDetectorService.
  * @hide
  */
 @SystemService(Context.TIME_DETECTOR_SERVICE)
-public final class TimeDetector {
+public class TimeDetector {
     private static final String TAG = "timedetector.TimeDetector";
     private static final boolean DEBUG = false;
 
@@ -41,10 +44,11 @@
     }
 
     /**
-     * Suggests the current time to the detector. The detector may ignore the signal if better
-     * signals are available such as those that come from more reliable sources or were
-     * determined more recently.
+     * Suggests the current phone-signal derived time to the detector. The detector may ignore the
+     * signal if better signals are available such as those that come from more reliable sources or
+     * were determined more recently.
      */
+    @RequiresPermission(android.Manifest.permission.SET_TIME)
     public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
         if (DEBUG) {
             Log.d(TAG, "suggestPhoneTime called: " + timeSuggestion);
@@ -56,4 +60,29 @@
         }
     }
 
+    /**
+     * Suggests the user's manually entered current time to the detector.
+     */
+    @RequiresPermission(android.Manifest.permission.SET_TIME)
+    public void suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion) {
+        if (DEBUG) {
+            Log.d(TAG, "suggestManualTime called: " + timeSuggestion);
+        }
+        try {
+            mITimeDetectorService.suggestManualTime(timeSuggestion);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * A shared utility method to create a {@link ManualTimeSuggestion}.
+     */
+    public static ManualTimeSuggestion createManualTimeSuggestion(long when, String why) {
+        TimestampedValue<Long> utcTime =
+                new TimestampedValue<>(SystemClock.elapsedRealtime(), when);
+        ManualTimeSuggestion manualTimeSuggestion = new ManualTimeSuggestion(utcTime);
+        manualTimeSuggestion.addDebugInfo(why);
+        return manualTimeSuggestion;
+    }
 }
diff --git a/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl
new file mode 100644
index 0000000..df643831
--- /dev/null
+++ b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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.timezonedetector;
+
+import android.app.timezonedetector.ManualTimeZoneSuggestion;
+import android.app.timezonedetector.PhoneTimeZoneSuggestion;
+
+/**
+ * System private API to communicate with time zone detector service.
+ *
+ * <p>Used to provide information to the Time Zone Detector Service from other parts of the Android
+ * system that have access to time zone-related signals, e.g. telephony.
+ *
+ * <p>Use the {@link android.app.timezonedetector.TimeZoneDetector} class rather than going through
+ * this Binder interface directly. See {@link android.app.timezonedetector.TimeZoneDetectorService}
+ * for more complete documentation.
+ *
+ *
+ * {@hide}
+ */
+interface ITimeZoneDetectorService {
+  void suggestManualTimeZone(in ManualTimeZoneSuggestion timeZoneSuggestion);
+  void suggestPhoneTimeZone(in PhoneTimeZoneSuggestion timeZoneSuggestion);
+}
diff --git a/core/java/android/app/timezonedetector/ManualTimeZoneSuggestion.aidl b/core/java/android/app/timezonedetector/ManualTimeZoneSuggestion.aidl
new file mode 100644
index 0000000..d1be86a
--- /dev/null
+++ b/core/java/android/app/timezonedetector/ManualTimeZoneSuggestion.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.timezonedetector;
+
+parcelable ManualTimeZoneSuggestion;
diff --git a/core/java/android/app/timezonedetector/ManualTimeZoneSuggestion.java b/core/java/android/app/timezonedetector/ManualTimeZoneSuggestion.java
new file mode 100644
index 0000000..a6b953b
--- /dev/null
+++ b/core/java/android/app/timezonedetector/ManualTimeZoneSuggestion.java
@@ -0,0 +1,128 @@
+/*
+ * 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.timezonedetector;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A time signal from a manual (user provided) source. The value consists of the number of
+ * milliseconds elapsed since 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime
+ * clock when that number was established. The elapsed realtime clock is considered accurate but
+ * volatile, so time signals must not be persisted across device resets.
+ *
+ * @hide
+ */
+public final class ManualTimeZoneSuggestion implements Parcelable {
+
+    public static final @NonNull Creator<ManualTimeZoneSuggestion> CREATOR =
+            new Creator<ManualTimeZoneSuggestion>() {
+                public ManualTimeZoneSuggestion createFromParcel(Parcel in) {
+                    return ManualTimeZoneSuggestion.createFromParcel(in);
+                }
+
+                public ManualTimeZoneSuggestion[] newArray(int size) {
+                    return new ManualTimeZoneSuggestion[size];
+                }
+            };
+
+    @NonNull
+    private final String mZoneId;
+    @Nullable
+    private ArrayList<String> mDebugInfo;
+
+    public ManualTimeZoneSuggestion(@NonNull String zoneId) {
+        mZoneId = Objects.requireNonNull(zoneId);
+    }
+
+    private static ManualTimeZoneSuggestion createFromParcel(Parcel in) {
+        String zoneId = in.readString();
+        ManualTimeZoneSuggestion suggestion = new ManualTimeZoneSuggestion(zoneId);
+        @SuppressWarnings("unchecked")
+        ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
+        suggestion.mDebugInfo = debugInfo;
+        return suggestion;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString(mZoneId);
+        dest.writeList(mDebugInfo);
+    }
+
+    @NonNull
+    public String getZoneId() {
+        return mZoneId;
+    }
+
+    @NonNull
+    public List<String> getDebugInfo() {
+        return mDebugInfo == null
+                ? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo);
+    }
+
+    /**
+     * Associates information with the instance that can be useful for debugging / logging. The
+     * information is present in {@link #toString()} but is not considered for
+     * {@link #equals(Object)} and {@link #hashCode()}.
+     */
+    public void addDebugInfo(String... debugInfos) {
+        if (mDebugInfo == null) {
+            mDebugInfo = new ArrayList<>();
+        }
+        mDebugInfo.addAll(Arrays.asList(debugInfos));
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        ManualTimeZoneSuggestion
+                that = (ManualTimeZoneSuggestion) o;
+        return Objects.equals(mZoneId, that.mZoneId);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mZoneId);
+    }
+
+    @Override
+    public String toString() {
+        return "ManualTimeSuggestion{"
+                + "mZoneId=" + mZoneId
+                + ", mDebugInfo=" + mDebugInfo
+                + '}';
+    }
+}
diff --git a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.aidl b/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.aidl
new file mode 100644
index 0000000..3ad903b
--- /dev/null
+++ b/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.timezonedetector;
+
+parcelable PhoneTimeZoneSuggestion;
diff --git a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java b/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java
new file mode 100644
index 0000000..e8162488
--- /dev/null
+++ b/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java
@@ -0,0 +1,341 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.timezonedetector;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A suggested time zone from a Phone-based signal, e.g. from MCC and NITZ information.
+ *
+ * @hide
+ */
+public final class PhoneTimeZoneSuggestion implements Parcelable {
+
+    @NonNull
+    public static final Creator<PhoneTimeZoneSuggestion> CREATOR =
+            new Creator<PhoneTimeZoneSuggestion>() {
+                public PhoneTimeZoneSuggestion createFromParcel(Parcel in) {
+                    return PhoneTimeZoneSuggestion.createFromParcel(in);
+                }
+
+                public PhoneTimeZoneSuggestion[] newArray(int size) {
+                    return new PhoneTimeZoneSuggestion[size];
+                }
+            };
+
+    /**
+     * Creates an empty time zone suggestion, i.e. one that will cancel previous suggestions with
+     * the same {@code phoneId}.
+     */
+    @NonNull
+    public static PhoneTimeZoneSuggestion createEmptySuggestion(
+            int phoneId, @NonNull String debugInfo) {
+        return new Builder(phoneId).addDebugInfo(debugInfo).build();
+    }
+
+    @IntDef({ MATCH_TYPE_NA, MATCH_TYPE_NETWORK_COUNTRY_ONLY, MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET,
+            MATCH_TYPE_EMULATOR_ZONE_ID, MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface MatchType {}
+
+    /** Used when match type is not applicable. */
+    public static final int MATCH_TYPE_NA = 0;
+
+    /**
+     * Only the network country is known.
+     */
+    public static final int MATCH_TYPE_NETWORK_COUNTRY_ONLY = 2;
+
+    /**
+     * Both the network county and offset were known.
+     */
+    public static final int MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET = 3;
+
+    /**
+     * The device is running in an emulator and an NITZ signal was simulated containing an
+     * Android extension with an explicit Olson ID.
+     */
+    public static final int MATCH_TYPE_EMULATOR_ZONE_ID = 4;
+
+    /**
+     * The phone is most likely running in a test network not associated with a country (this is
+     * distinct from the country just not being known yet).
+     * Historically, Android has just picked an arbitrary time zone with the correct offset when
+     * on a test network.
+     */
+    public static final int MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY = 5;
+
+    @IntDef({ QUALITY_NA, QUALITY_SINGLE_ZONE, QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET,
+            QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Quality {}
+
+    /** Used when quality is not applicable. */
+    public static final int QUALITY_NA = 0;
+
+    /** There is only one answer */
+    public static final int QUALITY_SINGLE_ZONE = 1;
+
+    /**
+     * There are multiple answers, but they all shared the same offset / DST state at the time
+     * the suggestion was created. i.e. it might be the wrong zone but the user won't notice
+     * immediately if it is wrong.
+     */
+    public static final int QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET = 2;
+
+    /**
+     * There are multiple answers with different offsets. The one given is just one possible.
+     */
+    public static final int QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS = 3;
+
+    /**
+     * The ID of the phone this suggestion is associated with. For multiple-sim devices this
+     * helps to establish origin so filtering / stickiness can be implemented.
+     */
+    private final int mPhoneId;
+
+    /**
+     * The suggestion. {@code null} means there is no current suggestion and any previous suggestion
+     * should be forgotten.
+     */
+    private final String mZoneId;
+
+    /**
+     * The type of "match" used to establish the time zone.
+     */
+    @MatchType
+    private final int mMatchType;
+
+    /**
+     * A measure of the quality of the time zone suggestion, i.e. how confident one could be in
+     * it.
+     */
+    @Quality
+    private final int mQuality;
+
+    /**
+     * Free-form debug information about how the signal was derived. Used for debug only,
+     * intentionally not used in equals(), etc.
+     */
+    private List<String> mDebugInfo;
+
+    private PhoneTimeZoneSuggestion(Builder builder) {
+        mPhoneId = builder.mPhoneId;
+        mZoneId = builder.mZoneId;
+        mMatchType = builder.mMatchType;
+        mQuality = builder.mQuality;
+        mDebugInfo = builder.mDebugInfo != null ? new ArrayList<>(builder.mDebugInfo) : null;
+    }
+
+    @SuppressWarnings("unchecked")
+    private static PhoneTimeZoneSuggestion createFromParcel(Parcel in) {
+        // Use the Builder so we get validation during build().
+        int phoneId = in.readInt();
+        PhoneTimeZoneSuggestion suggestion = new Builder(phoneId)
+                .setZoneId(in.readString())
+                .setMatchType(in.readInt())
+                .setQuality(in.readInt())
+                .build();
+        List<String> debugInfo = in.readArrayList(PhoneTimeZoneSuggestion.class.getClassLoader());
+        if (debugInfo != null) {
+            suggestion.addDebugInfo(debugInfo);
+        }
+        return suggestion;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mPhoneId);
+        dest.writeString(mZoneId);
+        dest.writeInt(mMatchType);
+        dest.writeInt(mQuality);
+        dest.writeList(mDebugInfo);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public int getPhoneId() {
+        return mPhoneId;
+    }
+
+    @Nullable
+    public String getZoneId() {
+        return mZoneId;
+    }
+
+    @MatchType
+    public int getMatchType() {
+        return mMatchType;
+    }
+
+    @Quality
+    public int getQuality() {
+        return mQuality;
+    }
+
+    @NonNull
+    public List<String> getDebugInfo() {
+        return mDebugInfo == null
+                ? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo);
+    }
+
+    /**
+     * Associates information with the instance that can be useful for debugging / logging. The
+     * information is present in {@link #toString()} but is not considered for
+     * {@link #equals(Object)} and {@link #hashCode()}.
+     */
+    public void addDebugInfo(@NonNull String debugInfo) {
+        if (mDebugInfo == null) {
+            mDebugInfo = new ArrayList<>();
+        }
+        mDebugInfo.add(debugInfo);
+    }
+
+    /**
+     * Associates information with the instance that can be useful for debugging / logging. The
+     * information is present in {@link #toString()} but is not considered for
+     * {@link #equals(Object)} and {@link #hashCode()}.
+     */
+    public void addDebugInfo(@NonNull List<String> debugInfo) {
+        if (mDebugInfo == null) {
+            mDebugInfo = new ArrayList<>(debugInfo.size());
+        }
+        mDebugInfo.addAll(debugInfo);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        PhoneTimeZoneSuggestion that = (PhoneTimeZoneSuggestion) o;
+        return mPhoneId == that.mPhoneId
+                && mMatchType == that.mMatchType
+                && mQuality == that.mQuality
+                && Objects.equals(mZoneId, that.mZoneId);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mPhoneId, mZoneId, mMatchType, mQuality);
+    }
+
+    @Override
+    public String toString() {
+        return "PhoneTimeZoneSuggestion{"
+                + "mPhoneId=" + mPhoneId
+                + ", mZoneId='" + mZoneId + '\''
+                + ", mMatchType=" + mMatchType
+                + ", mQuality=" + mQuality
+                + ", mDebugInfo=" + mDebugInfo
+                + '}';
+    }
+
+    /**
+     * Builds {@link PhoneTimeZoneSuggestion} instances.
+     *
+     * @hide
+     */
+    public static class Builder {
+        private final int mPhoneId;
+        private String mZoneId;
+        @MatchType private int mMatchType;
+        @Quality private int mQuality;
+        private List<String> mDebugInfo;
+
+        public Builder(int phoneId) {
+            mPhoneId = phoneId;
+        }
+
+        /** Returns the builder for call chaining. */
+        public Builder setZoneId(String zoneId) {
+            mZoneId = zoneId;
+            return this;
+        }
+
+        /** Returns the builder for call chaining. */
+        public Builder setMatchType(@MatchType int matchType) {
+            mMatchType = matchType;
+            return this;
+        }
+
+        /** Returns the builder for call chaining. */
+        public Builder setQuality(@Quality int quality) {
+            mQuality = quality;
+            return this;
+        }
+
+        /** Returns the builder for call chaining. */
+        public Builder addDebugInfo(@NonNull String debugInfo) {
+            if (mDebugInfo == null) {
+                mDebugInfo = new ArrayList<>();
+            }
+            mDebugInfo.add(debugInfo);
+            return this;
+        }
+
+        /**
+         * Performs basic structural validation of this instance. e.g. Are all the fields populated
+         * that must be? Are the enum ints set to valid values?
+         */
+        void validate() {
+            int quality = mQuality;
+            int matchType = mMatchType;
+            if (mZoneId == null) {
+                if (quality != QUALITY_NA || matchType != MATCH_TYPE_NA) {
+                    throw new RuntimeException("Invalid quality or match type for null zone ID."
+                            + " quality=" + quality + ", matchType=" + matchType);
+                }
+            } else {
+                boolean qualityValid = (quality == QUALITY_SINGLE_ZONE
+                        || quality == QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET
+                        || quality == QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS);
+                boolean matchTypeValid = (matchType == MATCH_TYPE_NETWORK_COUNTRY_ONLY
+                        || matchType == MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET
+                        || matchType == MATCH_TYPE_EMULATOR_ZONE_ID
+                        || matchType == MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY);
+                if (!qualityValid || !matchTypeValid) {
+                    throw new RuntimeException("Invalid quality or match type with zone ID."
+                            + " quality=" + quality + ", matchType=" + matchType);
+                }
+            }
+        }
+
+        /** Returns the {@link PhoneTimeZoneSuggestion}. */
+        public PhoneTimeZoneSuggestion build() {
+            validate();
+            return new PhoneTimeZoneSuggestion(this);
+        }
+    }
+}
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetector.java b/core/java/android/app/timezonedetector/TimeZoneDetector.java
new file mode 100644
index 0000000..387a36b
--- /dev/null
+++ b/core/java/android/app/timezonedetector/TimeZoneDetector.java
@@ -0,0 +1,86 @@
+/*
+ * 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.timezonedetector;
+
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceManager.ServiceNotFoundException;
+import android.util.Log;
+
+/**
+ * The interface through which system components can send signals to the TimeZoneDetectorService.
+ *
+ * @hide
+ */
+@SystemService(Context.TIME_ZONE_DETECTOR_SERVICE)
+public class TimeZoneDetector {
+    private static final String TAG = "timezonedetector.TimeZoneDetector";
+    private static final boolean DEBUG = false;
+
+    private final ITimeZoneDetectorService mITimeZoneDetectorService;
+
+    public TimeZoneDetector() throws ServiceNotFoundException {
+        mITimeZoneDetectorService = ITimeZoneDetectorService.Stub.asInterface(
+                ServiceManager.getServiceOrThrow(Context.TIME_ZONE_DETECTOR_SERVICE));
+    }
+
+    /**
+     * Suggests the current time zone, determined using telephony signals, to the detector. The
+     * detector may ignore the signal based on system settings, whether better information is
+     * available, and so on.
+     */
+    @RequiresPermission(android.Manifest.permission.SET_TIME_ZONE)
+    public void suggestPhoneTimeZone(@NonNull PhoneTimeZoneSuggestion timeZoneSuggestion) {
+        if (DEBUG) {
+            Log.d(TAG, "suggestPhoneTimeZone called: " + timeZoneSuggestion);
+        }
+        try {
+            mITimeZoneDetectorService.suggestPhoneTimeZone(timeZoneSuggestion);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Suggests the current time zone, determined for the user's manually information, to the
+     * detector. The detector may ignore the signal based on system settings.
+     */
+    @RequiresPermission(android.Manifest.permission.SET_TIME_ZONE)
+    public void suggestManualTimeZone(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion) {
+        if (DEBUG) {
+            Log.d(TAG, "suggestManualTimeZone called: " + timeZoneSuggestion);
+        }
+        try {
+            mITimeZoneDetectorService.suggestManualTimeZone(timeZoneSuggestion);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * A shared utility method to create a {@link ManualTimeZoneSuggestion}.
+     */
+    public static ManualTimeZoneSuggestion createManualTimeZoneSuggestion(String tzId, String why) {
+        ManualTimeZoneSuggestion suggestion = new ManualTimeZoneSuggestion(tzId);
+        suggestion.addDebugInfo(why);
+        return suggestion;
+    }
+}
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index ab404d2..fb5645a 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -160,48 +160,114 @@
     public static final int REASON_MAIN_MASK = 0xFF00;
     /** @hide */
     public static final int REASON_MAIN_DEFAULT =   0x0100;
-    /** @hide */
+    /**
+     * The app spent sufficient time in the old bucket without any substantial event so it reached
+     * the timeout threshold to have its bucket lowered.
+     *
+     * @hide
+     */
     public static final int REASON_MAIN_TIMEOUT =   0x0200;
-    /** @hide */
+    /**
+     * The app was used in some way. Look at the REASON_SUB_USAGE_ reason for more details.
+     * @hide
+     */
     public static final int REASON_MAIN_USAGE =     0x0300;
-    /** @hide */
+    /**
+     * Forced by a core UID.
+     * @hide
+     */
     public static final int REASON_MAIN_FORCED =    0x0400;
-    /** @hide */
+    /**
+     * Set by a privileged system app.
+     * @hide
+     */
     public static final int REASON_MAIN_PREDICTED = 0x0500;
 
     /** @hide */
     public static final int REASON_SUB_MASK = 0x00FF;
-    /** @hide */
+    /**
+     * The app was interacted with in some way by the system.
+     * @hide
+     */
     public static final int REASON_SUB_USAGE_SYSTEM_INTERACTION = 0x0001;
-    /** @hide */
+    /**
+     * A notification was viewed by the user. This does not mean the user interacted with the
+     * notification.
+     * @hide
+     */
     public static final int REASON_SUB_USAGE_NOTIFICATION_SEEN  = 0x0002;
-    /** @hide */
+    /**
+     * The app was interacted with in some way by the user. This includes interacting with
+     * notification.
+     * @hide
+     */
     public static final int REASON_SUB_USAGE_USER_INTERACTION   = 0x0003;
-    /** @hide */
+    /**
+     * An {@link android.app.Activity} moved to the foreground.
+     * @hide
+     */
     public static final int REASON_SUB_USAGE_MOVE_TO_FOREGROUND = 0x0004;
-    /** @hide */
+    /**
+     * An {@link android.app.Activity} moved to the background.
+     * @hide
+     */
     public static final int REASON_SUB_USAGE_MOVE_TO_BACKGROUND = 0x0005;
-    /** @hide */
+    /**
+     * There was a system update.
+     * @hide
+     */
     public static final int REASON_SUB_USAGE_SYSTEM_UPDATE      = 0x0006;
-    /** @hide */
+    /**
+     * An app is in an elevated bucket because of an active timeout preventing it from being placed
+     * in a lower bucket.
+     * @hide
+     */
     public static final int REASON_SUB_USAGE_ACTIVE_TIMEOUT     = 0x0007;
-    /** @hide */
+    /**
+     * This system package's sync adapter has been used for another package's content provider.
+     * @hide
+     */
     public static final int REASON_SUB_USAGE_SYNC_ADAPTER       = 0x0008;
-    /** @hide */
+    /**
+     * A slice was pinned by an app.
+     * @hide
+     */
     public static final int REASON_SUB_USAGE_SLICE_PINNED       = 0x0009;
-    /** @hide */
+    /** /**
+     * A slice was pinned by the default launcher or the default assistant.
+     * @hide
+     */
     public static final int REASON_SUB_USAGE_SLICE_PINNED_PRIV  = 0x000A;
-    /** @hide */
+    /**
+     * A sync operation that is exempt from app standby was scheduled when the device wasn't Dozing.
+     * @hide
+     */
     public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE = 0x000B;
-    /** @hide */
+    /**
+     * A sync operation that is exempt from app standby was scheduled while the device was Dozing.
+     * @hide
+     */
     public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE = 0x000C;
-    /** @hide */
+    /**
+     * A sync operation that is exempt from app standby started.
+     * @hide
+     */
     public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_START = 0x000D;
-    /** @hide */
+    /**
+     * A sync operation that is not exempt from app standby was scheduled.
+     * @hide
+     */
     public static final int REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED = 0x000E;
-    /** @hide */
+    /**
+     * A foreground service started.
+     * @hide
+     */
     public static final int REASON_SUB_USAGE_FOREGROUND_SERVICE_START = 0x000F;
-    /** @hide */
+    /**
+     * The predicted bucket was restored after the app's temporary elevation to the ACTIVE bucket
+     * ended.
+     * @hide
+     */
     public static final int REASON_SUB_PREDICTED_RESTORED       = 0x0001;
 
 
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 1fe1b10..64df0e8 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -17,10 +17,13 @@
 package android.bluetooth;
 
 import android.Manifest;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Binder;
@@ -30,6 +33,8 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -152,13 +157,22 @@
      */
     public static final int STATE_NOT_PLAYING = 11;
 
+    /** @hide */
+    @IntDef(prefix = "OPTIONAL_CODECS_", value = {
+            OPTIONAL_CODECS_SUPPORT_UNKNOWN,
+            OPTIONAL_CODECS_NOT_SUPPORTED,
+            OPTIONAL_CODECS_SUPPORTED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface OptionalCodecsSupportStatus {}
+
     /**
      * We don't have a stored preference for whether or not the given A2DP sink device supports
      * optional codecs.
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public static final int OPTIONAL_CODECS_SUPPORT_UNKNOWN = -1;
 
     /**
@@ -166,7 +180,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public static final int OPTIONAL_CODECS_NOT_SUPPORTED = 0;
 
     /**
@@ -174,16 +188,25 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public static final int OPTIONAL_CODECS_SUPPORTED = 1;
 
+    /** @hide */
+    @IntDef(prefix = "OPTIONAL_CODECS_PREF_", value = {
+            OPTIONAL_CODECS_PREF_UNKNOWN,
+            OPTIONAL_CODECS_PREF_DISABLED,
+            OPTIONAL_CODECS_PREF_ENABLED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface OptionalCodecsPreferenceStatus {}
+
     /**
-     * We don't have a stored preference for whether optional codecs should be enabled or disabled
-     * for the given A2DP device.
+     * We don't have a stored preference for whether optional codecs should be enabled or
+     * disabled for the given A2DP device.
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public static final int OPTIONAL_CODECS_PREF_UNKNOWN = -1;
 
     /**
@@ -191,7 +214,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public static final int OPTIONAL_CODECS_PREF_DISABLED = 0;
 
     /**
@@ -199,7 +222,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public static final int OPTIONAL_CODECS_PREF_ENABLED = 1;
 
     private BluetoothAdapter mAdapter;
@@ -246,13 +269,12 @@
      * the state. Users can get the connection state of the profile
      * from this intent.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
-     * permission.
      *
      * @param device Remote Bluetooth Device
      * @return false on immediate error, true otherwise
      * @hide
      */
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
     @UnsupportedAppUsage
     public boolean connect(BluetoothDevice device) {
         if (DBG) log("connect(" + device + ")");
@@ -287,13 +309,12 @@
      * {@link #STATE_DISCONNECTING} can be used to distinguish between the
      * two scenarios.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
-     * permission.
      *
      * @param device Remote Bluetooth Device
      * @return false on immediate error, true otherwise
      * @hide
      */
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
     @UnsupportedAppUsage
     public boolean disconnect(BluetoothDevice device) {
         if (DBG) log("disconnect(" + device + ")");
@@ -382,14 +403,12 @@
      * {@link #ACTION_ACTIVE_DEVICE_CHANGED} intent will be broadcasted
      * with the active device.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
-     * permission.
-     *
      * @param device the remote Bluetooth device. Could be null to clear
      * the active device and stop streaming audio to a Bluetooth device.
      * @return false on immediate error, true otherwise
      * @hide
      */
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
     @UnsupportedAppUsage
     public boolean setActiveDevice(@Nullable BluetoothDevice device) {
         if (DBG) log("setActiveDevice(" + device + ")");
@@ -410,16 +429,13 @@
     /**
      * Get the connected device that is active.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
-     * permission.
-     *
      * @return the connected device that is active or null if no device
      * is active
      * @hide
      */
-    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    @SystemApi
     @Nullable
-    @UnsupportedAppUsage
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
     public BluetoothDevice getActiveDevice() {
         if (VDBG) log("getActiveDevice()");
         try {
@@ -439,28 +455,45 @@
      * Set priority of the profile
      *
      * <p> The device should already be paired.
-     * Priority can be one of {@link #PRIORITY_ON} orgetBluetoothManager
-     * {@link #PRIORITY_OFF},
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
-     * permission.
+     * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF}
      *
      * @param device Paired bluetooth device
      * @param priority
      * @return true if priority is set, false on error
      * @hide
      */
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
     public boolean setPriority(BluetoothDevice device, int priority) {
         if (DBG) log("setPriority(" + device + ", " + priority + ")");
+        return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
+    }
+
+    /**
+     * Set connection policy of the profile
+     *
+     * <p> The device should already be paired.
+     * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
+     * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Paired bluetooth device
+     * @param connectionPolicy is the connection policy to set to for this profile
+     * @return true if connectionPolicy is set, false on error
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+    public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
+            @ConnectionPolicy int connectionPolicy) {
+        if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
         try {
             final IBluetoothA2dp service = getService();
             if (service != null && isEnabled()
                     && isValidDevice(device)) {
-                if (priority != BluetoothProfile.PRIORITY_OFF
-                        && priority != BluetoothProfile.PRIORITY_ON) {
+                if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
+                        && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
                     return false;
                 }
-                return service.setPriority(device, priority);
+                return service.setConnectionPolicy(device, connectionPolicy);
             }
             if (service == null) Log.w(TAG, "Proxy not attached to service");
             return false;
@@ -474,8 +507,7 @@
      * Get the priority of the profile.
      *
      * <p> The priority can be any of:
-     * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
-     * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
+     * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
      *
      * @param device Bluetooth device
      * @return priority of the device
@@ -485,17 +517,35 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public int getPriority(BluetoothDevice device) {
         if (VDBG) log("getPriority(" + device + ")");
+        return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
+    }
+
+    /**
+     * Get the connection policy of the profile.
+     *
+     * <p> The connection policy can be any of:
+     * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
+     * {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Bluetooth device
+     * @return connection policy of the device
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
+        if (VDBG) log("getConnectionPolicy(" + device + ")");
         try {
             final IBluetoothA2dp service = getService();
             if (service != null && isEnabled()
                     && isValidDevice(device)) {
-                return service.getPriority(device);
+                return service.getConnectionPolicy(device);
             }
             if (service == null) Log.w(TAG, "Proxy not attached to service");
-            return BluetoothProfile.PRIORITY_OFF;
+            return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
         } catch (RemoteException e) {
             Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
-            return BluetoothProfile.PRIORITY_OFF;
+            return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
         }
     }
 
@@ -574,7 +624,7 @@
             if (uuids == null) return false;
 
             for (ParcelUuid uuid : uuids) {
-                if (BluetoothUuid.isAvrcpTarget(uuid)) {
+                if (uuid.equals(BluetoothUuid.AVRCP_TARGET)) {
                     return true;
                 }
             }
@@ -590,8 +640,10 @@
      * @return the current codec status
      * @hide
      */
-    @UnsupportedAppUsage
-    public @Nullable BluetoothCodecStatus getCodecStatus(BluetoothDevice device) {
+    @SystemApi
+    @Nullable
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public BluetoothCodecStatus getCodecStatus(@Nullable BluetoothDevice device) {
         if (DBG) Log.d(TAG, "getCodecStatus(" + device + ")");
         try {
             final IBluetoothA2dp service = getService();
@@ -616,9 +668,10 @@
      * @param codecConfig the codec configuration preference
      * @hide
      */
-    @UnsupportedAppUsage
-    public void setCodecConfigPreference(BluetoothDevice device,
-                                         BluetoothCodecConfig codecConfig) {
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public void setCodecConfigPreference(@Nullable BluetoothDevice device,
+                                         @Nullable BluetoothCodecConfig codecConfig) {
         if (DBG) Log.d(TAG, "setCodecConfigPreference(" + device + ")");
         try {
             final IBluetoothA2dp service = getService();
@@ -640,8 +693,9 @@
      * active A2DP Bluetooth device.
      * @hide
      */
-    @UnsupportedAppUsage
-    public void enableOptionalCodecs(BluetoothDevice device) {
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public void enableOptionalCodecs(@Nullable BluetoothDevice device) {
         if (DBG) Log.d(TAG, "enableOptionalCodecs(" + device + ")");
         enableDisableOptionalCodecs(device, true);
     }
@@ -653,8 +707,9 @@
      * active A2DP Bluetooth device.
      * @hide
      */
-    @UnsupportedAppUsage
-    public void disableOptionalCodecs(BluetoothDevice device) {
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public void disableOptionalCodecs(@Nullable BluetoothDevice device) {
         if (DBG) Log.d(TAG, "disableOptionalCodecs(" + device + ")");
         enableDisableOptionalCodecs(device, false);
     }
@@ -692,8 +747,10 @@
      * OPTIONAL_CODECS_SUPPORTED.
      * @hide
      */
-    @UnsupportedAppUsage
-    public int supportsOptionalCodecs(BluetoothDevice device) {
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+    @OptionalCodecsSupportStatus
+    public int supportsOptionalCodecs(@Nullable BluetoothDevice device) {
         try {
             final IBluetoothA2dp service = getService();
             if (service != null && isEnabled() && isValidDevice(device)) {
@@ -702,7 +759,7 @@
             if (service == null) Log.w(TAG, "Proxy not attached to service");
             return OPTIONAL_CODECS_SUPPORT_UNKNOWN;
         } catch (RemoteException e) {
-            Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e);
+            Log.e(TAG, "Error talking to BT service in supportsOptionalCodecs()", e);
             return OPTIONAL_CODECS_SUPPORT_UNKNOWN;
         }
     }
@@ -715,8 +772,10 @@
      * OPTIONAL_CODECS_PREF_DISABLED.
      * @hide
      */
-    @UnsupportedAppUsage
-    public int getOptionalCodecsEnabled(BluetoothDevice device) {
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+    @OptionalCodecsPreferenceStatus
+    public int getOptionalCodecsEnabled(@Nullable BluetoothDevice device) {
         try {
             final IBluetoothA2dp service = getService();
             if (service != null && isEnabled() && isValidDevice(device)) {
@@ -725,7 +784,7 @@
             if (service == null) Log.w(TAG, "Proxy not attached to service");
             return OPTIONAL_CODECS_PREF_UNKNOWN;
         } catch (RemoteException e) {
-            Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e);
+            Log.e(TAG, "Error talking to BT service in getOptionalCodecsEnabled()", e);
             return OPTIONAL_CODECS_PREF_UNKNOWN;
         }
     }
@@ -739,8 +798,10 @@
      * OPTIONAL_CODECS_PREF_DISABLED.
      * @hide
      */
-    @UnsupportedAppUsage
-    public void setOptionalCodecsEnabled(BluetoothDevice device, int value) {
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public void setOptionalCodecsEnabled(@Nullable BluetoothDevice device,
+            @OptionalCodecsPreferenceStatus int value) {
         try {
             if (value != BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN
                     && value != BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED
diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java
index 5a8055a..cf33676 100755
--- a/core/java/android/bluetooth/BluetoothA2dpSink.java
+++ b/core/java/android/bluetooth/BluetoothA2dpSink.java
@@ -16,6 +16,9 @@
 
 package android.bluetooth;
 
+import android.Manifest;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Binder;
@@ -317,27 +320,43 @@
      * Set priority of the profile
      *
      * <p> The device should already be paired.
-     * Priority can be one of {@link #PRIORITY_ON} orgetBluetoothManager
-     * {@link #PRIORITY_OFF},
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
-     * permission.
+     * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF}
      *
      * @param device Paired bluetooth device
      * @param priority
      * @return true if priority is set, false on error
      * @hide
      */
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
     public boolean setPriority(BluetoothDevice device, int priority) {
         if (DBG) log("setPriority(" + device + ", " + priority + ")");
+        return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
+    }
+
+    /**
+     * Set connection policy of the profile
+     *
+     * <p> The device should already be paired.
+     * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
+     * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Paired bluetooth device
+     * @param connectionPolicy is the connection policy to set to for this profile
+     * @return true if connectionPolicy is set, false on error
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+    public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) {
+        if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
         final IBluetoothA2dpSink service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
-            if (priority != BluetoothProfile.PRIORITY_OFF
-                    && priority != BluetoothProfile.PRIORITY_ON) {
+            if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
+                    && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
                 return false;
             }
             try {
-                return service.setPriority(device, priority);
+                return service.setConnectionPolicy(device, connectionPolicy);
             } catch (RemoteException e) {
                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
                 return false;
@@ -351,28 +370,44 @@
      * Get the priority of the profile.
      *
      * <p> The priority can be any of:
-     * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
-     * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
      *
      * @param device Bluetooth device
      * @return priority of the device
      * @hide
      */
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
     public int getPriority(BluetoothDevice device) {
         if (VDBG) log("getPriority(" + device + ")");
+        return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
+    }
+
+    /**
+     * Get the connection policy of the profile.
+     *
+     * <p> The connection policy can be any of:
+     * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
+     * {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Bluetooth device
+     * @return connection policy of the device
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public int getConnectionPolicy(BluetoothDevice device) {
+        if (VDBG) log("getConnectionPolicy(" + device + ")");
         final IBluetoothA2dpSink service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
             try {
-                return service.getPriority(device);
+                return service.getConnectionPolicy(device);
             } catch (RemoteException e) {
                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
-                return BluetoothProfile.PRIORITY_OFF;
+                return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
             }
         }
         if (service == null) Log.w(TAG, "Proxy not attached to service");
-        return BluetoothProfile.PRIORITY_OFF;
+        return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
     }
 
     /**
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 9d152a7..3f8cb62 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -27,6 +27,7 @@
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
+import android.bluetooth.BluetoothProfile.ConnectionPolicy;
 import android.bluetooth.le.BluetoothLeAdvertiser;
 import android.bluetooth.le.BluetoothLeScanner;
 import android.bluetooth.le.PeriodicAdvertisingManager;
@@ -456,6 +457,37 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface IoCapability {}
 
+    /** @hide */
+    @IntDef(prefix = "ACTIVE_DEVICE_", value = {ACTIVE_DEVICE_AUDIO,
+            ACTIVE_DEVICE_PHONE_CALL, ACTIVE_DEVICE_ALL})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ActiveDeviceUse {}
+
+    /**
+     * Use the specified device for audio (a2dp and hearing aid profile)
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ACTIVE_DEVICE_AUDIO = 0;
+
+    /**
+     * Use the specified device for phone calls (headset profile and hearing
+     * aid profile)
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ACTIVE_DEVICE_PHONE_CALL = 1;
+
+    /**
+     * Use the specified device for a2dp, hearing aid profile, and headset profile
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int ACTIVE_DEVICE_ALL = 2;
+
     /**
      * Broadcast Action: The local Bluetooth adapter has started the remote
      * device discovery process.
@@ -830,18 +862,7 @@
      */
     @RequiresPermission(Manifest.permission.BLUETOOTH)
     public boolean isEnabled() {
-        try {
-            mServiceLock.readLock().lock();
-            if (mService != null) {
-                return mService.isEnabled();
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "", e);
-        } finally {
-            mServiceLock.readLock().unlock();
-        }
-
-        return false;
+        return getState() == BluetoothAdapter.STATE_ON;
     }
 
     /**
@@ -1734,6 +1755,41 @@
     }
 
     /**
+     *
+     * @param device is the remote bluetooth device
+     * @param profiles represents the purpose for which we are setting this as the active device.
+     *                 Possible values are:
+     *                 {@link BluetoothAdapter#ACTIVE_DEVICE_AUDIO},
+     *                 {@link BluetoothAdapter#ACTIVE_DEVICE_PHONE_CALL},
+     *                 {@link BluetoothAdapter#ACTIVE_DEVICE_ALL}
+     * @return false on immediate error, true otherwise
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+    public boolean setActiveDevice(@Nullable BluetoothDevice device,
+            @ActiveDeviceUse int profiles) {
+        if (profiles != ACTIVE_DEVICE_AUDIO && profiles != ACTIVE_DEVICE_PHONE_CALL
+                && profiles != ACTIVE_DEVICE_ALL) {
+            Log.e(TAG, "Invalid profiles param value in setActiveDevice");
+            return false;
+        }
+
+        try {
+            mServiceLock.readLock().lock();
+            if (mService != null) {
+                return mService.setActiveDevice(device, profiles);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
+
+        return false;
+    }
+
+    /**
      * Connects all enabled and supported bluetooth profiles between the local and remote device
      *
      * @param device is the remote device with which to connect these profiles
@@ -3381,4 +3437,48 @@
         void onMetadataChanged(@NonNull BluetoothDevice device, int key,
                 @Nullable byte[] value);
     }
+
+    /**
+     * Converts old constant of priority to the new for connection policy
+     *
+     * @param priority is the priority to convert to connection policy
+     * @return the equivalent connection policy constant to the priority
+     *
+     * @hide
+     */
+    public static @ConnectionPolicy int priorityToConnectionPolicy(int priority) {
+        switch(priority) {
+            case BluetoothProfile.PRIORITY_AUTO_CONNECT:
+                return BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+            case BluetoothProfile.PRIORITY_ON:
+                return BluetoothProfile.CONNECTION_POLICY_ALLOWED;
+            case BluetoothProfile.PRIORITY_OFF:
+                return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+            case BluetoothProfile.PRIORITY_UNDEFINED:
+                return BluetoothProfile.CONNECTION_POLICY_UNKNOWN;
+            default:
+                Log.e(TAG, "setPriority: Invalid priority: " + priority);
+                return BluetoothProfile.CONNECTION_POLICY_UNKNOWN;
+        }
+    }
+
+    /**
+     * Converts new constant of connection policy to the old for priority
+     *
+     * @param connectionPolicy is the connection policy to convert to priority
+     * @return the equivalent priority constant to the connectionPolicy
+     *
+     * @hide
+     */
+    public static int connectionPolicyToPriority(@ConnectionPolicy int connectionPolicy) {
+        switch(connectionPolicy) {
+            case BluetoothProfile.CONNECTION_POLICY_ALLOWED:
+                return BluetoothProfile.PRIORITY_ON;
+            case BluetoothProfile.CONNECTION_POLICY_FORBIDDEN:
+                return BluetoothProfile.PRIORITY_OFF;
+            case BluetoothProfile.CONNECTION_POLICY_UNKNOWN:
+                return BluetoothProfile.PRIORITY_UNDEFINED;
+        }
+        return BluetoothProfile.PRIORITY_UNDEFINED;
+    }
 }
diff --git a/core/java/android/bluetooth/BluetoothCodecConfig.java b/core/java/android/bluetooth/BluetoothCodecConfig.java
index 36f3a1e..08d0797 100644
--- a/core/java/android/bluetooth/BluetoothCodecConfig.java
+++ b/core/java/android/bluetooth/BluetoothCodecConfig.java
@@ -16,10 +16,15 @@
 
 package android.bluetooth;
 
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
 
 /**
@@ -29,78 +34,131 @@
  *
  * {@hide}
  */
+@SystemApi
 public final class BluetoothCodecConfig implements Parcelable {
     // Add an entry for each source codec here.
     // NOTE: The values should be same as those listed in the following file:
     //   hardware/libhardware/include/hardware/bt_av.h
-    @UnsupportedAppUsage
+
+    /** @hide */
+    @IntDef(prefix = "SOURCE_CODEC_TYPE_", value = {
+            SOURCE_CODEC_TYPE_SBC,
+            SOURCE_CODEC_TYPE_AAC,
+            SOURCE_CODEC_TYPE_APTX,
+            SOURCE_CODEC_TYPE_APTX_HD,
+            SOURCE_CODEC_TYPE_LDAC,
+            SOURCE_CODEC_TYPE_MAX,
+            SOURCE_CODEC_TYPE_INVALID
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SourceCodecType {}
+
     public static final int SOURCE_CODEC_TYPE_SBC = 0;
-    @UnsupportedAppUsage
+
     public static final int SOURCE_CODEC_TYPE_AAC = 1;
-    @UnsupportedAppUsage
+
     public static final int SOURCE_CODEC_TYPE_APTX = 2;
-    @UnsupportedAppUsage
+
     public static final int SOURCE_CODEC_TYPE_APTX_HD = 3;
-    @UnsupportedAppUsage
+
     public static final int SOURCE_CODEC_TYPE_LDAC = 4;
-    @UnsupportedAppUsage
+
     public static final int SOURCE_CODEC_TYPE_MAX = 5;
 
-    @UnsupportedAppUsage
+
     public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000;
 
-    @UnsupportedAppUsage
+    /** @hide */
+    @IntDef(prefix = "CODEC_PRIORITY_", value = {
+            CODEC_PRIORITY_DISABLED,
+            CODEC_PRIORITY_DEFAULT,
+            CODEC_PRIORITY_HIGHEST
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CodecPriority {}
+
     public static final int CODEC_PRIORITY_DISABLED = -1;
-    @UnsupportedAppUsage
+
     public static final int CODEC_PRIORITY_DEFAULT = 0;
-    @UnsupportedAppUsage
+
     public static final int CODEC_PRIORITY_HIGHEST = 1000 * 1000;
 
-    @UnsupportedAppUsage
+
+    /** @hide */
+    @IntDef(prefix = "SAMPLE_RATE_", value = {
+            SAMPLE_RATE_NONE,
+            SAMPLE_RATE_44100,
+            SAMPLE_RATE_48000,
+            SAMPLE_RATE_88200,
+            SAMPLE_RATE_96000,
+            SAMPLE_RATE_176400,
+            SAMPLE_RATE_192000
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SampleRate {}
+
     public static final int SAMPLE_RATE_NONE = 0;
-    @UnsupportedAppUsage
+
     public static final int SAMPLE_RATE_44100 = 0x1 << 0;
-    @UnsupportedAppUsage
+
     public static final int SAMPLE_RATE_48000 = 0x1 << 1;
-    @UnsupportedAppUsage
+
     public static final int SAMPLE_RATE_88200 = 0x1 << 2;
-    @UnsupportedAppUsage
+
     public static final int SAMPLE_RATE_96000 = 0x1 << 3;
-    @UnsupportedAppUsage
+
     public static final int SAMPLE_RATE_176400 = 0x1 << 4;
-    @UnsupportedAppUsage
+
     public static final int SAMPLE_RATE_192000 = 0x1 << 5;
 
-    @UnsupportedAppUsage
+
+    /** @hide */
+    @IntDef(prefix = "BITS_PER_SAMPLE_", value = {
+            BITS_PER_SAMPLE_NONE,
+            BITS_PER_SAMPLE_16,
+            BITS_PER_SAMPLE_24,
+            BITS_PER_SAMPLE_32
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface BitsPerSample {}
+
     public static final int BITS_PER_SAMPLE_NONE = 0;
-    @UnsupportedAppUsage
+
     public static final int BITS_PER_SAMPLE_16 = 0x1 << 0;
-    @UnsupportedAppUsage
+
     public static final int BITS_PER_SAMPLE_24 = 0x1 << 1;
-    @UnsupportedAppUsage
+
     public static final int BITS_PER_SAMPLE_32 = 0x1 << 2;
 
-    @UnsupportedAppUsage
+
+    /** @hide */
+    @IntDef(prefix = "CHANNEL_MODE_", value = {
+            CHANNEL_MODE_NONE,
+            CHANNEL_MODE_MONO,
+            CHANNEL_MODE_STEREO
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ChannelMode {}
+
     public static final int CHANNEL_MODE_NONE = 0;
-    @UnsupportedAppUsage
+
     public static final int CHANNEL_MODE_MONO = 0x1 << 0;
-    @UnsupportedAppUsage
+
     public static final int CHANNEL_MODE_STEREO = 0x1 << 1;
 
-    private final int mCodecType;
-    private int mCodecPriority;
-    private final int mSampleRate;
-    private final int mBitsPerSample;
-    private final int mChannelMode;
+    private final @SourceCodecType int mCodecType;
+    private @CodecPriority int mCodecPriority;
+    private final @SampleRate int mSampleRate;
+    private final @BitsPerSample int mBitsPerSample;
+    private final @ChannelMode int mChannelMode;
     private final long mCodecSpecific1;
     private final long mCodecSpecific2;
     private final long mCodecSpecific3;
     private final long mCodecSpecific4;
 
-    @UnsupportedAppUsage
-    public BluetoothCodecConfig(int codecType, int codecPriority,
-            int sampleRate, int bitsPerSample,
-            int channelMode, long codecSpecific1,
+    public BluetoothCodecConfig(@SourceCodecType int codecType, @CodecPriority int codecPriority,
+            @SampleRate int sampleRate, @BitsPerSample int bitsPerSample,
+            @ChannelMode int channelMode, long codecSpecific1,
             long codecSpecific2, long codecSpecific3,
             long codecSpecific4) {
         mCodecType = codecType;
@@ -114,8 +172,7 @@
         mCodecSpecific4 = codecSpecific4;
     }
 
-    @UnsupportedAppUsage
-    public BluetoothCodecConfig(int codecType) {
+    public BluetoothCodecConfig(@SourceCodecType int codecType) {
         mCodecType = codecType;
         mCodecPriority = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT;
         mSampleRate = BluetoothCodecConfig.SAMPLE_RATE_NONE;
@@ -144,6 +201,12 @@
         return false;
     }
 
+    /**
+     * Returns a hash based on the config values
+     *
+     * @return a hash based on the config values
+     * @hide
+     */
     @Override
     public int hashCode() {
         return Objects.hash(mCodecType, mCodecPriority, mSampleRate,
@@ -155,6 +218,7 @@
      * Checks whether the object contains valid codec configuration.
      *
      * @return true if the object contains valid codec configuration, otherwise false.
+     * @hide
      */
     public boolean isValid() {
         return (mSampleRate != SAMPLE_RATE_NONE)
@@ -242,6 +306,12 @@
                 + ",mCodecSpecific4:" + mCodecSpecific4 + "}";
     }
 
+    /**
+     * Always returns 0
+     *
+     * @return 0
+     * @hide
+     */
     @Override
     public int describeContents() {
         return 0;
@@ -271,6 +341,14 @@
                 }
             };
 
+    /**
+     * Flattens the object to a parcel
+     *
+     * @param out The Parcel in which the object should be written.
+     * @param flags Additional flags about how the object should be written.
+     *
+     * @hide
+     */
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mCodecType);
@@ -289,7 +367,7 @@
      *
      * @return the codec name
      */
-    public String getCodecName() {
+    public @NonNull String getCodecName() {
         switch (mCodecType) {
             case SOURCE_CODEC_TYPE_SBC:
                 return "SBC";
@@ -315,8 +393,7 @@
      *
      * @return the codec type
      */
-    @UnsupportedAppUsage
-    public int getCodecType() {
+    public @SourceCodecType int getCodecType() {
         return mCodecType;
     }
 
@@ -336,8 +413,7 @@
      *
      * @return the codec priority
      */
-    @UnsupportedAppUsage
-    public int getCodecPriority() {
+    public @CodecPriority int getCodecPriority() {
         return mCodecPriority;
     }
 
@@ -347,9 +423,10 @@
      * means higher priority. If 0, reset to default.
      *
      * @param codecPriority the codec priority
+     * @hide
      */
     @UnsupportedAppUsage
-    public void setCodecPriority(int codecPriority) {
+    public void setCodecPriority(@CodecPriority int codecPriority) {
         mCodecPriority = codecPriority;
     }
 
@@ -366,8 +443,7 @@
      *
      * @return the codec sample rate
      */
-    @UnsupportedAppUsage
-    public int getSampleRate() {
+    public @SampleRate int getSampleRate() {
         return mSampleRate;
     }
 
@@ -381,8 +457,7 @@
      *
      * @return the codec bits per sample
      */
-    @UnsupportedAppUsage
-    public int getBitsPerSample() {
+    public @BitsPerSample int getBitsPerSample() {
         return mBitsPerSample;
     }
 
@@ -394,9 +469,10 @@
      * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_STEREO}
      *
      * @return the codec channel mode
+     * @hide
      */
     @UnsupportedAppUsage
-    public int getChannelMode() {
+    public @ChannelMode int getChannelMode() {
         return mChannelMode;
     }
 
@@ -405,7 +481,6 @@
      *
      * @return a codec specific value1.
      */
-    @UnsupportedAppUsage
     public long getCodecSpecific1() {
         return mCodecSpecific1;
     }
@@ -414,6 +489,7 @@
      * Gets a codec specific value2.
      *
      * @return a codec specific value2
+     * @hide
      */
     @UnsupportedAppUsage
     public long getCodecSpecific2() {
@@ -424,6 +500,7 @@
      * Gets a codec specific value3.
      *
      * @return a codec specific value3
+     * @hide
      */
     @UnsupportedAppUsage
     public long getCodecSpecific3() {
@@ -434,6 +511,7 @@
      * Gets a codec specific value4.
      *
      * @return a codec specific value4
+     * @hide
      */
     @UnsupportedAppUsage
     public long getCodecSpecific4() {
@@ -445,6 +523,7 @@
      *
      * @param valueSet the value set presented by a bitmask
      * @return true if the valueSet contains zero or single bit, otherwise false.
+     * @hide
      */
     private static boolean hasSingleBit(int valueSet) {
         return (valueSet == 0 || (valueSet & (valueSet - 1)) == 0);
@@ -454,6 +533,7 @@
      * Checks whether the object contains none or single sample rate.
      *
      * @return true if the object contains none or single sample rate, otherwise false.
+     * @hide
      */
     public boolean hasSingleSampleRate() {
         return hasSingleBit(mSampleRate);
@@ -463,6 +543,7 @@
      * Checks whether the object contains none or single bits per sample.
      *
      * @return true if the object contains none or single bits per sample, otherwise false.
+     * @hide
      */
     public boolean hasSingleBitsPerSample() {
         return hasSingleBit(mBitsPerSample);
@@ -472,6 +553,7 @@
      * Checks whether the object contains none or single channel mode.
      *
      * @return true if the object contains none or single channel mode, otherwise false.
+     * @hide
      */
     public boolean hasSingleChannelMode() {
         return hasSingleBit(mChannelMode);
@@ -482,6 +564,7 @@
      *
      * @param other the codec config to compare against
      * @return true if the audio feeding parameters are same, otherwise false
+     * @hide
      */
     public boolean sameAudioFeedingParameters(BluetoothCodecConfig other) {
         return (other != null && other.mSampleRate == mSampleRate
@@ -495,6 +578,7 @@
      *
      * @param other the codec config to compare against
      * @return true if the audio feeding parameters are similar, otherwise false.
+     * @hide
      */
     public boolean similarCodecFeedingParameters(BluetoothCodecConfig other) {
         if (other == null || mCodecType != other.mCodecType) {
@@ -526,6 +610,7 @@
      *
      * @param other the codec config to compare against
      * @return true if the codec specific parameters are the same, otherwise false.
+     * @hide
      */
     public boolean sameCodecSpecificParameters(BluetoothCodecConfig other) {
         if (other == null && mCodecType != other.mCodecType) {
diff --git a/core/java/android/bluetooth/BluetoothCodecStatus.java b/core/java/android/bluetooth/BluetoothCodecStatus.java
index 58a764a..b6e7739 100644
--- a/core/java/android/bluetooth/BluetoothCodecStatus.java
+++ b/core/java/android/bluetooth/BluetoothCodecStatus.java
@@ -17,7 +17,7 @@
 package android.bluetooth;
 
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -32,6 +32,7 @@
  *
  * {@hide}
  */
+@SystemApi
 public final class BluetoothCodecStatus implements Parcelable {
     /**
      * Extra for the codec configuration intents of the individual profiles.
@@ -39,17 +40,16 @@
      * This extra represents the current codec status of the A2DP
      * profile.
      */
-    @UnsupportedAppUsage
     public static final String EXTRA_CODEC_STATUS =
-            "android.bluetooth.codec.extra.CODEC_STATUS";
+            "android.bluetooth.extra.CODEC_STATUS";
 
     private final @Nullable BluetoothCodecConfig mCodecConfig;
     private final BluetoothCodecConfig[] mCodecsLocalCapabilities;
     private final BluetoothCodecConfig[] mCodecsSelectableCapabilities;
 
-    public BluetoothCodecStatus(BluetoothCodecConfig codecConfig,
-            BluetoothCodecConfig[] codecsLocalCapabilities,
-            BluetoothCodecConfig[] codecsSelectableCapabilities) {
+    public BluetoothCodecStatus(@Nullable BluetoothCodecConfig codecConfig,
+            @Nullable BluetoothCodecConfig[] codecsLocalCapabilities,
+            @Nullable BluetoothCodecConfig[] codecsSelectableCapabilities) {
         mCodecConfig = codecConfig;
         mCodecsLocalCapabilities = codecsLocalCapabilities;
         mCodecsSelectableCapabilities = codecsSelectableCapabilities;
@@ -74,6 +74,7 @@
      * @param c1 the first array of capabilities to compare
      * @param c2 the second array of capabilities to compare
      * @return true if both arrays contain same capabilities
+     * @hide
      */
     public static boolean sameCapabilities(BluetoothCodecConfig[] c1,
                                            BluetoothCodecConfig[] c2) {
@@ -95,6 +96,7 @@
      *
      * @param codecConfig the codec config to compare against
      * @return true if the codec config matches, otherwise false
+     * @hide
      */
     public boolean isCodecConfigSelectable(BluetoothCodecConfig codecConfig) {
         if (codecConfig == null || !codecConfig.hasSingleSampleRate()
@@ -125,7 +127,12 @@
         return false;
     }
 
-
+    /**
+     * Returns a hash based on the codec config and local capabilities
+     *
+     * @return a hash based on the config values
+     * @hide
+     */
     @Override
     public int hashCode() {
         return Objects.hash(mCodecConfig, mCodecsLocalCapabilities,
@@ -140,6 +147,12 @@
                 + "}";
     }
 
+    /**
+     * Always returns 0
+     *
+     * @return 0
+     * @hide
+     */
     @Override
     public int describeContents() {
         return 0;
@@ -165,6 +178,14 @@
                 }
             };
 
+    /**
+     * Flattens the object to a parcel
+     *
+     * @param out The Parcel in which the object should be written.
+     * @param flags Additional flags about how the object should be written.
+     *
+     * @hide
+     */
     @Override
     public void writeToParcel(Parcel out, int flags) {
         out.writeTypedObject(mCodecConfig, 0);
@@ -177,7 +198,6 @@
      *
      * @return the current codec configuration
      */
-    @UnsupportedAppUsage
     public @Nullable BluetoothCodecConfig getCodecConfig() {
         return mCodecConfig;
     }
@@ -187,8 +207,7 @@
      *
      * @return an array with the codecs local capabilities
      */
-    @UnsupportedAppUsage
-    public BluetoothCodecConfig[] getCodecsLocalCapabilities() {
+    public @Nullable BluetoothCodecConfig[] getCodecsLocalCapabilities() {
         return mCodecsLocalCapabilities;
     }
 
@@ -197,8 +216,7 @@
      *
      * @return an array with the codecs selectable capabilities
      */
-    @UnsupportedAppUsage
-    public BluetoothCodecConfig[] getCodecsSelectableCapabilities() {
+    public @Nullable BluetoothCodecConfig[] getCodecsSelectableCapabilities() {
         return mCodecsSelectableCapabilities;
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 0be3eca..49187dc 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1131,20 +1131,7 @@
      */
     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
     public boolean createBond() {
-        final IBluetooth service = sService;
-        if (service == null) {
-            Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device");
-            return false;
-        }
-        try {
-            Log.i(TAG, "createBond() for device " + getAddress()
-                    + " called by pid: " + Process.myPid()
-                    + " tid: " + Process.myTid());
-            return service.createBond(this, TRANSPORT_AUTO);
-        } catch (RemoteException e) {
-            Log.e(TAG, "", e);
-        }
-        return false;
+        return createBond(TRANSPORT_AUTO);
     }
 
     /**
@@ -1165,23 +1152,7 @@
      */
     @UnsupportedAppUsage
     public boolean createBond(int transport) {
-        final IBluetooth service = sService;
-        if (service == null) {
-            Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device");
-            return false;
-        }
-        if (TRANSPORT_AUTO > transport || transport > TRANSPORT_LE) {
-            throw new IllegalArgumentException(transport + " is not a valid Bluetooth transport");
-        }
-        try {
-            Log.i(TAG, "createBond() for device " + getAddress()
-                    + " called by pid: " + Process.myPid()
-                    + " tid: " + Process.myTid());
-            return service.createBond(this, transport);
-        } catch (RemoteException e) {
-            Log.e(TAG, "", e);
-        }
-        return false;
+        return createBondOutOfBand(transport, null);
     }
 
     /**
@@ -1209,7 +1180,7 @@
             return false;
         }
         try {
-            return service.createBondOutOfBand(this, transport, oobData);
+            return service.createBond(this, transport, oobData);
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
         }
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 672174f..0955b10 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -17,6 +17,7 @@
 package android.bluetooth;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
@@ -558,28 +559,47 @@
      *
      * <p> The device should already be paired.
      * Priority can be one of {@link BluetoothProfile#PRIORITY_ON} or
-     * {@link BluetoothProfile#PRIORITY_OFF},
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
-     * permission.
+     * {@link BluetoothProfile#PRIORITY_OFF}
      *
      * @param device Paired bluetooth device
      * @param priority
      * @return true if priority is set, false on error
      * @hide
+     * @deprecated Replaced with {@link #setConnectionPolicy(BluetoothDevice, int)}
      */
+    @Deprecated
     @SystemApi
     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN)
     public boolean setPriority(BluetoothDevice device, int priority) {
         if (DBG) log("setPriority(" + device + ", " + priority + ")");
+        return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
+    }
+
+    /**
+     * Set connection policy of the profile
+     *
+     * <p> The device should already be paired.
+     * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
+     * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Paired bluetooth device
+     * @param connectionPolicy is the connection policy to set to for this profile
+     * @return true if connectionPolicy is set, false on error
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+    public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
+            @ConnectionPolicy int connectionPolicy) {
+        if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
         final IBluetoothHeadset service = mService;
         if (service != null && isEnabled() && isValidDevice(device)) {
-            if (priority != BluetoothProfile.PRIORITY_OFF
-                    && priority != BluetoothProfile.PRIORITY_ON) {
+            if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
+                    && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
                 return false;
             }
             try {
-                return service.setPriority(device, priority);
+                return service.setConnectionPolicy(device, connectionPolicy);
             } catch (RemoteException e) {
                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
                 return false;
@@ -596,26 +616,43 @@
      * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
      * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
      * @param device Bluetooth device
      * @return priority of the device
      * @hide
      */
     @UnsupportedAppUsage
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
     public int getPriority(BluetoothDevice device) {
         if (VDBG) log("getPriority(" + device + ")");
+        return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
+    }
+
+    /**
+     * Get the connection policy of the profile.
+     *
+     * <p> The connection policy can be any of:
+     * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
+     * {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Bluetooth device
+     * @return connection policy of the device
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
+        if (VDBG) log("getConnectionPolicy(" + device + ")");
         final IBluetoothHeadset service = mService;
         if (service != null && isEnabled() && isValidDevice(device)) {
             try {
-                return service.getPriority(device);
+                return service.getConnectionPolicy(device);
             } catch (RemoteException e) {
                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
-                return PRIORITY_OFF;
+                return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
             }
         }
         if (service == null) Log.w(TAG, "Proxy not attached to service");
-        return PRIORITY_OFF;
+        return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
     }
 
     /**
@@ -1096,8 +1133,9 @@
      * is active.
      * @hide
      */
+    @SystemApi
+    @Nullable
     @RequiresPermission(android.Manifest.permission.BLUETOOTH)
-    @UnsupportedAppUsage
     public BluetoothDevice getActiveDevice() {
         if (VDBG) {
             Log.d(TAG, "getActiveDevice");
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
index 5d00f09..7ee29ff 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClient.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -16,6 +16,9 @@
 
 package android.bluetooth;
 
+import android.Manifest;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Binder;
@@ -553,19 +556,45 @@
     /**
      * Set priority of the profile
      *
-     * The device should already be paired.
+     * <p> The device should already be paired.
+     * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF}
+     *
+     * @param device Paired bluetooth device
+     * @param priority
+     * @return true if priority is set, false on error
+     * @hide
      */
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
     public boolean setPriority(BluetoothDevice device, int priority) {
         if (DBG) log("setPriority(" + device + ", " + priority + ")");
+        return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
+    }
+
+    /**
+     * Set connection policy of the profile
+     *
+     * <p> The device should already be paired.
+     * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
+     * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Paired bluetooth device
+     * @param connectionPolicy is the connection policy to set to for this profile
+     * @return true if connectionPolicy is set, false on error
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+    public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) {
+        if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
         final IBluetoothHeadsetClient service =
                 getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
-            if (priority != BluetoothProfile.PRIORITY_OFF
-                    && priority != BluetoothProfile.PRIORITY_ON) {
+            if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
+                    && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
                 return false;
             }
             try {
-                return service.setPriority(device, priority);
+                return service.setConnectionPolicy(device, connectionPolicy);
             } catch (RemoteException e) {
                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
                 return false;
@@ -577,21 +606,47 @@
 
     /**
      * Get the priority of the profile.
+     *
+     * <p> The priority can be any of:
+     * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
+     *
+     * @param device Bluetooth device
+     * @return priority of the device
+     * @hide
      */
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
     public int getPriority(BluetoothDevice device) {
         if (VDBG) log("getPriority(" + device + ")");
+        return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
+    }
+
+    /**
+     * Get the connection policy of the profile.
+     *
+     * <p> The connection policy can be any of:
+     * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
+     * {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Bluetooth device
+     * @return connection policy of the device
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public int getConnectionPolicy(BluetoothDevice device) {
+        if (VDBG) log("getConnectionPolicy(" + device + ")");
         final IBluetoothHeadsetClient service =
                 getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
             try {
-                return service.getPriority(device);
+                return service.getConnectionPolicy(device);
             } catch (RemoteException e) {
                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
-                return PRIORITY_OFF;
+                return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
             }
         }
         if (service == null) Log.w(TAG, "Proxy not attached to service");
-        return PRIORITY_OFF;
+        return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
     }
 
     /**
diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java
index a812c32..ead8429 100644
--- a/core/java/android/bluetooth/BluetoothHearingAid.java
+++ b/core/java/android/bluetooth/BluetoothHearingAid.java
@@ -22,6 +22,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Binder;
@@ -355,28 +356,45 @@
      * Set priority of the profile
      *
      * <p> The device should already be paired.
-     * Priority can be one of {@link #PRIORITY_ON} orgetBluetoothManager
-     * {@link #PRIORITY_OFF},
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
-     * permission.
+     * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF},
      *
      * @param device Paired bluetooth device
      * @param priority
      * @return true if priority is set, false on error
      * @hide
      */
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
     public boolean setPriority(BluetoothDevice device, int priority) {
         if (DBG) log("setPriority(" + device + ", " + priority + ")");
+        return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
+    }
+
+    /**
+     * Set connection policy of the profile
+     *
+     * <p> The device should already be paired.
+     * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
+     * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Paired bluetooth device
+     * @param connectionPolicy is the connection policy to set to for this profile
+     * @return true if connectionPolicy is set, false on error
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+    public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
+            @ConnectionPolicy int connectionPolicy) {
+        if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
         final IBluetoothHearingAid service = getService();
         try {
             if (service != null && isEnabled()
                     && isValidDevice(device)) {
-                if (priority != BluetoothProfile.PRIORITY_OFF
-                        && priority != BluetoothProfile.PRIORITY_ON) {
+                if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
+                        && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
                     return false;
                 }
-                return service.setPriority(device, priority);
+                return service.setConnectionPolicy(device, connectionPolicy);
             }
             if (service == null) Log.w(TAG, "Proxy not attached to service");
             return false;
@@ -390,8 +408,7 @@
      * Get the priority of the profile.
      *
      * <p> The priority can be any of:
-     * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
-     * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
+     * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
      *
      * @param device Bluetooth device
      * @return priority of the device
@@ -400,17 +417,35 @@
     @RequiresPermission(Manifest.permission.BLUETOOTH)
     public int getPriority(BluetoothDevice device) {
         if (VDBG) log("getPriority(" + device + ")");
+        return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
+    }
+
+    /**
+     * Get the connection policy of the profile.
+     *
+     * <p> The connection policy can be any of:
+     * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
+     * {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Bluetooth device
+     * @return connection policy of the device
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
+        if (VDBG) log("getConnectionPolicy(" + device + ")");
         final IBluetoothHearingAid service = getService();
         try {
             if (service != null && isEnabled()
                     && isValidDevice(device)) {
-                return service.getPriority(device);
+                return service.getConnectionPolicy(device);
             }
             if (service == null) Log.w(TAG, "Proxy not attached to service");
-            return BluetoothProfile.PRIORITY_OFF;
+            return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
         } catch (RemoteException e) {
             Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
-            return BluetoothProfile.PRIORITY_OFF;
+            return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
         }
     }
 
diff --git a/core/java/android/bluetooth/BluetoothHidHost.java b/core/java/android/bluetooth/BluetoothHidHost.java
index 4afb382..8f5cdf0 100644
--- a/core/java/android/bluetooth/BluetoothHidHost.java
+++ b/core/java/android/bluetooth/BluetoothHidHost.java
@@ -16,8 +16,11 @@
 
 package android.bluetooth;
 
+import android.Manifest;
+import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
 import android.content.Context;
 import android.os.Binder;
 import android.os.IBinder;
@@ -379,27 +382,43 @@
      * Set priority of the profile
      *
      * <p> The device should already be paired.
-     * Priority can be one of {@link #PRIORITY_ON} or
-     * {@link #PRIORITY_OFF},
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
-     * permission.
+     * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF},
      *
      * @param device Paired bluetooth device
      * @param priority
      * @return true if priority is set, false on error
      * @hide
      */
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
     public boolean setPriority(BluetoothDevice device, int priority) {
         if (DBG) log("setPriority(" + device + ", " + priority + ")");
+        return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
+    }
+
+    /**
+     * Set connection policy of the profile
+     *
+     * <p> The device should already be paired.
+     * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
+     * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Paired bluetooth device
+     * @param connectionPolicy is the connection policy to set to for this profile
+     * @return true if connectionPolicy is set, false on error
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+    public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) {
+        if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
         final IBluetoothHidHost service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
-            if (priority != BluetoothProfile.PRIORITY_OFF
-                    && priority != BluetoothProfile.PRIORITY_ON) {
+            if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
+                    && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
                 return false;
             }
             try {
-                return service.setPriority(device, priority);
+                return service.setConnectionPolicy(device, connectionPolicy);
             } catch (RemoteException e) {
                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
                 return false;
@@ -413,28 +432,44 @@
      * Get the priority of the profile.
      *
      * <p> The priority can be any of:
-     * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
-     * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
      *
      * @param device Bluetooth device
      * @return priority of the device
      * @hide
      */
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
     public int getPriority(BluetoothDevice device) {
         if (VDBG) log("getPriority(" + device + ")");
+        return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
+    }
+
+    /**
+     * Get the connection policy of the profile.
+     *
+     * <p> The connection policy can be any of:
+     * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
+     * {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Bluetooth device
+     * @return connection policy of the device
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public int getConnectionPolicy(BluetoothDevice device) {
+        if (VDBG) log("getConnectionPolicy(" + device + ")");
         final IBluetoothHidHost service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
             try {
-                return service.getPriority(device);
+                return service.getConnectionPolicy(device);
             } catch (RemoteException e) {
                 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
-                return BluetoothProfile.PRIORITY_OFF;
+                return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
             }
         }
         if (service == null) Log.w(TAG, "Proxy not attached to service");
-        return BluetoothProfile.PRIORITY_OFF;
+        return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
     }
 
     private boolean isEnabled() {
diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java
index dd2f150..979dfd4 100644
--- a/core/java/android/bluetooth/BluetoothMap.java
+++ b/core/java/android/bluetooth/BluetoothMap.java
@@ -16,6 +16,9 @@
 
 package android.bluetooth;
 
+import android.Manifest;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Binder;
@@ -271,23 +274,43 @@
      * Set priority of the profile
      *
      * <p> The device should already be paired.
-     * Priority can be one of {@link #PRIORITY_ON} or
-     * {@link #PRIORITY_OFF},
+     * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF},
      *
      * @param device Paired bluetooth device
      * @param priority
      * @return true if priority is set, false on error
+     * @hide
      */
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
     public boolean setPriority(BluetoothDevice device, int priority) {
         if (DBG) log("setPriority(" + device + ", " + priority + ")");
+        return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
+    }
+
+    /**
+     * Set connection policy of the profile
+     *
+     * <p> The device should already be paired.
+     * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
+     * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Paired bluetooth device
+     * @param connectionPolicy is the connection policy to set to for this profile
+     * @return true if connectionPolicy is set, false on error
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+    public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) {
+        if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
         final IBluetoothMap service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
-            if (priority != BluetoothProfile.PRIORITY_OFF
-                    && priority != BluetoothProfile.PRIORITY_ON) {
+            if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
+                    && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
                 return false;
             }
             try {
-                return service.setPriority(device, priority);
+                return service.setConnectionPolicy(device, connectionPolicy);
             } catch (RemoteException e) {
                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
                 return false;
@@ -301,25 +324,44 @@
      * Get the priority of the profile.
      *
      * <p> The priority can be any of:
-     * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
-     * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
+     * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
      *
      * @param device Bluetooth device
      * @return priority of the device
+     * @hide
      */
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
     public int getPriority(BluetoothDevice device) {
         if (VDBG) log("getPriority(" + device + ")");
+        return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
+    }
+
+    /**
+     * Get the connection policy of the profile.
+     *
+     * <p> The connection policy can be any of:
+     * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
+     * {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Bluetooth device
+     * @return connection policy of the device
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public int getConnectionPolicy(BluetoothDevice device) {
+        if (VDBG) log("getConnectionPolicy(" + device + ")");
         final IBluetoothMap service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
             try {
-                return service.getPriority(device);
+                return service.getConnectionPolicy(device);
             } catch (RemoteException e) {
                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
-                return PRIORITY_OFF;
+                return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
             }
         }
         if (service == null) Log.w(TAG, "Proxy not attached to service");
-        return PRIORITY_OFF;
+        return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
     }
 
     private static void log(String msg) {
diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java
index 69682c6..0ec473c 100644
--- a/core/java/android/bluetooth/BluetoothMapClient.java
+++ b/core/java/android/bluetooth/BluetoothMapClient.java
@@ -16,6 +16,9 @@
 
 package android.bluetooth;
 
+import android.Manifest;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -240,22 +243,44 @@
     /**
      * Set priority of the profile
      *
-     * <p> The device should already be paired.  Priority can be one of {@link #PRIORITY_ON} or
-     * {@link #PRIORITY_OFF},
+     * <p> The device should already be paired.
+     * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF},
      *
      * @param device Paired bluetooth device
+     * @param priority
      * @return true if priority is set, false on error
+     * @hide
      */
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
     public boolean setPriority(BluetoothDevice device, int priority) {
         if (DBG) Log.d(TAG, "setPriority(" + device + ", " + priority + ")");
+        return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
+    }
+
+    /**
+     * Set connection policy of the profile
+     *
+     * <p> The device should already be paired.
+     * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
+     * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Paired bluetooth device
+     * @param connectionPolicy is the connection policy to set to for this profile
+     * @return true if connectionPolicy is set, false on error
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+    public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) {
+        if (DBG) Log.d(TAG, "setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
         final IBluetoothMapClient service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
-            if (priority != BluetoothProfile.PRIORITY_OFF
-                    && priority != BluetoothProfile.PRIORITY_ON) {
+            if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
+                    && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
                 return false;
             }
             try {
-                return service.setPriority(device, priority);
+                return service.setConnectionPolicy(device, connectionPolicy);
             } catch (RemoteException e) {
                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
                 return false;
@@ -269,25 +294,44 @@
      * Get the priority of the profile.
      *
      * <p> The priority can be any of:
-     * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
-     * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
+     * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
      *
      * @param device Bluetooth device
      * @return priority of the device
+     * @hide
      */
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
     public int getPriority(BluetoothDevice device) {
         if (VDBG) Log.d(TAG, "getPriority(" + device + ")");
+        return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
+    }
+
+    /**
+     * Get the connection policy of the profile.
+     *
+     * <p> The connection policy can be any of:
+     * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
+     * {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Bluetooth device
+     * @return connection policy of the device
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public int getConnectionPolicy(BluetoothDevice device) {
+        if (VDBG) Log.d(TAG, "getConnectionPolicy(" + device + ")");
         final IBluetoothMapClient service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
             try {
-                return service.getPriority(device);
+                return service.getConnectionPolicy(device);
             } catch (RemoteException e) {
                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
-                return PRIORITY_OFF;
+                return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
             }
         }
         if (service == null) Log.w(TAG, "Proxy not attached to service");
-        return PRIORITY_OFF;
+        return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
     }
 
     /**
diff --git a/core/java/android/bluetooth/BluetoothPbapClient.java b/core/java/android/bluetooth/BluetoothPbapClient.java
index d70e1e7..9618ba0 100644
--- a/core/java/android/bluetooth/BluetoothPbapClient.java
+++ b/core/java/android/bluetooth/BluetoothPbapClient.java
@@ -16,6 +16,9 @@
 
 package android.bluetooth;
 
+import android.Manifest;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.content.Context;
 import android.os.Binder;
 import android.os.IBinder;
@@ -241,25 +244,45 @@
      * Set priority of the profile
      *
      * <p> The device should already be paired.
-     * Priority can be one of {@link #PRIORITY_ON} or
-     * {@link #PRIORITY_OFF},
+     * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF},
      *
      * @param device Paired bluetooth device
-     * @param priority Priority of this profile
+     * @param priority
      * @return true if priority is set, false on error
+     * @hide
      */
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
     public boolean setPriority(BluetoothDevice device, int priority) {
+        if (DBG) log("setPriority(" + device + ", " + priority + ")");
+        return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
+    }
+
+    /**
+     * Set connection policy of the profile
+     *
+     * <p> The device should already be paired.
+     * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
+     * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Paired bluetooth device
+     * @param connectionPolicy is the connection policy to set to for this profile
+     * @return true if connectionPolicy is set, false on error
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+    public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) {
         if (DBG) {
-            log("setPriority(" + device + ", " + priority + ")");
+            log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
         }
         final IBluetoothPbapClient service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
-            if (priority != BluetoothProfile.PRIORITY_OFF
-                    && priority != BluetoothProfile.PRIORITY_ON) {
+            if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
+                    && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
                 return false;
             }
             try {
-                return service.setPriority(device, priority);
+                return service.setConnectionPolicy(device, connectionPolicy);
             } catch (RemoteException e) {
                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
                 return false;
@@ -275,28 +298,47 @@
      * Get the priority of the profile.
      *
      * <p> The priority can be any of:
-     * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
-     * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
+     * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
      *
      * @param device Bluetooth device
      * @return priority of the device
+     * @hide
      */
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
     public int getPriority(BluetoothDevice device) {
+        if (VDBG) log("getPriority(" + device + ")");
+        return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
+    }
+
+    /**
+     * Get the connection policy of the profile.
+     *
+     * <p> The connection policy can be any of:
+     * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
+     * {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Bluetooth device
+     * @return connection policy of the device
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public int getConnectionPolicy(BluetoothDevice device) {
         if (VDBG) {
-            log("getPriority(" + device + ")");
+            log("getConnectionPolicy(" + device + ")");
         }
         final IBluetoothPbapClient service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
             try {
-                return service.getPriority(device);
+                return service.getConnectionPolicy(device);
             } catch (RemoteException e) {
                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
-                return PRIORITY_OFF;
+                return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
             }
         }
         if (service == null) {
             Log.w(TAG, "Proxy not attached to service");
         }
-        return PRIORITY_OFF;
+        return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index f1ac765..097a367 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -225,7 +225,9 @@
      * and outgoing connections for the profile
      *
      * @hide
+     * @deprecated Replaced with {@link #CONNECTION_POLICY_ALLOWED}
      **/
+    @Deprecated
     @SystemApi
     int PRIORITY_ON = 100;
 
@@ -234,7 +236,9 @@
      * connections and outgoing connections for the profile.
      *
      * @hide
+     * @deprecated Replaced with {@link #CONNECTION_POLICY_FORBIDDEN}
      **/
+    @Deprecated
     @SystemApi
     int PRIORITY_OFF = 0;
 
@@ -246,6 +250,38 @@
     @UnsupportedAppUsage
     int PRIORITY_UNDEFINED = -1;
 
+    /** @hide */
+    @IntDef(prefix = "CONNECTION_POLICY_", value = {CONNECTION_POLICY_ALLOWED,
+            CONNECTION_POLICY_FORBIDDEN, CONNECTION_POLICY_UNKNOWN})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ConnectionPolicy{}
+
+    /**
+     * Default connection policy for devices that allow incoming and outgoing connections
+     * for the profile
+     *
+     * @hide
+     **/
+    @SystemApi
+    int CONNECTION_POLICY_ALLOWED = 100;
+
+    /**
+     * Default connection policy for devices that do not allow incoming or outgoing connections
+     * for the profile.
+     *
+     * @hide
+     **/
+    @SystemApi
+    int CONNECTION_POLICY_FORBIDDEN = 0;
+
+    /**
+     * Default connection policy when not set or when the device is unpaired
+     *
+     * @hide
+     */
+    @SystemApi
+    int CONNECTION_POLICY_UNKNOWN = -1;
+
     /**
      * Get connected devices for this specific profile.
      *
diff --git a/core/java/android/bluetooth/BluetoothSap.java b/core/java/android/bluetooth/BluetoothSap.java
index e0610c8..9b4dabc 100644
--- a/core/java/android/bluetooth/BluetoothSap.java
+++ b/core/java/android/bluetooth/BluetoothSap.java
@@ -16,6 +16,9 @@
 
 package android.bluetooth;
 
+import android.Manifest;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Binder;
@@ -300,22 +303,43 @@
      * Set priority of the profile
      *
      * <p> The device should already be paired.
+     * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF},
      *
      * @param device Paired bluetooth device
      * @param priority
      * @return true if priority is set, false on error
      * @hide
      */
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
     public boolean setPriority(BluetoothDevice device, int priority) {
         if (DBG) log("setPriority(" + device + ", " + priority + ")");
+        return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
+    }
+
+    /**
+     * Set connection policy of the profile
+     *
+     * <p> The device should already be paired.
+     * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
+     * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Paired bluetooth device
+     * @param connectionPolicy is the connection policy to set to for this profile
+     * @return true if connectionPolicy is set, false on error
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+    public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) {
+        if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
         final IBluetoothSap service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
-            if (priority != BluetoothProfile.PRIORITY_OFF
-                    && priority != BluetoothProfile.PRIORITY_ON) {
+            if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
+                    && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
                 return false;
             }
             try {
-                return service.setPriority(device, priority);
+                return service.setConnectionPolicy(device, connectionPolicy);
             } catch (RemoteException e) {
                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
                 return false;
@@ -328,23 +352,45 @@
     /**
      * Get the priority of the profile.
      *
+     * <p> The priority can be any of:
+     * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
+     *
      * @param device Bluetooth device
      * @return priority of the device
      * @hide
      */
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
     public int getPriority(BluetoothDevice device) {
         if (VDBG) log("getPriority(" + device + ")");
+        return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
+    }
+
+    /**
+     * Get the connection policy of the profile.
+     *
+     * <p> The connection policy can be any of:
+     * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
+     * {@link #CONNECTION_POLICY_UNKNOWN}
+     *
+     * @param device Bluetooth device
+     * @return connection policy of the device
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public int getConnectionPolicy(BluetoothDevice device) {
+        if (VDBG) log("getConnectionPolicy(" + device + ")");
         final IBluetoothSap service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
             try {
-                return service.getPriority(device);
+                return service.getConnectionPolicy(device);
             } catch (RemoteException e) {
                 Log.e(TAG, Log.getStackTraceString(new Throwable()));
-                return PRIORITY_OFF;
+                return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
             }
         }
         if (service == null) Log.w(TAG, "Proxy not attached to service");
-        return PRIORITY_OFF;
+        return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
     }
 
     private static void log(String msg) {
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index bc3c9a9..7e96c23 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -16,8 +16,10 @@
 
 package android.bluetooth;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
-import android.os.Build;
 import android.os.ParcelUuid;
 
 import java.nio.ByteBuffer;
@@ -31,6 +33,7 @@
  *
  * @hide
  */
+@SystemApi
 public final class BluetoothUuid {
 
     /* See Bluetooth Assigned Numbers document - SDP section, to get the values of UUIDs
@@ -39,167 +42,157 @@
      * The following 128 bit values are calculated as:
      *  uuid * 2^96 + BASE_UUID
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-    public static final ParcelUuid AudioSink =
+
+    /** @hide */
+    @NonNull
+    @SystemApi
+    public static final ParcelUuid A2DP_SINK =
             ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB");
-    public static final ParcelUuid AudioSource =
+    /** @hide */
+    @NonNull
+    @SystemApi
+    public static final ParcelUuid A2DP_SOURCE =
             ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB");
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-    public static final ParcelUuid AdvAudioDist =
+    /** @hide */
+    @NonNull
+    @SystemApi
+    public static final ParcelUuid ADV_AUDIO_DIST =
             ParcelUuid.fromString("0000110D-0000-1000-8000-00805F9B34FB");
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+    /** @hide */
+    @NonNull
+    @SystemApi
     public static final ParcelUuid HSP =
             ParcelUuid.fromString("00001108-0000-1000-8000-00805F9B34FB");
+    /** @hide */
+    @NonNull
+    @SystemApi
     public static final ParcelUuid HSP_AG =
             ParcelUuid.fromString("00001112-0000-1000-8000-00805F9B34FB");
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-    public static final ParcelUuid Handsfree =
+    /** @hide */
+    @NonNull
+    @SystemApi
+    public static final ParcelUuid HFP =
             ParcelUuid.fromString("0000111E-0000-1000-8000-00805F9B34FB");
-    public static final ParcelUuid Handsfree_AG =
+    /** @hide */
+    @NonNull
+    @SystemApi
+    public static final ParcelUuid HFP_AG =
             ParcelUuid.fromString("0000111F-0000-1000-8000-00805F9B34FB");
-    public static final ParcelUuid AvrcpController =
+    /** @hide */
+    @NonNull
+    @SystemApi
+    public static final ParcelUuid AVRCP_CONTROLLER =
             ParcelUuid.fromString("0000110E-0000-1000-8000-00805F9B34FB");
-    public static final ParcelUuid AvrcpTarget =
+    /** @hide */
+    @NonNull
+    @SystemApi
+    public static final ParcelUuid AVRCP_TARGET =
             ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB");
-    @UnsupportedAppUsage
-    public static final ParcelUuid ObexObjectPush =
+    /** @hide */
+    @NonNull
+    @SystemApi
+    public static final ParcelUuid OBEX_OBJECT_PUSH =
             ParcelUuid.fromString("00001105-0000-1000-8000-00805f9b34fb");
-    public static final ParcelUuid Hid =
+    /** @hide */
+    @NonNull
+    @SystemApi
+    public static final ParcelUuid HID =
             ParcelUuid.fromString("00001124-0000-1000-8000-00805f9b34fb");
-    @UnsupportedAppUsage
-    public static final ParcelUuid Hogp =
+    /** @hide */
+    @NonNull
+    @SystemApi
+    public static final ParcelUuid HOGP =
             ParcelUuid.fromString("00001812-0000-1000-8000-00805f9b34fb");
+    /** @hide */
+    @NonNull
+    @SystemApi
     public static final ParcelUuid PANU =
             ParcelUuid.fromString("00001115-0000-1000-8000-00805F9B34FB");
-    @UnsupportedAppUsage
+    /** @hide */
+    @NonNull
+    @SystemApi
     public static final ParcelUuid NAP =
             ParcelUuid.fromString("00001116-0000-1000-8000-00805F9B34FB");
+    /** @hide */
+    @NonNull
+    @SystemApi
     public static final ParcelUuid BNEP =
             ParcelUuid.fromString("0000000f-0000-1000-8000-00805F9B34FB");
+    /** @hide */
+    @NonNull
+    @SystemApi
     public static final ParcelUuid PBAP_PCE =
             ParcelUuid.fromString("0000112e-0000-1000-8000-00805F9B34FB");
-    @UnsupportedAppUsage
+    /** @hide */
+    @NonNull
+    @SystemApi
     public static final ParcelUuid PBAP_PSE =
             ParcelUuid.fromString("0000112f-0000-1000-8000-00805F9B34FB");
+    /** @hide */
+    @NonNull
+    @SystemApi
     public static final ParcelUuid MAP =
             ParcelUuid.fromString("00001134-0000-1000-8000-00805F9B34FB");
+    /** @hide */
+    @NonNull
+    @SystemApi
     public static final ParcelUuid MNS =
             ParcelUuid.fromString("00001133-0000-1000-8000-00805F9B34FB");
+    /** @hide */
+    @NonNull
+    @SystemApi
     public static final ParcelUuid MAS =
             ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB");
+    /** @hide */
+    @NonNull
+    @SystemApi
     public static final ParcelUuid SAP =
             ParcelUuid.fromString("0000112D-0000-1000-8000-00805F9B34FB");
-    public static final ParcelUuid HearingAid =
+    /** @hide */
+    @NonNull
+    @SystemApi
+    public static final ParcelUuid HEARING_AID =
             ParcelUuid.fromString("0000FDF0-0000-1000-8000-00805f9b34fb");
 
+    /** @hide */
+    @NonNull
+    @SystemApi
     public static final ParcelUuid BASE_UUID =
             ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
 
-    /** Length of bytes for 16 bit UUID */
-    public static final int UUID_BYTES_16_BIT = 2;
-    /** Length of bytes for 32 bit UUID */
-    public static final int UUID_BYTES_32_BIT = 4;
-    /** Length of bytes for 128 bit UUID */
-    public static final int UUID_BYTES_128_BIT = 16;
-
-    @UnsupportedAppUsage
-    public static final ParcelUuid[] RESERVED_UUIDS = {
-            AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget,
-            ObexObjectPush, PANU, NAP, MAP, MNS, MAS, SAP};
-
-    @UnsupportedAppUsage
-    public static boolean isAudioSource(ParcelUuid uuid) {
-        return uuid.equals(AudioSource);
-    }
-
-    public static boolean isAudioSink(ParcelUuid uuid) {
-        return uuid.equals(AudioSink);
-    }
-
-    @UnsupportedAppUsage
-    public static boolean isAdvAudioDist(ParcelUuid uuid) {
-        return uuid.equals(AdvAudioDist);
-    }
-
-    public static boolean isHandsfree(ParcelUuid uuid) {
-        return uuid.equals(Handsfree);
-    }
-
-    public static boolean isHeadset(ParcelUuid uuid) {
-        return uuid.equals(HSP);
-    }
-
-    public static boolean isAvrcpController(ParcelUuid uuid) {
-        return uuid.equals(AvrcpController);
-    }
-
-    @UnsupportedAppUsage
-    public static boolean isAvrcpTarget(ParcelUuid uuid) {
-        return uuid.equals(AvrcpTarget);
-    }
-
-    public static boolean isInputDevice(ParcelUuid uuid) {
-        return uuid.equals(Hid);
-    }
-
-    public static boolean isPanu(ParcelUuid uuid) {
-        return uuid.equals(PANU);
-    }
-
-    public static boolean isNap(ParcelUuid uuid) {
-        return uuid.equals(NAP);
-    }
-
-    public static boolean isBnep(ParcelUuid uuid) {
-        return uuid.equals(BNEP);
-    }
-
-    public static boolean isMap(ParcelUuid uuid) {
-        return uuid.equals(MAP);
-    }
-
-    public static boolean isMns(ParcelUuid uuid) {
-        return uuid.equals(MNS);
-    }
-
-    public static boolean isMas(ParcelUuid uuid) {
-        return uuid.equals(MAS);
-    }
-
-    public static boolean isSap(ParcelUuid uuid) {
-        return uuid.equals(SAP);
-    }
-
     /**
-     * Returns true if ParcelUuid is present in uuidArray
+     * Length of bytes for 16 bit UUID
      *
-     * @param uuidArray - Array of ParcelUuids
-     * @param uuid
+     * @hide
      */
-    @UnsupportedAppUsage
-    public static boolean isUuidPresent(ParcelUuid[] uuidArray, ParcelUuid uuid) {
-        if ((uuidArray == null || uuidArray.length == 0) && uuid == null) {
-            return true;
-        }
-
-        if (uuidArray == null) {
-            return false;
-        }
-
-        for (ParcelUuid element : uuidArray) {
-            if (element.equals(uuid)) return true;
-        }
-        return false;
-    }
+    @SystemApi
+    public static final int UUID_BYTES_16_BIT = 2;
+    /**
+     * Length of bytes for 32 bit UUID
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int UUID_BYTES_32_BIT = 4;
+    /**
+     * Length of bytes for 128 bit UUID
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int UUID_BYTES_128_BIT = 16;
 
     /**
      * Returns true if there any common ParcelUuids in uuidA and uuidB.
      *
      * @param uuidA - List of ParcelUuids
      * @param uuidB - List of ParcelUuids
+     *
+     * @hide
      */
-    @UnsupportedAppUsage
-    public static boolean containsAnyUuid(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
+    @SystemApi
+    public static boolean containsAnyUuid(@Nullable ParcelUuid[] uuidA,
+            @Nullable ParcelUuid[] uuidB) {
         if (uuidA == null && uuidB == null) return true;
 
         if (uuidA == null) {
@@ -218,29 +211,6 @@
     }
 
     /**
-     * Returns true if all the ParcelUuids in ParcelUuidB are present in
-     * ParcelUuidA
-     *
-     * @param uuidA - Array of ParcelUuidsA
-     * @param uuidB - Array of ParcelUuidsB
-     */
-    public static boolean containsAllUuids(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
-        if (uuidA == null && uuidB == null) return true;
-
-        if (uuidA == null) {
-            return uuidB.length == 0;
-        }
-
-        if (uuidB == null) return true;
-
-        HashSet<ParcelUuid> uuidSet = new HashSet<ParcelUuid>(Arrays.asList(uuidA));
-        for (ParcelUuid uuid : uuidB) {
-            if (!uuidSet.contains(uuid)) return false;
-        }
-        return true;
-    }
-
-    /**
      * Extract the Service Identifier or the actual uuid from the Parcel Uuid.
      * For example, if 0000110B-0000-1000-8000-00805F9B34FB is the parcel Uuid,
      * this function will return 110B
@@ -248,7 +218,7 @@
      * @param parcelUuid
      * @return the service identifier.
      */
-    public static int getServiceIdentifierFromParcelUuid(ParcelUuid parcelUuid) {
+    private static int getServiceIdentifierFromParcelUuid(ParcelUuid parcelUuid) {
         UUID uuid = parcelUuid.getUuid();
         long value = (uuid.getMostSignificantBits() & 0xFFFFFFFF00000000L) >>> 32;
         return (int) value;
@@ -262,8 +232,12 @@
      * @param uuidBytes Byte representation of uuid.
      * @return {@link ParcelUuid} parsed from bytes.
      * @throws IllegalArgumentException If the {@code uuidBytes} cannot be parsed.
+     *
+     * @hide
      */
-    public static ParcelUuid parseUuidFrom(byte[] uuidBytes) {
+    @NonNull
+    @SystemApi
+    public static ParcelUuid parseUuidFrom(@Nullable byte[] uuidBytes) {
         if (uuidBytes == null) {
             throw new IllegalArgumentException("uuidBytes cannot be null");
         }
@@ -305,6 +279,8 @@
      * @param uuid uuid to parse.
      * @return shortest representation of {@code uuid} as bytes.
      * @throws IllegalArgumentException If the {@code uuid} is null.
+     *
+     * @hide
      */
     public static byte[] uuidToBytes(ParcelUuid uuid) {
         if (uuid == null) {
@@ -345,6 +321,8 @@
      *
      * @param parcelUuid
      * @return true if the parcelUuid can be converted to 16 bit uuid, false otherwise.
+     *
+     * @hide
      */
     @UnsupportedAppUsage
     public static boolean is16BitUuid(ParcelUuid parcelUuid) {
@@ -361,6 +339,8 @@
      *
      * @param parcelUuid
      * @return true if the parcelUuid can be converted to 32 bit uuid, false otherwise.
+     *
+     * @hide
      */
     @UnsupportedAppUsage
     public static boolean is32BitUuid(ParcelUuid parcelUuid) {
@@ -373,4 +353,6 @@
         }
         return ((uuid.getMostSignificantBits() & 0xFFFFFFFFL) == 0x1000L);
     }
+
+    private BluetoothUuid() {}
 }
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index b6a0a56..999ec37 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -682,7 +682,7 @@
         }
 
         /** @hide */
-        public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        public void dumpDebug(ProtoOutputStream proto, long fieldId) {
             final long token = proto.start(fieldId);
 
             if (mHtmlText != null) {
@@ -692,7 +692,7 @@
             } else if (mUri != null) {
                 proto.write(ClipDataProto.Item.URI, mUri.toString());
             } else if (mIntent != null) {
-                mIntent.writeToProto(proto, ClipDataProto.Item.INTENT, true, true, true, true);
+                mIntent.dumpDebug(proto, ClipDataProto.Item.INTENT, true, true, true, true);
             } else {
                 proto.write(ClipDataProto.Item.NOTHING, true);
             }
@@ -1076,11 +1076,11 @@
     }
 
     /** @hide */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
 
         if (mClipDescription != null) {
-            mClipDescription.writeToProto(proto, ClipDataProto.DESCRIPTION);
+            mClipDescription.dumpDebug(proto, ClipDataProto.DESCRIPTION);
         }
         if (mIcon != null) {
             final long iToken = proto.start(ClipDataProto.ICON);
@@ -1089,7 +1089,7 @@
             proto.end(iToken);
         }
         for (int i = 0; i < mItems.size(); i++) {
-            mItems.get(i).writeToProto(proto, ClipDataProto.ITEMS);
+            mItems.get(i).dumpDebug(proto, ClipDataProto.ITEMS);
         }
 
         proto.end(token);
diff --git a/core/java/android/content/ClipDescription.java b/core/java/android/content/ClipDescription.java
index 0c6a935..6739138 100644
--- a/core/java/android/content/ClipDescription.java
+++ b/core/java/android/content/ClipDescription.java
@@ -349,7 +349,7 @@
     }
 
     /** @hide */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
 
         final int size = mMimeTypes.size();
@@ -361,7 +361,7 @@
             proto.write(ClipDescriptionProto.LABEL, mLabel.toString());
         }
         if (mExtras != null) {
-            mExtras.writeToProto(proto, ClipDescriptionProto.EXTRAS);
+            mExtras.dumpDebug(proto, ClipDescriptionProto.EXTRAS);
         }
         if (mTimeStamp > 0) {
             proto.write(ClipDescriptionProto.TIMESTAMP_MS, mTimeStamp);
diff --git a/core/java/android/content/ComponentName.java b/core/java/android/content/ComponentName.java
index 18147b5..33216d7 100644
--- a/core/java/android/content/ComponentName.java
+++ b/core/java/android/content/ComponentName.java
@@ -298,7 +298,7 @@
     }
 
     /** Put this here so that individual services don't have to reimplement this. @hide */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(ComponentNameProto.PACKAGE_NAME, mPackage);
         proto.write(ComponentNameProto.CLASS_NAME, mClass);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 4a0fc66..d370a38 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2484,6 +2484,48 @@
     }
 
     /**
+     * Version of
+     * {@link #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String,
+     * Bundle)} that allows you to specify the App Op to enforce restrictions on which receivers
+     * the broadcast will be sent to as well as supply an optional sending options
+     *
+     * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
+     *
+     * @param intent The Intent to broadcast; all receivers matching this
+     *               Intent will receive the broadcast.
+     * @param receiverPermission String naming a permissions that
+     *               a receiver must hold in order to receive your broadcast.
+     *               If null, no permission is required.
+     * @param receiverAppOp The app op associated with the broadcast. If null, no appOp is
+     *                      required. If both receiverAppOp and receiverPermission are non-null,
+     *                      a receiver must have both of them to
+     *                      receive the broadcast
+     * @param options (optional) Additional sending options, generated from a
+     * {@link android.app.BroadcastOptions}.
+     * @param resultReceiver Your own BroadcastReceiver to treat as the final
+     *                       receiver of the broadcast.
+     * @param scheduler A custom Handler with which to schedule the
+     *                  resultReceiver callback; if null it will be
+     *                  scheduled in the Context's main thread.
+     * @param initialCode An initial value for the result code.  Often
+     *                    Activity.RESULT_OK.
+     * @param initialData An initial value for the result data.  Often
+     *                    null.
+     * @param initialExtras An initial value for the result extras.  Often
+     *                      null.
+     *
+     * @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
+     * @see android.app.BroadcastOptions
+     */
+    public void sendOrderedBroadcast(@RequiresPermission @NonNull Intent intent,
+            @Nullable String receiverPermission, @Nullable String receiverAppOp,
+            @Nullable Bundle options, @Nullable BroadcastReceiver resultReceiver,
+            @Nullable Handler scheduler, int initialCode, @Nullable String initialData,
+            @Nullable Bundle initialExtras) {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
+
+    /**
      * <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
      * Intent you are sending stays around after the broadcast is complete,
      * so that others can quickly retrieve that data through the return
@@ -3383,6 +3425,7 @@
             CROSS_PROFILE_APPS_SERVICE,
             //@hide: SYSTEM_UPDATE_SERVICE,
             //@hide: TIME_DETECTOR_SERVICE,
+            //@hide: TIME_ZONE_DETECTOR_SERVICE,
             PERMISSION_SERVICE,
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -4835,7 +4878,7 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve an
-     * {@link android.app.timedetector.ITimeDetectorService}.
+     * {@link android.app.timedetector.TimeDetector}.
      * @hide
      *
      * @see #getSystemService(String)
@@ -4843,6 +4886,15 @@
     public static final String TIME_DETECTOR_SERVICE = "time_detector";
 
     /**
+     * Use with {@link #getSystemService(String)} to retrieve an
+     * {@link android.app.timezonedetector.TimeZoneDetector}.
+     * @hide
+     *
+     * @see #getSystemService(String)
+     */
+    public static final String TIME_ZONE_DETECTOR_SERVICE = "time_zone_detector";
+
+    /**
      * Binder service name for {@link AppBindingService}.
      * @hide
      */
@@ -4917,6 +4969,20 @@
     public static final String APP_INTEGRITY_SERVICE = "app_integrity";
 
     /**
+     * Use with {@link #getSystemService(String)} to retrieve an
+     * {@link android.content.pm.DataLoaderManager}.
+     * @hide
+     */
+    public static final String DATA_LOADER_MANAGER_SERVICE = "dataloadermanager";
+
+    /**
+     * Use with {@link #getSystemService(String)} to retrieve an
+     * {@link android.os.incremental.IncrementalManager}.
+     * @hide
+     */
+    public static final String INCREMENTAL_SERVICE = "incremental";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index e44d6ae..d6442e2 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -590,6 +590,16 @@
     }
 
     @Override
+    public void sendOrderedBroadcast(@RequiresPermission @NonNull Intent intent,
+            @Nullable String receiverPermission, @Nullable String receiverAppOp,
+            @Nullable Bundle options, @Nullable BroadcastReceiver resultReceiver,
+            @Nullable Handler scheduler, int initialCode, @Nullable String initialData,
+            @Nullable Bundle initialExtras) {
+        mBase.sendOrderedBroadcast(intent, receiverPermission, receiverAppOp, options,
+                resultReceiver, scheduler, initialCode, initialData, initialExtras);
+    }
+
+    @Override
     @Deprecated
     public void sendStickyBroadcast(Intent intent) {
         mBase.sendStickyBroadcast(intent);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 40aca0e..7815a33 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -4053,6 +4053,13 @@
     public static final String ACTION_SERVICE_STATE = "android.intent.action.SERVICE_STATE";
 
     /**
+     * Used for looking up a Data Loader Service providers.
+     * @hide
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String ACTION_LOAD_DATA = "android.intent.action.LOAD_DATA";
+
+    /**
      * An int extra used with {@link #ACTION_SERVICE_STATE} which indicates voice registration
      * state.
      * @see android.telephony.ServiceState#STATE_EMERGENCY_ONLY
@@ -10286,26 +10293,26 @@
     }
 
     /** @hide */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         // Same input parameters that toString() gives to toShortString().
-        writeToProto(proto, fieldId, true, true, true, false);
+        dumpDebug(proto, fieldId, true, true, true, false);
     }
 
     /** @hide */
-    public void writeToProto(ProtoOutputStream proto) {
+    public void dumpDebug(ProtoOutputStream proto) {
         // Same input parameters that toString() gives to toShortString().
-        writeToProtoWithoutFieldId(proto, true, true, true, false);
+        dumpDebugWithoutFieldId(proto, true, true, true, false);
     }
 
     /** @hide */
-    public void writeToProto(ProtoOutputStream proto, long fieldId, boolean secure, boolean comp,
+    public void dumpDebug(ProtoOutputStream proto, long fieldId, boolean secure, boolean comp,
             boolean extras, boolean clip) {
         long token = proto.start(fieldId);
-        writeToProtoWithoutFieldId(proto, secure, comp, extras, clip);
+        dumpDebugWithoutFieldId(proto, secure, comp, extras, clip);
         proto.end(token);
     }
 
-    private void writeToProtoWithoutFieldId(ProtoOutputStream proto, boolean secure, boolean comp,
+    private void dumpDebugWithoutFieldId(ProtoOutputStream proto, boolean secure, boolean comp,
             boolean extras, boolean clip) {
         if (mAction != null) {
             proto.write(IntentProto.ACTION, mAction);
@@ -10331,7 +10338,7 @@
             proto.write(IntentProto.PACKAGE, mPackage);
         }
         if (comp && mComponent != null) {
-            mComponent.writeToProto(proto, IntentProto.COMPONENT);
+            mComponent.dumpDebug(proto, IntentProto.COMPONENT);
         }
         if (mSourceBounds != null) {
             proto.write(IntentProto.SOURCE_BOUNDS, mSourceBounds.toShortString());
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 099dea2..93390bd 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -924,7 +924,7 @@
             dest.writeInt(mPort);
         }
 
-        void writeToProto(ProtoOutputStream proto, long fieldId) {
+        void dumpDebug(ProtoOutputStream proto, long fieldId) {
             long token = proto.start(fieldId);
             // The original host information is already contained in host and wild, no output now.
             proto.write(AuthorityEntryProto.HOST, mHost);
@@ -1758,7 +1758,7 @@
     }
 
     /** @hide */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         long token = proto.start(fieldId);
         if (mActions.size() > 0) {
             Iterator<String> it = mActions.iterator();
@@ -1781,19 +1781,19 @@
         if (mDataSchemeSpecificParts != null) {
             Iterator<PatternMatcher> it = mDataSchemeSpecificParts.iterator();
             while (it.hasNext()) {
-                it.next().writeToProto(proto, IntentFilterProto.DATA_SCHEME_SPECS);
+                it.next().dumpDebug(proto, IntentFilterProto.DATA_SCHEME_SPECS);
             }
         }
         if (mDataAuthorities != null) {
             Iterator<AuthorityEntry> it = mDataAuthorities.iterator();
             while (it.hasNext()) {
-                it.next().writeToProto(proto, IntentFilterProto.DATA_AUTHORITIES);
+                it.next().dumpDebug(proto, IntentFilterProto.DATA_AUTHORITIES);
             }
         }
         if (mDataPaths != null) {
             Iterator<PatternMatcher> it = mDataPaths.iterator();
             while (it.hasNext()) {
-                it.next().writeToProto(proto, IntentFilterProto.DATA_PATHS);
+                it.next().dumpDebug(proto, IntentFilterProto.DATA_PATHS);
             }
         }
         if (mDataTypes != null) {
diff --git a/core/java/android/content/integrity/AtomicFormula.java b/core/java/android/content/integrity/AtomicFormula.java
index c8e164f..574a93f 100644
--- a/core/java/android/content/integrity/AtomicFormula.java
+++ b/core/java/android/content/integrity/AtomicFormula.java
@@ -44,6 +44,7 @@
 
     private static final String TAG = "AtomicFormula";
 
+    /** @hide */
     @IntDef(
             value = {
                 PACKAGE_NAME,
@@ -56,6 +57,7 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface Key {}
 
+    /** @hide */
     @IntDef(value = {EQ, LT, LE, GT, GE})
     @Retention(RetentionPolicy.SOURCE)
     public @interface Operator {}
diff --git a/core/java/android/content/integrity/CompoundFormula.java b/core/java/android/content/integrity/CompoundFormula.java
index 53a9953..2a651d9 100644
--- a/core/java/android/content/integrity/CompoundFormula.java
+++ b/core/java/android/content/integrity/CompoundFormula.java
@@ -47,6 +47,7 @@
 public final class CompoundFormula implements Formula, Parcelable {
     private static final String TAG = "OpenFormula";
 
+    /** @hide */
     @IntDef(
             value = {
                 AND, OR, NOT,
diff --git a/core/java/android/content/integrity/Formula.java b/core/java/android/content/integrity/Formula.java
index 030ff6b..b092a22 100644
--- a/core/java/android/content/integrity/Formula.java
+++ b/core/java/android/content/integrity/Formula.java
@@ -38,6 +38,7 @@
 @SystemApi
 @VisibleForTesting
 public interface Formula {
+    /** @hide */
     @IntDef(
             value = {
                     COMPOUND_FORMULA_TAG,
diff --git a/core/java/android/content/integrity/Rule.java b/core/java/android/content/integrity/Rule.java
index 914f147..39a0909 100644
--- a/core/java/android/content/integrity/Rule.java
+++ b/core/java/android/content/integrity/Rule.java
@@ -42,6 +42,7 @@
 @VisibleForTesting
 public final class Rule implements Parcelable {
 
+    /** @hide */
     @IntDef(
             value = {
                 DENY,
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index e724443..26193f6 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1376,7 +1376,8 @@
             this.minHeight = minHeight;
         }
 
-        WindowLayout(Parcel source) {
+        /** @hide */
+        public WindowLayout(Parcel source) {
             width = source.readInt();
             widthFraction = source.readFloat();
             height = source.readInt();
diff --git a/core/java/android/content/pm/AndroidHidlUpdater.java b/core/java/android/content/pm/AndroidHidlUpdater.java
deleted file mode 100644
index d0657e5..0000000
--- a/core/java/android/content/pm/AndroidHidlUpdater.java
+++ /dev/null
@@ -1,52 +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 android.content.pm;
-
-import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_BASE;
-import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER;
-
-import android.content.pm.PackageParser.Package;
-import android.os.Build;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * Updates a package to ensure that if it targets <= P that the android.hidl.base-V1.0-java
- * and android.hidl.manager-V1.0-java libraries are included by default.
- *
- * @hide
- */
-@VisibleForTesting
-public class AndroidHidlUpdater extends PackageSharedLibraryUpdater {
-
-    @Override
-    public void updatePackage(Package pkg) {
-        ApplicationInfo info = pkg.applicationInfo;
-
-        // This was the default <= P and is maintained for backwards compatibility.
-        boolean isLegacy = info.targetSdkVersion <= Build.VERSION_CODES.P;
-        // Only system apps use these libraries
-        boolean isSystem = info.isSystemApp() || info.isUpdatedSystemApp();
-
-        if (isLegacy && isSystem) {
-            prefixRequiredLibrary(pkg, ANDROID_HIDL_BASE);
-            prefixRequiredLibrary(pkg, ANDROID_HIDL_MANAGER);
-        } else {
-            removeLibrary(pkg, ANDROID_HIDL_BASE);
-            removeLibrary(pkg, ANDROID_HIDL_MANAGER);
-        }
-    }
-}
diff --git a/core/java/android/content/pm/AndroidTestBaseUpdater.java b/core/java/android/content/pm/AndroidTestBaseUpdater.java
deleted file mode 100644
index 18d3ba3..0000000
--- a/core/java/android/content/pm/AndroidTestBaseUpdater.java
+++ /dev/null
@@ -1,88 +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 android.content.pm;
-
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER;
-
-import android.compat.annotation.ChangeId;
-import android.compat.annotation.EnabledAfter;
-import android.content.Context;
-import android.content.pm.PackageParser.Package;
-import android.os.Build;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.compat.IPlatformCompat;
-
-/**
- * Updates a package to ensure that if it targets <= Q that the android.test.base library is
- * included by default.
- *
- * <p>This is separated out so that it can be conditionally included at build time depending on
- * whether android.test.base is on the bootclasspath or not. In order to include this at
- * build time, and remove android.test.base from the bootclasspath pass
- * REMOVE_ATB_FROM_BCP=true on the build command line, otherwise this class will not be included
- * and the
- *
- * @hide
- */
-@VisibleForTesting
-public class AndroidTestBaseUpdater extends PackageSharedLibraryUpdater {
-    private static final String TAG = "AndroidTestBaseUpdater";
-
-    /**
-     * Remove android.test.base library for apps that target SDK R or more and do not depend on
-     * android.test.runner (as it depends on classes from the android.test.base library).
-     */
-    @ChangeId
-    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
-    private static final long REMOVE_ANDROID_TEST_BASE = 133396946L;
-
-    private static boolean isChangeEnabled(Package pkg) {
-        // Do not ask platform compat for system apps to prevent a boot time regression in tests.
-        // b/142558883.
-        if (!pkg.applicationInfo.isSystemApp()) {
-            IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
-                    ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
-            try {
-                return platformCompat.isChangeEnabled(REMOVE_ANDROID_TEST_BASE,
-                        pkg.applicationInfo);
-            } catch (RemoteException | NullPointerException e) {
-                Log.e(TAG, "Failed to get a response from PLATFORM_COMPAT_SERVICE", e);
-            }
-        }
-        // Fall back to previous behaviour.
-        return pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.Q;
-    }
-
-    @Override
-    public void updatePackage(Package pkg) {
-        // Packages targeted at <= Q expect the classes in the android.test.base library
-        // to be accessible so this maintains backward compatibility by adding the
-        // android.test.base library to those packages.
-        if (!isChangeEnabled(pkg)) {
-            prefixRequiredLibrary(pkg, ANDROID_TEST_BASE);
-        } else {
-            // If a package already depends on android.test.runner then add a dependency on
-            // android.test.base because android.test.runner depends on classes from the
-            // android.test.base library.
-            prefixImplicitDependency(pkg, ANDROID_TEST_RUNNER, ANDROID_TEST_BASE);
-        }
-    }
-}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 37c6f57..552c8ac 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1398,9 +1398,9 @@
     }
 
     /** {@hide} */
-    public void writeToProto(ProtoOutputStream proto, long fieldId, int dumpFlags) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId, int dumpFlags) {
         long token = proto.start(fieldId);
-        super.writeToProto(proto, ApplicationInfoProto.PACKAGE, dumpFlags);
+        super.dumpDebug(proto, ApplicationInfoProto.PACKAGE, dumpFlags);
         proto.write(ApplicationInfoProto.PERMISSION, permission);
         proto.write(ApplicationInfoProto.PROCESS_NAME, processName);
         proto.write(ApplicationInfoProto.UID, uid);
diff --git a/core/java/android/content/pm/DataLoaderManager.java b/core/java/android/content/pm/DataLoaderManager.java
new file mode 100644
index 0000000..2688038
--- /dev/null
+++ b/core/java/android/content/pm/DataLoaderManager.java
@@ -0,0 +1,87 @@
+/*
+ * 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.content.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.RemoteException;
+
+/**
+ * Data loader manager takes care of data loaders of different packages. It provides methods to
+ * initialize a data loader binder service (binding and creating it), to return a binder of the data
+ * loader binder service and to destroy a data loader binder service.
+ * @see com.android.server.pm.DataLoaderManagerService
+ * @hide
+ */
+public class DataLoaderManager {
+    private static final String TAG = "DataLoaderManager";
+    private final IDataLoaderManager mService;
+
+    public DataLoaderManager(IDataLoaderManager service) {
+        mService = service;
+    }
+
+    /**
+     * Finds a data loader binder service and binds to it. This requires PackageManager.
+     *
+     * @param dataLoaderId ID for the new data loader binder service.
+     * @param params       Bundle that contains parameters to configure the data loader service.
+     *                     Must contain:
+     *                     key: "packageName", value: String, package name of data loader service
+     *                     package;
+     *                     key: "extras", value: Bundle, client-specific data structures
+     *
+     * @param listener     Callback for the data loader service to report status back to the
+     *                     caller.
+     * @return false if 1) target ID collides with a data loader that is already bound to data
+     * loader manager; 2) package name is not specified; 3) fails to find data loader package;
+     * or 4) fails to bind to the specified data loader service, otherwise return true.
+     */
+    public boolean initializeDataLoader(int dataLoaderId, @NonNull Bundle params,
+            @NonNull IDataLoaderStatusListener listener) {
+        try {
+            return mService.initializeDataLoader(dataLoaderId, params, listener);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns a binder interface of the data loader binder service, given its ID.
+     */
+    @Nullable
+    public IDataLoader getDataLoader(int dataLoaderId) {
+        try {
+            return mService.getDataLoader(dataLoaderId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Destroys the data loader binder service and removes it from data loader manager service.
+     */
+    @Nullable
+    public void destroyDataLoader(int dataLoaderId) {
+        try {
+            mService.destroyDataLoader(dataLoaderId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/core/java/android/content/pm/FeatureInfo.java b/core/java/android/content/pm/FeatureInfo.java
index dc576e8..9f3ab77 100644
--- a/core/java/android/content/pm/FeatureInfo.java
+++ b/core/java/android/content/pm/FeatureInfo.java
@@ -115,7 +115,7 @@
     }
 
     /** @hide */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         long token = proto.start(fieldId);
         if (name != null) {
             proto.write(FeatureInfoProto.NAME, name);
diff --git a/core/java/android/content/pm/IDataLoader.aidl b/core/java/android/content/pm/IDataLoader.aidl
new file mode 100644
index 0000000..60cc9ba9
--- /dev/null
+++ b/core/java/android/content/pm/IDataLoader.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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.content.pm;
+
+import android.os.Bundle;
+import android.content.pm.IDataLoaderStatusListener;
+import android.content.pm.InstallationFile;
+import java.util.List;
+
+/**
+ * TODO: update with new APIs
+ * @hide
+ */
+oneway interface IDataLoader {
+   void create(int id, in Bundle params, IDataLoaderStatusListener listener);
+   void start(in List<InstallationFile> fileInfos);
+   void stop();
+   void destroy();
+   void onFileCreated(long inode, in byte[] metadata);
+}
diff --git a/core/java/android/content/pm/IDataLoaderManager.aidl b/core/java/android/content/pm/IDataLoaderManager.aidl
new file mode 100644
index 0000000..f453c9b
--- /dev/null
+++ b/core/java/android/content/pm/IDataLoaderManager.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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.content.pm;
+
+import android.os.Bundle;
+import android.content.pm.IDataLoader;
+import android.content.pm.IDataLoaderStatusListener;
+import java.util.List;
+
+/** @hide */
+interface IDataLoaderManager {
+    boolean initializeDataLoader(int id, in Bundle params, IDataLoaderStatusListener listener);
+    IDataLoader getDataLoader(int dataLoaderId);
+    void destroyDataLoader(int dataLoaderId);
+}
\ No newline at end of file
diff --git a/core/java/android/content/pm/IDataLoaderStatusListener.aidl b/core/java/android/content/pm/IDataLoaderStatusListener.aidl
new file mode 100644
index 0000000..a60d6ee
--- /dev/null
+++ b/core/java/android/content/pm/IDataLoaderStatusListener.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.content.pm;
+
+/**
+ * Callbacks from a data loader binder service to report data loader status.
+ * @hide
+ */
+oneway interface IDataLoaderStatusListener {
+    /** Data loader status */
+    const int DATA_LOADER_READY = 0;
+    const int DATA_LOADER_NOT_READY = 1;
+    const int DATA_LOADER_RUNNING = 2;
+    const int DATA_LOADER_STOPPED = 3;
+    const int DATA_LOADER_SLOW_CONNECTION = 4;
+    const int DATA_LOADER_NO_CONNECTION = 5;
+    const int DATA_LOADER_CONNECTION_OK = 6;
+
+    /** Data loader status callback */
+    void onStatusChanged(in int dataLoaderId, in int status);
+}
+
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index 04e15c7..0b3c765 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -36,7 +36,7 @@
 
     void close();
     void commit(in IntentSender statusReceiver, boolean forTransferred);
-    void transfer(in String packageName);
+    void transfer(in String packageName, in IntentSender statusReceiver);
     void abandon();
 
     boolean isMultiPackage();
@@ -46,4 +46,5 @@
     int getParentSessionId();
 
     boolean isStaged();
+    void addFile(in String name, long size, in byte[] metadata);
 }
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index a71367d..b3d8eb5 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -26,6 +26,7 @@
 import android.content.pm.InstantAppInfo;
 import android.content.pm.FeatureInfo;
 import android.content.pm.IDexModuleRegisterCallback;
+import android.content.pm.InstallSourceInfo;
 import android.content.pm.IPackageInstaller;
 import android.content.pm.IPackageDeleteObserver;
 import android.content.pm.IPackageDeleteObserver2;
@@ -237,6 +238,8 @@
     @UnsupportedAppUsage
     String getInstallerPackageName(in String packageName);
 
+    InstallSourceInfo getInstallSourceInfo(in String packageName);
+
     void resetApplicationPreferences(int userId);
 
     @UnsupportedAppUsage
diff --git a/core/java/android/content/pm/InstallSourceInfo.aidl b/core/java/android/content/pm/InstallSourceInfo.aidl
new file mode 100644
index 0000000..21ee4c3
--- /dev/null
+++ b/core/java/android/content/pm/InstallSourceInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+parcelable InstallSourceInfo;
diff --git a/core/java/android/content/pm/InstallSourceInfo.java b/core/java/android/content/pm/InstallSourceInfo.java
new file mode 100644
index 0000000..4d235f1
--- /dev/null
+++ b/core/java/android/content/pm/InstallSourceInfo.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Information about how an app was installed.
+ * @see PackageManager#getInstallSourceInfo(String)
+ */
+public final class InstallSourceInfo implements Parcelable {
+
+    @Nullable private final String mInitiatingPackageName;
+
+    @Nullable private final String mOriginatingPackageName;
+
+    @Nullable private final String mInstallingPackageName;
+
+    /** @hide */
+    public InstallSourceInfo(@Nullable String initiatingPackageName,
+            @Nullable String originatingPackageName, @Nullable String installingPackageName) {
+        this.mInitiatingPackageName = initiatingPackageName;
+        this.mOriginatingPackageName = originatingPackageName;
+        this.mInstallingPackageName = installingPackageName;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString(mInitiatingPackageName);
+        dest.writeString(mOriginatingPackageName);
+        dest.writeString(mInstallingPackageName);
+    }
+
+    private InstallSourceInfo(Parcel source) {
+        mInitiatingPackageName = source.readString();
+        mOriginatingPackageName = source.readString();
+        mInstallingPackageName = source.readString();
+    }
+
+    /** The name of the package that requested the installation, or null if not available. */
+    @Nullable
+    public String getInitiatingPackageName() {
+        return mInitiatingPackageName;
+    }
+
+    /**
+     * The name of the package on behalf of which the initiating package requested the installation,
+     * or null if not available.
+     * <p>
+     * For example if a downloaded APK is installed via the Package Installer this could be the
+     * app that performed the download. This value is provided by the initiating package and not
+     * verified by the framework.
+     * <p>
+     * Note that the {@code InstallSourceInfo} returned by
+     * {@link PackageManager#getInstallSourceInfo(String)} will not have this information
+     * available unless the calling application holds the INSTALL_PACKAGES permission.
+     */
+    @Nullable
+    public String getOriginatingPackageName() {
+        return mOriginatingPackageName;
+    }
+
+    /**
+     * The name of the package responsible for the installation (the installer of record), or null
+     * if not available.
+     * Note that this may differ from the initiating package name and can be modified.
+     *
+     * @see PackageManager#setInstallerPackageName(String, String)
+     */
+    @Nullable
+    public String getInstallingPackageName() {
+        return mInstallingPackageName;
+    }
+
+    @NonNull
+    public static final Parcelable.Creator<InstallSourceInfo> CREATOR =
+            new Creator<InstallSourceInfo>() {
+                @Override
+                public InstallSourceInfo createFromParcel(Parcel source) {
+                    return new InstallSourceInfo(source);
+                }
+
+                @Override
+                public InstallSourceInfo[] newArray(int size) {
+                    return new InstallSourceInfo[size];
+                }
+            };
+}
diff --git a/core/java/android/content/pm/InstallationFile.aidl b/core/java/android/content/pm/InstallationFile.aidl
new file mode 100644
index 0000000..1edff9d
--- /dev/null
+++ b/core/java/android/content/pm/InstallationFile.aidl
@@ -0,0 +1,23 @@
+/*
+ * 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.content.pm;
+
+/**
+ * Describes a file which is part of a package installation.
+ */
+parcelable InstallationFile;
+
diff --git a/core/java/android/content/pm/InstallationFile.java b/core/java/android/content/pm/InstallationFile.java
new file mode 100644
index 0000000..ac5fd1e
--- /dev/null
+++ b/core/java/android/content/pm/InstallationFile.java
@@ -0,0 +1,118 @@
+/*
+ * 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.content.pm;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Defines the properties of a file in an installation session.
+ * TODO(b/136132412): update with new APIs.
+ *
+ * @hide
+ */
+public final class InstallationFile implements Parcelable {
+    public static final int FILE_TYPE_UNKNOWN = -1;
+    public static final int FILE_TYPE_APK = 0;
+    public static final int FILE_TYPE_LIB = 1;
+    public static final int FILE_TYPE_OBB = 2;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"FILE_TYPE_"}, value = {
+            FILE_TYPE_APK,
+            FILE_TYPE_LIB,
+            FILE_TYPE_OBB,
+    })
+    public @interface FileType {
+    }
+
+    private String mFileName;
+    private @FileType int mFileType;
+    private long mFileSize;
+    private byte[] mMetadata;
+
+    public InstallationFile(@NonNull String fileName, long fileSize,
+            @Nullable byte[] metadata) {
+        mFileName = fileName;
+        mFileSize = fileSize;
+        mMetadata = metadata;
+        if (fileName.toLowerCase().endsWith(".apk")) {
+            mFileType = FILE_TYPE_APK;
+        } else if (fileName.toLowerCase().endsWith(".obb")) {
+            mFileType = FILE_TYPE_OBB;
+        } else if (fileName.toLowerCase().endsWith(".so") && fileName.toLowerCase().startsWith(
+                "lib/")) {
+            mFileType = FILE_TYPE_LIB;
+        } else {
+            mFileType = FILE_TYPE_UNKNOWN;
+        }
+    }
+
+    public @FileType int getFileType() {
+        return mFileType;
+    }
+
+    public @NonNull String getName() {
+        return mFileName;
+    }
+
+    public long getSize() {
+        return mFileSize;
+    }
+
+    public @Nullable byte[] getMetadata() {
+        return mMetadata;
+    }
+
+    private InstallationFile(Parcel source) {
+        mFileName = source.readString();
+        mFileType = source.readInt();
+        mFileSize = source.readLong();
+        mMetadata = source.createByteArray();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString(mFileName);
+        dest.writeInt(mFileType);
+        dest.writeLong(mFileSize);
+        dest.writeByteArray(mMetadata);
+    }
+
+    public static final @NonNull Creator<InstallationFile> CREATOR =
+            new Creator<InstallationFile>() {
+        public InstallationFile createFromParcel(Parcel source) {
+            return new InstallationFile(source);
+        }
+
+        public InstallationFile[] newArray(int size) {
+            return new InstallationFile[size];
+        }
+    };
+
+}
diff --git a/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java b/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java
deleted file mode 100644
index 707443b..0000000
--- a/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java
+++ /dev/null
@@ -1,48 +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 android.content.pm;
-
-import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
-
-import android.content.pm.PackageParser.Package;
-import android.os.Build;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * Updates a package to ensure that if it targets < P that the org.apache.http.legacy library is
- * included by default.
- *
- * @hide
- */
-@VisibleForTesting
-public class OrgApacheHttpLegacyUpdater extends PackageSharedLibraryUpdater {
-
-    private static boolean apkTargetsApiLevelLessThanOrEqualToOMR1(Package pkg) {
-        int targetSdkVersion = pkg.applicationInfo.targetSdkVersion;
-        return targetSdkVersion < Build.VERSION_CODES.P;
-    }
-
-    @Override
-    public void updatePackage(Package pkg) {
-        // Packages targeted at <= O_MR1 expect the classes in the org.apache.http.legacy library
-        // to be accessible so this maintains backward compatibility by adding the
-        // org.apache.http.legacy library to those packages.
-        if (apkTargetsApiLevelLessThanOrEqualToOMR1(pkg)) {
-            prefixRequiredLibrary(pkg, ORG_APACHE_HTTP_LEGACY);
-        }
-    }
-}
diff --git a/core/java/android/content/pm/PackageBackwardCompatibility.java b/core/java/android/content/pm/PackageBackwardCompatibility.java
deleted file mode 100644
index 4331bd4..0000000
--- a/core/java/android/content/pm/PackageBackwardCompatibility.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_MOCK;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER;
-import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
-
-import android.content.pm.PackageParser.Package;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.function.Supplier;
-
-/**
- * Modifies {@link Package} in order to maintain backwards compatibility.
- *
- * @hide
- */
-@VisibleForTesting
-public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater {
-
-    private static final String TAG = PackageBackwardCompatibility.class.getSimpleName();
-
-    private static final PackageBackwardCompatibility INSTANCE;
-
-    static {
-        final List<PackageSharedLibraryUpdater> packageUpdaters = new ArrayList<>();
-
-        // Automatically add the org.apache.http.legacy library to the app classpath if the app
-        // targets < P.
-        packageUpdaters.add(new OrgApacheHttpLegacyUpdater());
-
-        packageUpdaters.add(new AndroidHidlUpdater());
-
-        // Add this before adding AndroidTestBaseUpdater so that android.test.base comes before
-        // android.test.mock.
-        packageUpdaters.add(new AndroidTestRunnerSplitUpdater());
-
-        // Attempt to load and add the optional updater that will only be available when
-        // REMOVE_ATB_FROM_BCP=true. If that could not be found then add the default updater that
-        // will remove any references to org.apache.http.library from the package so that it does
-        // not try and load the library when it is on the bootclasspath.
-        boolean bootClassPathContainsATB = !addOptionalUpdater(packageUpdaters,
-                "android.content.pm.AndroidTestBaseUpdater",
-                RemoveUnnecessaryAndroidTestBaseLibrary::new);
-
-        PackageSharedLibraryUpdater[] updaterArray = packageUpdaters
-                .toArray(new PackageSharedLibraryUpdater[0]);
-        INSTANCE = new PackageBackwardCompatibility(
-                bootClassPathContainsATB, updaterArray);
-    }
-
-    /**
-     * Add an optional {@link PackageSharedLibraryUpdater} instance to the list, if it could not be
-     * found then add a default instance instead.
-     *
-     * @param packageUpdaters the list to update.
-     * @param className the name of the optional class.
-     * @param defaultUpdater the supplier of the default instance.
-     * @return true if the optional updater was added false otherwise.
-     */
-    private static boolean addOptionalUpdater(List<PackageSharedLibraryUpdater> packageUpdaters,
-            String className, Supplier<PackageSharedLibraryUpdater> defaultUpdater) {
-        Class<? extends PackageSharedLibraryUpdater> clazz;
-        try {
-            clazz = (PackageBackwardCompatibility.class.getClassLoader()
-                    .loadClass(className)
-                    .asSubclass(PackageSharedLibraryUpdater.class));
-            Log.i(TAG, "Loaded " + className);
-        } catch (ClassNotFoundException e) {
-            Log.i(TAG, "Could not find " + className + ", ignoring");
-            clazz = null;
-        }
-
-        boolean usedOptional = false;
-        PackageSharedLibraryUpdater updater;
-        if (clazz == null) {
-            updater = defaultUpdater.get();
-        } else {
-            try {
-                updater = clazz.getConstructor().newInstance();
-                usedOptional = true;
-            } catch (ReflectiveOperationException e) {
-                throw new IllegalStateException("Could not create instance of " + className, e);
-            }
-        }
-        packageUpdaters.add(updater);
-        return usedOptional;
-    }
-
-    @VisibleForTesting
-    public static PackageSharedLibraryUpdater getInstance() {
-        return INSTANCE;
-    }
-
-    private final boolean mBootClassPathContainsATB;
-
-    private final PackageSharedLibraryUpdater[] mPackageUpdaters;
-
-    private PackageBackwardCompatibility(
-            boolean bootClassPathContainsATB, PackageSharedLibraryUpdater[] packageUpdaters) {
-        this.mBootClassPathContainsATB = bootClassPathContainsATB;
-        this.mPackageUpdaters = packageUpdaters;
-    }
-
-    /**
-     * Modify the shared libraries in the supplied {@link Package} to maintain backwards
-     * compatibility.
-     *
-     * @param pkg the {@link Package} to modify.
-     */
-    @VisibleForTesting
-    public static void modifySharedLibraries(Package pkg) {
-        INSTANCE.updatePackage(pkg);
-    }
-
-    @Override
-    public void updatePackage(Package pkg) {
-        for (PackageSharedLibraryUpdater packageUpdater : mPackageUpdaters) {
-            packageUpdater.updatePackage(pkg);
-        }
-    }
-
-    /**
-     * True if the android.test.base is on the bootclasspath, false otherwise.
-     */
-    @VisibleForTesting
-    public static boolean bootClassPathContainsATB() {
-        return INSTANCE.mBootClassPathContainsATB;
-    }
-
-    /**
-     * Add android.test.mock dependency for any APK that depends on android.test.runner.
-     *
-     * <p>This is needed to maintain backwards compatibility as in previous versions of Android the
-     * android.test.runner library included the classes from android.test.mock which have since
-     * been split out into a separate library.
-     *
-     * @hide
-     */
-    @VisibleForTesting
-    public static class AndroidTestRunnerSplitUpdater extends PackageSharedLibraryUpdater {
-
-        @Override
-        public void updatePackage(Package pkg) {
-            // android.test.runner has a dependency on android.test.mock so if android.test.runner
-            // is present but android.test.mock is not then add android.test.mock.
-            prefixImplicitDependency(pkg, ANDROID_TEST_RUNNER, ANDROID_TEST_MOCK);
-        }
-    }
-
-    /**
-     * Remove any usages of org.apache.http.legacy from the shared library as the library is on the
-     * bootclasspath.
-     */
-    @VisibleForTesting
-    public static class RemoveUnnecessaryOrgApacheHttpLegacyLibrary
-            extends PackageSharedLibraryUpdater {
-
-        @Override
-        public void updatePackage(Package pkg) {
-            removeLibrary(pkg, ORG_APACHE_HTTP_LEGACY);
-        }
-
-    }
-
-    /**
-     * Remove any usages of android.test.base from the shared library as the library is on the
-     * bootclasspath.
-     */
-    @VisibleForTesting
-    public static class RemoveUnnecessaryAndroidTestBaseLibrary
-            extends PackageSharedLibraryUpdater {
-
-        @Override
-        public void updatePackage(Package pkg) {
-            removeLibrary(pkg, ANDROID_TEST_BASE);
-        }
-    }
-}
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index d6fb28f..aa0002d 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -373,8 +373,9 @@
 
     /**
      * Whether the overlay is static, meaning it cannot be enabled/disabled at runtime.
+     * @hide
      */
-    boolean mOverlayIsStatic;
+    public boolean mOverlayIsStatic;
 
     /**
      * The user-visible SDK version (ex. 26) of the framework against which the application claims
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 0c52979..f017aad 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -29,6 +29,8 @@
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
 import android.app.AppGlobals;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.pm.PackageManager.DeleteFlags;
@@ -36,9 +38,11 @@
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Build;
+import android.os.Bundle;
 import android.os.FileBridge;
 import android.os.Handler;
 import android.os.HandlerExecutor;
+import android.os.IBinder;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
@@ -46,6 +50,8 @@
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.incremental.IncrementalDataLoaderParams;
+import android.os.incremental.IncrementalDataLoaderParamsParcel;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.util.ArraySet;
@@ -67,6 +73,8 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 import java.util.stream.Collectors;
 
@@ -176,8 +184,9 @@
      * {@link #STATUS_PENDING_USER_ACTION}, {@link #STATUS_SUCCESS},
      * {@link #STATUS_FAILURE}, {@link #STATUS_FAILURE_ABORTED},
      * {@link #STATUS_FAILURE_BLOCKED}, {@link #STATUS_FAILURE_CONFLICT},
-     * {@link #STATUS_FAILURE_INCOMPATIBLE}, {@link #STATUS_FAILURE_INVALID}, or
-     * {@link #STATUS_FAILURE_STORAGE}.
+     * {@link #STATUS_FAILURE_INCOMPATIBLE}, {@link #STATUS_FAILURE_INVALID},
+     * {@link #STATUS_FAILURE_STORAGE}, {@link #STATUS_FAILURE_NAME_NOT_FOUND},
+     * {@link #STATUS_FAILURE_ILLEGAL_STATE} or {@link #STATUS_FAILURE_SECURITY}.
      * <p>
      * More information about a status may be available through additional
      * extras; see the individual status documentation for details.
@@ -316,6 +325,34 @@
      */
     public static final int STATUS_FAILURE_INCOMPATIBLE = 7;
 
+    /**
+     * The transfer failed because a target package can't be found. For example
+     * transferring a session to a non-existing package.
+     * <p>
+     * The result may also contain {@link #EXTRA_OTHER_PACKAGE_NAME} with the
+     * missing package.
+     *
+     * @see #EXTRA_STATUS_MESSAGE
+     * @see #EXTRA_OTHER_PACKAGE_NAME
+     */
+    public static final int STATUS_FAILURE_NAME_NOT_FOUND = 8;
+
+    /**
+     * The transfer failed because a session is in invalid state. For example
+     * transferring an already committed session.
+     *
+     * @see #EXTRA_STATUS_MESSAGE
+     */
+    public static final int STATUS_FAILURE_ILLEGAL_STATE = 9;
+
+    /**
+     * The transfer failed for security reasons. For example transferring
+     * to a package which does not have INSTALL_PACKAGES permission.
+     *
+     * @see #EXTRA_STATUS_MESSAGE
+     */
+    public static final int STATUS_FAILURE_SECURITY = 10;
+
     private final IPackageInstaller mInstaller;
     private final int mUserId;
     private final String mInstallerPackageName;
@@ -1052,7 +1089,8 @@
         }
 
         /**
-         * Attempt to commit a session that has been {@link #transfer(String) transferred}.
+         * Attempt to commit a session that has been {@link #transfer(String, IntentSender)
+         * transferred}.
          *
          * <p>If the device reboots before the session has been finalized, you may commit the
          * session again.
@@ -1093,6 +1131,43 @@
          *
          * @param packageName The package of the new owner. Needs to hold the INSTALL_PACKAGES
          *                    permission.
+         * @param statusReceiver Called when the state of the session changes. Intents sent to
+         *                       this receiver contain {@link #EXTRA_STATUS}. Possible statuses:
+         *                       {@link #STATUS_FAILURE_NAME_NOT_FOUND},
+         *                       {@link #STATUS_FAILURE_ILLEGAL_STATE},
+         *                       {@link #STATUS_FAILURE_SECURITY},
+         *                       {@link #STATUS_FAILURE}.
+         *                       Refer to the individual transfer status codes on how to handle
+         *                       them.
+         *
+         * @throws PackageManager.NameNotFoundException if the new owner could not be found.
+         * @throws SecurityException if called after the session has been committed or abandoned.
+         * @throws SecurityException if the session does not update the original installer
+         * @throws SecurityException if streams opened through
+         *                           {@link #openWrite(String, long, long) are still open.
+         */
+        public void transfer(@NonNull String packageName, @NonNull IntentSender statusReceiver)
+                throws PackageManager.NameNotFoundException {
+            Preconditions.checkNotNull(statusReceiver);
+            Preconditions.checkNotNull(packageName);
+
+            try {
+                mSession.transfer(packageName, statusReceiver);
+            } catch (ParcelableException e) {
+                e.maybeRethrow(PackageManager.NameNotFoundException.class);
+                throw new RuntimeException(e);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        /**
+         * Transfer the session to a new owner.
+         * This is a convenience blocking wrapper around {@link #transfer(String, IntentSender)}.
+         * Converts all statuses into exceptions.
+         *
+         * @param packageName The package of the new owner. Needs to hold the INSTALL_PACKAGES
+         *                    permission.
          *
          * @throws PackageManager.NameNotFoundException if the new owner could not be found.
          * @throws SecurityException if called after the session has been committed or abandoned.
@@ -1104,11 +1179,62 @@
                 throws PackageManager.NameNotFoundException {
             Preconditions.checkNotNull(packageName);
 
+            CompletableFuture<Intent> intentFuture = new CompletableFuture<Intent>();
             try {
-                mSession.transfer(packageName);
+                IIntentSender localSender = new IIntentSender.Stub() {
+                    @Override
+                    public void send(int code, Intent intent, String resolvedType,
+                            IBinder whitelistToken,
+                            IIntentReceiver finishedReceiver, String requiredPermission,
+                            Bundle options) {
+                        intentFuture.complete(intent);
+                    }
+                };
+                transfer(packageName, new IntentSender(localSender));
             } catch (ParcelableException e) {
                 e.maybeRethrow(PackageManager.NameNotFoundException.class);
                 throw new RuntimeException(e);
+            }
+
+            try {
+                Intent intent = intentFuture.get();
+                final int status = intent.getIntExtra(EXTRA_STATUS, Integer.MIN_VALUE);
+                final String statusMessage = intent.getStringExtra(EXTRA_STATUS_MESSAGE);
+                switch (status) {
+                    case STATUS_SUCCESS:
+                        break;
+                    case STATUS_FAILURE_NAME_NOT_FOUND:
+                        throw new PackageManager.NameNotFoundException(statusMessage);
+                    case STATUS_FAILURE_ILLEGAL_STATE:
+                        throw new IllegalStateException(statusMessage);
+                    case STATUS_FAILURE_SECURITY:
+                        throw new SecurityException(statusMessage);
+                    default:
+                        throw new RuntimeException(statusMessage);
+                }
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            } catch (ExecutionException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        /**
+         * Configure files for an installation session.
+         *
+         * Currently only for Incremental installation session. Once this method is called,
+         * the files and their paths, as specified in the parameters, will be created and properly
+         * configured in the Incremental File System.
+         *
+         * TODO(b/136132412): update this and InstallationFile class with latest API design.
+         *
+         * @throws IllegalStateException if {@link SessionParams#incrementalParams} is null.
+         *
+         * @hide
+         */
+        public void addFile(@NonNull String name, long size, @NonNull byte[] metadata) {
+            try {
+                mSession.addFile(name, size, metadata);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -1301,6 +1427,8 @@
         public boolean isStaged;
         /** {@hide} */
         public long requiredInstalledVersionCode = PackageManager.VERSION_CODE_HIGHEST;
+        /** {@hide} */
+        public IncrementalDataLoaderParams incrementalParams;
 
         /**
          * Construct parameters for a new package install session.
@@ -1334,6 +1462,12 @@
             isMultiPackage = source.readBoolean();
             isStaged = source.readBoolean();
             requiredInstalledVersionCode = source.readLong();
+            IncrementalDataLoaderParamsParcel dataLoaderParamsParcel = source.readParcelable(
+                    IncrementalDataLoaderParamsParcel.class.getClassLoader());
+            if (dataLoaderParamsParcel != null) {
+                incrementalParams = new IncrementalDataLoaderParams(
+                        dataLoaderParamsParcel);
+            }
         }
 
         /** {@hide} */
@@ -1357,6 +1491,7 @@
             ret.isMultiPackage = isMultiPackage;
             ret.isStaged = isStaged;
             ret.requiredInstalledVersionCode = requiredInstalledVersionCode;
+            ret.incrementalParams = incrementalParams;
             return ret;
         }
 
@@ -1685,6 +1820,16 @@
             return (installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0;
         }
 
+        /**
+         * Set Incremental data loader params.
+         *
+         * {@hide}
+         */
+        @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
+        public void setIncrementalParams(@NonNull IncrementalDataLoaderParams incrementalParams) {
+            this.incrementalParams = incrementalParams;
+        }
+
         /** {@hide} */
         public void dump(IndentingPrintWriter pw) {
             pw.printPair("mode", mode);
@@ -1734,6 +1879,11 @@
             dest.writeBoolean(isMultiPackage);
             dest.writeBoolean(isStaged);
             dest.writeLong(requiredInstalledVersionCode);
+            if (incrementalParams != null) {
+                dest.writeParcelable(incrementalParams.getData(), flags);
+            } else {
+                dest.writeParcelable(null, flags);
+            }
         }
 
         public static final Parcelable.Creator<SessionParams>
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index d0ab8f7..50a2f00 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -436,7 +436,7 @@
     /**
      * @hide
      */
-    public void writeToProto(ProtoOutputStream proto, long fieldId, int dumpFlags) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId, int dumpFlags) {
         long token = proto.start(fieldId);
         if (name != null) {
             proto.write(PackageItemInfoProto.NAME, name);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index bbfdf91..6e890ba 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -5989,11 +5989,30 @@
      *
      * @param packageName The name of the package to query
      * @throws IllegalArgumentException if the given package name is not installed
+     *
+     * @deprecated use {@link #getInstallSourceInfo(String)} instead
      */
+    @Deprecated
     @Nullable
     public abstract String getInstallerPackageName(@NonNull String packageName);
 
     /**
+     * Retrieves information about how a package was installed or updated.
+     * <p>
+     * If the calling application does not hold the INSTALL_PACKAGES permission then
+     * the result will always return {@code null} from
+     * {@link InstallSourceInfo#getOriginatingPackageName()}.
+     *
+     * @param packageName The name of the package to query
+     * @throws NameNotFoundException if the given package name is not installed
+     */
+    @NonNull
+    public InstallSourceInfo getInstallSourceInfo(@NonNull String packageName)
+            throws NameNotFoundException {
+        throw new UnsupportedOperationException("getInstallSourceInfo not implemented");
+    }
+
+    /**
      * Attempts to clear the user data directory of an application.
      * Since this may take a little while, the result will
      * be posted back to the given observer.  A deletion will fail if the
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index cf21e96..65ee1e5 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -57,6 +57,12 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageParserCacheHelper.ReadHelper;
 import android.content.pm.PackageParserCacheHelper.WriteHelper;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ApkParseUtils;
+import android.content.pm.parsing.ComponentParseUtils;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.PackageInfoUtils;
+import android.content.pm.parsing.ParsedPackage;
 import android.content.pm.permission.SplitPermissionInfoParcelable;
 import android.content.pm.split.DefaultSplitAssetLoader;
 import android.content.pm.split.SplitAssetDependencyLoader;
@@ -67,7 +73,6 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
-import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.FileUtils;
@@ -156,21 +161,22 @@
  * @hide
  */
 public class PackageParser {
-    private static final boolean DEBUG_JAR = false;
-    private static final boolean DEBUG_PARSER = false;
-    private static final boolean DEBUG_BACKUP = false;
-    private static final boolean LOG_PARSE_TIMINGS = Build.IS_DEBUGGABLE;
-    private static final int LOG_PARSE_TIMINGS_THRESHOLD_MS = 100;
+
+    public static final boolean DEBUG_JAR = false;
+    public static final boolean DEBUG_PARSER = false;
+    public static final boolean DEBUG_BACKUP = false;
+    public static final boolean LOG_PARSE_TIMINGS = Build.IS_DEBUGGABLE;
+    public static final int LOG_PARSE_TIMINGS_THRESHOLD_MS = 100;
 
     private static final String PROPERTY_CHILD_PACKAGES_ENABLED =
             "persist.sys.child_packages_enabled";
 
-    private static final boolean MULTI_PACKAGE_APK_ENABLED = Build.IS_DEBUGGABLE &&
+    public static final boolean MULTI_PACKAGE_APK_ENABLED = Build.IS_DEBUGGABLE &&
             SystemProperties.getBoolean(PROPERTY_CHILD_PACKAGES_ENABLED, false);
 
-    private static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f;
-    private static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO = 1.333f;
-    private static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH = 1f;
+    public static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f;
+    public static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO = 1.333f;
+    public static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH = 1f;
 
     private static final int DEFAULT_MIN_SDK_VERSION = 1;
     private static final int DEFAULT_TARGET_SDK_VERSION = 0;
@@ -182,37 +188,38 @@
     public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
 
     /** Path prefix for apps on expanded storage */
-    private static final String MNT_EXPAND = "/mnt/expand/";
+    public static final String MNT_EXPAND = "/mnt/expand/";
 
-    private static final String TAG_MANIFEST = "manifest";
-    private static final String TAG_APPLICATION = "application";
-    private static final String TAG_PACKAGE_VERIFIER = "package-verifier";
-    private static final String TAG_OVERLAY = "overlay";
-    private static final String TAG_KEY_SETS = "key-sets";
-    private static final String TAG_PERMISSION_GROUP = "permission-group";
-    private static final String TAG_PERMISSION = "permission";
-    private static final String TAG_PERMISSION_TREE = "permission-tree";
-    private static final String TAG_USES_PERMISSION = "uses-permission";
-    private static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m";
-    private static final String TAG_USES_PERMISSION_SDK_23 = "uses-permission-sdk-23";
-    private static final String TAG_USES_CONFIGURATION = "uses-configuration";
-    private static final String TAG_USES_FEATURE = "uses-feature";
-    private static final String TAG_FEATURE_GROUP = "feature-group";
-    private static final String TAG_USES_SDK = "uses-sdk";
-    private static final String TAG_SUPPORT_SCREENS = "supports-screens";
-    private static final String TAG_PROTECTED_BROADCAST = "protected-broadcast";
-    private static final String TAG_INSTRUMENTATION = "instrumentation";
-    private static final String TAG_ORIGINAL_PACKAGE = "original-package";
-    private static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions";
-    private static final String TAG_USES_GL_TEXTURE = "uses-gl-texture";
-    private static final String TAG_COMPATIBLE_SCREENS = "compatible-screens";
-    private static final String TAG_SUPPORTS_INPUT = "supports-input";
-    private static final String TAG_EAT_COMMENT = "eat-comment";
-    private static final String TAG_PACKAGE = "package";
-    private static final String TAG_RESTRICT_UPDATE = "restrict-update";
-    private static final String TAG_USES_SPLIT = "uses-split";
+    public static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions";
+    public static final String TAG_APPLICATION = "application";
+    public static final String TAG_COMPATIBLE_SCREENS = "compatible-screens";
+    public static final String TAG_EAT_COMMENT = "eat-comment";
+    public static final String TAG_FEATURE_GROUP = "feature-group";
+    public static final String TAG_INSTRUMENTATION = "instrumentation";
+    public static final String TAG_KEY_SETS = "key-sets";
+    public static final String TAG_MANIFEST = "manifest";
+    public static final String TAG_ORIGINAL_PACKAGE = "original-package";
+    public static final String TAG_OVERLAY = "overlay";
+    public static final String TAG_PACKAGE = "package";
+    public static final String TAG_PACKAGE_VERIFIER = "package-verifier";
+    public static final String TAG_PERMISSION = "permission";
+    public static final String TAG_PERMISSION_GROUP = "permission-group";
+    public static final String TAG_PERMISSION_TREE = "permission-tree";
+    public static final String TAG_PROTECTED_BROADCAST = "protected-broadcast";
+    public static final String TAG_QUERIES = "queries";
+    public static final String TAG_RESTRICT_UPDATE = "restrict-update";
+    public static final String TAG_SUPPORT_SCREENS = "supports-screens";
+    public static final String TAG_SUPPORTS_INPUT = "supports-input";
+    public static final String TAG_USES_CONFIGURATION = "uses-configuration";
+    public static final String TAG_USES_FEATURE = "uses-feature";
+    public static final String TAG_USES_GL_TEXTURE = "uses-gl-texture";
+    public static final String TAG_USES_PERMISSION = "uses-permission";
+    public static final String TAG_USES_PERMISSION_SDK_23 = "uses-permission-sdk-23";
+    public static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m";
+    public static final String TAG_USES_SDK = "uses-sdk";
+    public static final String TAG_USES_SPLIT = "uses-split";
 
-    private static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect";
+    public static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect";
 
     /**
      * Bit mask of all the valid bits that can be set in recreateOnConfigChanges.
@@ -222,25 +229,25 @@
             ActivityInfo.CONFIG_MCC | ActivityInfo.CONFIG_MNC;
 
     // These are the tags supported by child packages
-    private static final Set<String> CHILD_PACKAGE_TAGS = new ArraySet<>();
+    public static final Set<String> CHILD_PACKAGE_TAGS = new ArraySet<>();
     static {
         CHILD_PACKAGE_TAGS.add(TAG_APPLICATION);
-        CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION);
-        CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_M);
-        CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_23);
+        CHILD_PACKAGE_TAGS.add(TAG_COMPATIBLE_SCREENS);
+        CHILD_PACKAGE_TAGS.add(TAG_EAT_COMMENT);
+        CHILD_PACKAGE_TAGS.add(TAG_FEATURE_GROUP);
+        CHILD_PACKAGE_TAGS.add(TAG_INSTRUMENTATION);
+        CHILD_PACKAGE_TAGS.add(TAG_SUPPORT_SCREENS);
+        CHILD_PACKAGE_TAGS.add(TAG_SUPPORTS_INPUT);
         CHILD_PACKAGE_TAGS.add(TAG_USES_CONFIGURATION);
         CHILD_PACKAGE_TAGS.add(TAG_USES_FEATURE);
-        CHILD_PACKAGE_TAGS.add(TAG_FEATURE_GROUP);
-        CHILD_PACKAGE_TAGS.add(TAG_USES_SDK);
-        CHILD_PACKAGE_TAGS.add(TAG_SUPPORT_SCREENS);
-        CHILD_PACKAGE_TAGS.add(TAG_INSTRUMENTATION);
         CHILD_PACKAGE_TAGS.add(TAG_USES_GL_TEXTURE);
-        CHILD_PACKAGE_TAGS.add(TAG_COMPATIBLE_SCREENS);
-        CHILD_PACKAGE_TAGS.add(TAG_SUPPORTS_INPUT);
-        CHILD_PACKAGE_TAGS.add(TAG_EAT_COMMENT);
+        CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION);
+        CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_23);
+        CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_M);
+        CHILD_PACKAGE_TAGS.add(TAG_USES_SDK);
     }
 
-    private static final boolean LOG_UNSAFE_BROADCASTS = false;
+    public static final boolean LOG_UNSAFE_BROADCASTS = false;
 
     /**
      * Total number of packages that were read from the cache.  We use it only for logging.
@@ -248,7 +255,7 @@
     public static final AtomicInteger sCachedPackageReadCount = new AtomicInteger();
 
     // Set of broadcast actions that are safe for manifest receivers
-    private static final Set<String> SAFE_BROADCASTS = new ArraySet<>();
+    public static final Set<String> SAFE_BROADCASTS = new ArraySet<>();
     static {
         SAFE_BROADCASTS.add(Intent.ACTION_BOOT_COMPLETED);
     }
@@ -295,26 +302,29 @@
      * @deprecated callers should move to explicitly passing around source path.
      */
     @Deprecated
-    private String mArchiveSourcePath;
+    public String mArchiveSourcePath;
 
-    private String[] mSeparateProcesses;
+    public String[] mSeparateProcesses;
     private boolean mOnlyCoreApps;
     private DisplayMetrics mMetrics;
     @UnsupportedAppUsage
-    private Callback mCallback;
+    public Callback mCallback;
     private File mCacheDir;
 
-    private static final int SDK_VERSION = Build.VERSION.SDK_INT;
-    private static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
+    public static final int SDK_VERSION = Build.VERSION.SDK_INT;
+    public static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
 
-    private int mParseError = PackageManager.INSTALL_SUCCEEDED;
+    public int mParseError = PackageManager.INSTALL_SUCCEEDED;
 
-    private static boolean sCompatibilityModeEnabled = true;
-    private static boolean sUseRoundIcon = false;
+    public ThreadLocal<ApkParseUtils.ParseResult> mSharedResult
+            = ThreadLocal.withInitial(ApkParseUtils.ParseResult::new);
 
-    private static final int PARSE_DEFAULT_INSTALL_LOCATION =
+    public static boolean sCompatibilityModeEnabled = true;
+    public static boolean sUseRoundIcon = false;
+
+    public static final int PARSE_DEFAULT_INSTALL_LOCATION =
             PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
-    private static final int PARSE_DEFAULT_TARGET_SANDBOX = 1;
+    public static final int PARSE_DEFAULT_TARGET_SANDBOX = 1;
 
     static class ParsePackageItemArgs {
         final Package owner;
@@ -536,7 +546,7 @@
      *  the DTD.  Otherwise, we try to get as much from the package as we
      *  can without failing.  This should normally be set to false, to
      *  support extensions to the DTD in future versions. */
-    private static final boolean RIGID_PARSER = false;
+    public static final boolean RIGID_PARSER = false;
 
     private static final String TAG = "PackageParser";
 
@@ -887,7 +897,7 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface ParseFlags {}
 
-    private static final Comparator<String> sSplitNameComparator = new SplitNameComparator();
+    public static final Comparator<String> sSplitNameComparator = new SplitNameComparator();
 
     /**
      * Used to sort a set of APKs based on their split names, always placing the
@@ -1033,7 +1043,7 @@
      * and unique split names.
      * <p>
      * Note that this <em>does not</em> perform signature verification; that
-     * must be done separately in {@link #collectCertificates(Package, int)}.
+     * must be done separately in {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}.
      *
      * If {@code useCaches} is true, the package parser might return a cached
      * result from a previous parse of the same {@code packageFile} with the same
@@ -1041,21 +1051,54 @@
      * has changed since the last parse, it's up to callers to do so.
      *
      * @see #parsePackageLite(File, int)
+     * @deprecated use {@link #parseParsedPackage(File, int, boolean)}
      */
     @UnsupportedAppUsage
+    @Deprecated
     public Package parsePackage(File packageFile, int flags, boolean useCaches)
             throws PackageParserException {
-        Package parsed = useCaches ? getCachedResult(packageFile, flags) : null;
+        if (packageFile.isDirectory()) {
+            return parseClusterPackage(packageFile, flags);
+        } else {
+            return parseMonolithicPackage(packageFile, flags);
+        }
+    }
+
+    /**
+     * Equivalent to {@link #parsePackage(File, int, boolean)} with {@code useCaches == false}.
+     * @deprecated use {@link #parseParsedPackage(File, int, boolean)}
+     */
+    @UnsupportedAppUsage
+    @Deprecated
+    public Package parsePackage(File packageFile, int flags) throws PackageParserException {
+        return parsePackage(packageFile, flags, false /* useCaches */);
+    }
+
+    /**
+     * Updated method which returns {@link ParsedPackage}, the current representation of a
+     * package parsed from disk.
+     *
+     * @see #parsePackage(File, int, boolean)
+     */
+    public ParsedPackage parseParsedPackage(File packageFile, int flags, boolean useCaches)
+            throws PackageParserException {
+        ParsedPackage parsed = useCaches ? getCachedResult(packageFile, flags) : null;
         if (parsed != null) {
             return parsed;
         }
 
         long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
-        if (packageFile.isDirectory()) {
-            parsed = parseClusterPackage(packageFile, flags);
-        } else {
-            parsed = parseMonolithicPackage(packageFile, flags);
-        }
+        ApkParseUtils.ParseInput parseInput = mSharedResult.get().reset();
+        parsed = ApkParseUtils.parsePackage(
+                parseInput,
+                mSeparateProcesses,
+                mCallback,
+                mMetrics,
+                mOnlyCoreApps,
+                packageFile,
+                flags
+        )
+                .hideAsParsed();
 
         long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
         cacheResult(packageFile, flags, parsed);
@@ -1067,19 +1110,12 @@
                         + "ms, update_cache=" + cacheTime + " ms");
             }
         }
+
         return parsed;
     }
 
     /**
-     * Equivalent to {@link #parsePackage(File, int, boolean)} with {@code useCaches == false}.
-     */
-    @UnsupportedAppUsage
-    public Package parsePackage(File packageFile, int flags) throws PackageParserException {
-        return parsePackage(packageFile, flags, false /* useCaches */);
-    }
-
-    /**
-     * Returns the cache key for a specificied {@code packageFile} and {@code flags}.
+     * Returns the cache key for a specified {@code packageFile} and {@code flags}.
      */
     private String getCacheKey(File packageFile, int flags) {
         StringBuilder sb = new StringBuilder(packageFile.getName());
@@ -1090,13 +1126,13 @@
     }
 
     @VisibleForTesting
-    protected Package fromCacheEntry(byte[] bytes) {
+    protected ParsedPackage fromCacheEntry(byte[] bytes) {
         return fromCacheEntryStatic(bytes);
     }
 
     /** static version of {@link #fromCacheEntry} for unit tests. */
     @VisibleForTesting
-    public static Package fromCacheEntryStatic(byte[] bytes) {
+    public static ParsedPackage fromCacheEntryStatic(byte[] bytes) {
         final Parcel p = Parcel.obtain();
         p.unmarshall(bytes, 0, bytes.length);
         p.setDataPosition(0);
@@ -1104,7 +1140,8 @@
         final ReadHelper helper = new ReadHelper(p);
         helper.startAndInstall();
 
-        PackageParser.Package pkg = new PackageParser.Package(p);
+        // TODO(b/135203078): Hide PackageImpl constructor?
+        ParsedPackage pkg = new PackageImpl(p);
 
         p.recycle();
 
@@ -1114,14 +1151,14 @@
     }
 
     @VisibleForTesting
-    protected byte[] toCacheEntry(Package pkg) {
+    protected byte[] toCacheEntry(ParsedPackage pkg) {
         return toCacheEntryStatic(pkg);
 
     }
 
     /** static version of {@link #toCacheEntry} for unit tests. */
     @VisibleForTesting
-    public static byte[] toCacheEntryStatic(Package pkg) {
+    public static byte[] toCacheEntryStatic(ParsedPackage pkg) {
         final Parcel p = Parcel.obtain();
         final WriteHelper helper = new WriteHelper(p);
 
@@ -1170,7 +1207,7 @@
      * Returns the cached parse result for {@code packageFile} for parse flags {@code flags},
      * or {@code null} if no cached result exists.
      */
-    private Package getCachedResult(File packageFile, int flags) {
+    public ParsedPackage getCachedResult(File packageFile, int flags) {
         if (mCacheDir == null) {
             return null;
         }
@@ -1199,7 +1236,7 @@
     /**
      * Caches the parse result for {@code packageFile} with flags {@code flags}.
      */
-    private void cacheResult(File packageFile, int flags, Package parsed) {
+    public void cacheResult(File packageFile, int flags, ParsedPackage parsed) {
         if (mCacheDir == null) {
             return;
         }
@@ -1238,7 +1275,8 @@
      * split names.
      * <p>
      * Note that this <em>does not</em> perform signature verification; that
-     * must be done separately in {@link #collectCertificates(Package, int)}.
+     * must be done separately in
+     * {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}.
      */
     private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
         final PackageLite lite = parseClusterPackageLite(packageDir, 0);
@@ -1302,10 +1340,11 @@
      * Parse the given APK file, treating it as as a single monolithic package.
      * <p>
      * Note that this <em>does not</em> perform signature verification; that
-     * must be done separately in {@link #collectCertificates(Package, int)}.
+     * must be done separately in
+     * {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}.
      *
      * @deprecated external callers should move to
-     *             {@link #parsePackage(File, int)}. Eventually this method will
+     *             {@link #parseParsedPackage(File, int, boolean)}. Eventually this method will
      *             be marked private.
      */
     @Deprecated
@@ -1505,8 +1544,11 @@
      * Collect certificates from all the APKs described in the given package,
      * populating {@link Package#mSigningDetails}. Also asserts that all APK
      * contents are signed correctly and consistently.
+     *
+     * @deprecated use {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}
      */
     @UnsupportedAppUsage
+    @Deprecated
     public static void collectCertificates(Package pkg, boolean skipVerify)
             throws PackageParserException {
         collectCertificatesInternal(pkg, skipVerify);
@@ -1685,7 +1727,7 @@
                 ? null : "must have at least one '.' separator";
     }
 
-    private static Pair<String, String> parsePackageSplitNames(XmlPullParser parser,
+    public static Pair<String, String> parsePackageSplitNames(XmlPullParser parser,
             AttributeSet attrs) throws IOException, XmlPullParserException,
             PackageParserException {
 
@@ -2454,8 +2496,6 @@
                 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                 return null;
 
-            } else if (tagName.equals("queries")) {
-                parseQueries(pkg, res, parser, flags, outError);
             } else {
                 Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
                         + " at " + mArchiveSourcePath + " "
@@ -2925,7 +2965,7 @@
         return true;
     }
 
-    private static String buildClassName(String pkg, CharSequence clsSeq,
+    public static String buildClassName(String pkg, CharSequence clsSeq,
             String[] outError) {
         if (clsSeq == null || clsSeq.length() <= 0) {
             outError[0] = "Empty class name in package " + pkg;
@@ -2973,7 +3013,7 @@
         return proc;
     }
 
-    private static String buildProcessName(String pkg, String defProc,
+    public static String buildProcessName(String pkg, String defProc,
             CharSequence procSeq, int flags, String[] separateProcesses,
             String[] outError) {
         if ((flags&PARSE_IGNORE_PROCESSES) != 0 && !"system".equals(procSeq)) {
@@ -2993,7 +3033,7 @@
         return TextUtils.safeIntern(buildCompoundName(pkg, procSeq, "process", outError));
     }
 
-    private static String buildTaskAffinityName(String pkg, String defProc,
+    public static String buildTaskAffinityName(String pkg, String defProc,
             CharSequence procSeq, String[] outError) {
         if (procSeq == null) {
             return defProc;
@@ -3555,9 +3595,6 @@
             owner.mRequiredAccountType = requiredAccountType;
         }
 
-        owner.mForceQueryable =
-                sa.getBoolean(R.styleable.AndroidManifestApplication_forceQueryable, false);
-
         if (sa.getBoolean(
                 com.android.internal.R.styleable.AndroidManifestApplication_debuggable,
                 false)) {
@@ -4019,89 +4056,6 @@
         return true;
     }
 
-    private boolean parseQueries(Package owner, Resources res, XmlResourceParser parser, int flags,
-            String[] outError)
-            throws IOException, XmlPullParserException {
-
-        final int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG
-                || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-            if (parser.getName().equals("intent")) {
-                QueriesIntentInfo intentInfo = new QueriesIntentInfo();
-                if (!parseIntent(res, parser, true /*allowGlobs*/, true /*allowAutoVerify*/,
-                        intentInfo, outError)) {
-                    return false;
-                }
-
-                Uri data = null;
-                String dataType = null;
-                String host = "";
-                final int numActions = intentInfo.countActions();
-                final int numSchemes = intentInfo.countDataSchemes();
-                final int numTypes = intentInfo.countDataTypes();
-                final int numHosts = intentInfo.getHosts().length;
-                if ((numSchemes == 0 && numTypes == 0 && numActions == 0)) {
-                    outError[0] = "intent tags must contain either an action or data.";
-                    return false;
-                }
-                if (numActions > 1) {
-                    outError[0] = "intent tag may have at most one action.";
-                    return false;
-                }
-                if (numTypes > 1) {
-                    outError[0] = "intent tag may have at most one data type.";
-                    return false;
-                }
-                if (numSchemes > 1) {
-                    outError[0] = "intent tag may have at most one data scheme.";
-                    return false;
-                }
-                if (numHosts > 1) {
-                    outError[0] = "intent tag may have at most one data host.";
-                    return false;
-                }
-                Intent intent = new Intent();
-                for (int i = 0, max = intentInfo.countCategories(); i < max; i++) {
-                    intent.addCategory(intentInfo.getCategory(i));
-                }
-                if (numHosts == 1) {
-                    host = intentInfo.getHosts()[0];
-                }
-                if (numSchemes == 1) {
-                    data = new Uri.Builder()
-                            .scheme(intentInfo.getDataScheme(0))
-                            .authority(host)
-                            .build();
-                }
-                if (numTypes == 1) {
-                    dataType = intentInfo.getDataType(0);
-                }
-                intent.setDataAndType(data, dataType);
-                if (numActions == 1) {
-                    intent.setAction(intentInfo.getAction(0));
-                }
-                owner.mQueriesIntents = ArrayUtils.add(owner.mQueriesIntents, intent);
-            } else if (parser.getName().equals("package")) {
-                final TypedArray sa = res.obtainAttributes(parser,
-                        com.android.internal.R.styleable.AndroidManifestQueriesPackage);
-                final String packageName =
-                        sa.getString(R.styleable.AndroidManifestQueriesPackage_name);
-                if (TextUtils.isEmpty(packageName)) {
-                    outError[0] = "Package name is missing from package tag.";
-                    return false;
-                }
-                owner.mQueriesPackages =
-                        ArrayUtils.add(owner.mQueriesPackages, packageName.intern());
-            }
-        }
-        return true;
-    }
-
     /**
      * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI
      */
@@ -5813,7 +5767,7 @@
         return null;
     }
 
-    private static final String ANDROID_RESOURCES
+    public static final String ANDROID_RESOURCES
             = "http://schemas.android.com/apk/res/android";
 
     private boolean parseIntent(Resources res, XmlResourceParser parser, boolean allowGlobs,
@@ -6508,7 +6462,10 @@
     /**
      * Representation of a full package parsed from APK files on disk. A package
      * consists of a single base APK, and zero or more split APKs.
+     *
+     * @deprecated use an {@link AndroidPackage}
      */
+    @Deprecated
     public final static class Package implements Parcelable {
 
         @UnsupportedAppUsage
@@ -6616,9 +6573,6 @@
         // The major version code declared for this package.
         public int mVersionCodeMajor;
 
-        // Whether the package declares that it should be queryable by all normal apps on device.
-        public boolean mForceQueryable;
-
         // Return long containing mVersionCode and mVersionCodeMajor.
         public long getLongVersionCode() {
             return PackageInfo.composeLongVersionCode(mVersionCodeMajor, mVersionCode);
@@ -6724,9 +6678,6 @@
         /** Whether or not the package is a stub and must be replaced by the full version. */
         public boolean isStub;
 
-        public ArrayList<String> mQueriesPackages;
-        public ArrayList<Intent> mQueriesIntents;
-
         @UnsupportedAppUsage
         public Package(String packageName) {
             this.packageName = packageName;
@@ -7230,9 +7181,6 @@
             use32bitAbi = (dest.readInt() == 1);
             restrictUpdateHash = dest.createByteArray();
             visibleToInstantApps = dest.readInt() == 1;
-            mForceQueryable = dest.readBoolean();
-            mQueriesIntents = dest.createTypedArrayList(Intent.CREATOR);
-            mQueriesPackages = dest.createStringArrayList();
         }
 
         private static void internStringArrayList(List<String> list) {
@@ -7248,7 +7196,7 @@
          * Sets the package owner and the the {@code applicationInfo} for every component
          * owner by this package.
          */
-        private void fixupOwner(List<? extends Component<?>> list) {
+        public void fixupOwner(List<? extends Component<?>> list) {
             if (list != null) {
                 for (Component<?> c : list) {
                     c.owner = this;
@@ -7358,12 +7306,8 @@
             dest.writeInt(use32bitAbi ? 1 : 0);
             dest.writeByteArray(restrictUpdateHash);
             dest.writeInt(visibleToInstantApps ? 1 : 0);
-            dest.writeBoolean(mForceQueryable);
-            dest.writeTypedList(mQueriesIntents);
-            dest.writeList(mQueriesPackages);
         }
 
-
         /**
          * Writes the keyset mapping to the provided package. {@code null} mappings are permitted.
          */
@@ -7435,6 +7379,10 @@
         };
     }
 
+    /**
+     * @deprecated use a {@link ComponentParseUtils.ParsedComponent}
+     */
+    @Deprecated
     public static abstract class Component<II extends IntentInfo> {
         @UnsupportedAppUsage
         public final ArrayList<II> intents;
@@ -7615,6 +7563,10 @@
         }
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedPermission}
+     */
+    @Deprecated
     public final static class Permission extends Component<IntentInfo> implements Parcelable {
         @UnsupportedAppUsage
         public final PermissionInfo info;
@@ -7689,6 +7641,10 @@
         };
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedPermissionGroup}
+     */
+    @Deprecated
     public final static class PermissionGroup extends Component<IntentInfo> implements Parcelable {
         @UnsupportedAppUsage
         public final PermissionGroupInfo info;
@@ -7788,7 +7744,12 @@
         return false;
     }
 
+    /**
+     * @deprecated use {@link PackageInfoUtils#generateApplicationInfo(
+     *      AndroidPackage, int, PackageUserState, int)}
+     */
     @UnsupportedAppUsage
+    @Deprecated
     public static ApplicationInfo generateApplicationInfo(Package p, int flags,
             PackageUserState state) {
         return generateApplicationInfo(p, flags, state, UserHandle.getCallingUserId());
@@ -7845,7 +7806,12 @@
         ai.icon = (sUseRoundIcon && ai.roundIconRes != 0) ? ai.roundIconRes : ai.iconRes;
     }
 
+    /**
+     * @deprecated use {@link PackageInfoUtils#generateApplicationInfo(
+     *      AndroidPackage, int, PackageUserState, int)}
+     */
     @UnsupportedAppUsage
+    @Deprecated
     public static ApplicationInfo generateApplicationInfo(Package p, int flags,
             PackageUserState state, int userId) {
         if (p == null) return null;
@@ -7885,6 +7851,11 @@
         return ai;
     }
 
+    /**
+     * @deprecated use {@link PackageInfoUtils#generateApplicationInfo(
+     *      AndroidPackage, int, PackageUserState, int)}
+     */
+    @Deprecated
     public static ApplicationInfo generateApplicationInfo(ApplicationInfo ai, int flags,
             PackageUserState state, int userId) {
         if (ai == null) return null;
@@ -7904,7 +7875,12 @@
         return ai;
     }
 
+    /**
+     * @deprecated use {@link PackageInfoUtils#generatePermissionInfo(
+     *      ComponentParseUtils.ParsedPermission, int)}
+     */
     @UnsupportedAppUsage
+    @Deprecated
     public static final PermissionInfo generatePermissionInfo(
             Permission p, int flags) {
         if (p == null) return null;
@@ -7916,7 +7892,12 @@
         return pi;
     }
 
+    /**
+     * @deprecated use {@link PackageInfoUtils#generatePermissionGroupInfo(
+     *      ComponentParseUtils.ParsedPermissionGroup, int)}
+     */
     @UnsupportedAppUsage
+    @Deprecated
     public static final PermissionGroupInfo generatePermissionGroupInfo(
             PermissionGroup pg, int flags) {
         if (pg == null) return null;
@@ -7928,6 +7909,10 @@
         return pgi;
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedActivity}
+     */
+    @Deprecated
     public final static class Activity extends Component<ActivityIntentInfo> implements Parcelable {
         @UnsupportedAppUsage
         public final ActivityInfo info;
@@ -8043,7 +8028,12 @@
         };
     }
 
+    /**
+     * @deprecated use {@link PackageInfoUtils#generateActivityInfo(
+     *      AndroidPackage, ComponentParseUtils.ParsedActivity, int, PackageUserState, int)}
+     */
     @UnsupportedAppUsage
+    @Deprecated
     public static final ActivityInfo generateActivityInfo(Activity a, int flags,
             PackageUserState state, int userId) {
         if (a == null) return null;
@@ -8061,6 +8051,11 @@
         return ai;
     }
 
+    /**
+     * @deprecated use {@link PackageInfoUtils#generateActivityInfo(
+     *      AndroidPackage, ComponentParseUtils.ParsedActivity, int, PackageUserState, int)}
+     */
+    @Deprecated
     public static final ActivityInfo generateActivityInfo(ActivityInfo ai, int flags,
             PackageUserState state, int userId) {
         if (ai == null) return null;
@@ -8074,6 +8069,10 @@
         return ai;
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedService}
+     */
+    @Deprecated
     public final static class Service extends Component<ServiceIntentInfo> implements Parcelable {
         @UnsupportedAppUsage
         public final ServiceInfo info;
@@ -8135,7 +8134,12 @@
         };
     }
 
+    /**
+     * @deprecated use {@link PackageInfoUtils#generateServiceInfo(
+     * AndroidPackage, ComponentParseUtils.ParsedService, int, PackageUserState, int)}
+     */
     @UnsupportedAppUsage
+    @Deprecated
     public static final ServiceInfo generateServiceInfo(Service s, int flags,
             PackageUserState state, int userId) {
         if (s == null) return null;
@@ -8153,6 +8157,10 @@
         return si;
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedProvider}
+     */
+    @Deprecated
     public final static class Provider extends Component<ProviderIntentInfo> implements Parcelable {
         @UnsupportedAppUsage
         public final ProviderInfo info;
@@ -8233,7 +8241,12 @@
         };
     }
 
+    /**
+     * @deprecated use {@link PackageInfoUtils#generateProviderInfo(
+     *      AndroidPackage, ComponentParseUtils.ParsedProvider, int, PackageUserState, int)}
+     */
     @UnsupportedAppUsage
+    @Deprecated
     public static final ProviderInfo generateProviderInfo(Provider p, int flags,
             PackageUserState state, int userId) {
         if (p == null) return null;
@@ -8256,6 +8269,10 @@
         return pi;
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedInstrumentation}
+     */
+    @Deprecated
     public final static class Instrumentation extends Component<IntentInfo> implements
             Parcelable {
         @UnsupportedAppUsage
@@ -8316,7 +8333,12 @@
         };
     }
 
+    /**
+     * @deprecated use {@link PackageInfoUtils#generateInstrumentationInfo(
+     *      ComponentParseUtils.ParsedInstrumentation, int)}
+     */
     @UnsupportedAppUsage
+    @Deprecated
     public static final InstrumentationInfo generateInstrumentationInfo(
             Instrumentation i, int flags) {
         if (i == null) return null;
@@ -8328,6 +8350,10 @@
         return ii;
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedIntentInfo}
+     */
+    @Deprecated
     public static abstract class IntentInfo extends IntentFilter {
         @UnsupportedAppUsage
         public boolean hasDefault;
@@ -8371,8 +8397,10 @@
         }
     }
 
-    public static final class QueriesIntentInfo extends IntentInfo {}
-
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedActivityIntentInfo}
+     */
+    @Deprecated
     public final static class ActivityIntentInfo extends IntentInfo {
         @UnsupportedAppUsage
         public Activity activity;
@@ -8396,6 +8424,10 @@
         }
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedServiceIntentInfo}
+     */
+    @Deprecated
     public final static class ServiceIntentInfo extends IntentInfo {
         @UnsupportedAppUsage
         public Service service;
@@ -8419,6 +8451,10 @@
         }
     }
 
+    /**
+     * @deprecated use {@link ComponentParseUtils.ParsedProviderIntentInfo}
+     */
+    @Deprecated
     public static final class ProviderIntentInfo extends IntentInfo {
         @UnsupportedAppUsage
         public Provider provider;
diff --git a/core/java/android/content/pm/PackageSharedLibraryUpdater.java b/core/java/android/content/pm/PackageSharedLibraryUpdater.java
deleted file mode 100644
index 1565d9c..0000000
--- a/core/java/android/content/pm/PackageSharedLibraryUpdater.java
+++ /dev/null
@@ -1,101 +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 android.content.pm;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
-
-import java.util.ArrayList;
-
-/**
- * Base for classes that update a {@link PackageParser.Package}'s shared libraries.
- *
- * @hide
- */
-@VisibleForTesting
-public abstract class PackageSharedLibraryUpdater {
-
-    /**
-     * Update the package's shared libraries.
-     *
-     * @param pkg the package to update.
-     */
-    public abstract void updatePackage(PackageParser.Package pkg);
-
-    static void removeLibrary(PackageParser.Package pkg, String libraryName) {
-        pkg.usesLibraries = ArrayUtils.remove(pkg.usesLibraries, libraryName);
-        pkg.usesOptionalLibraries =
-                ArrayUtils.remove(pkg.usesOptionalLibraries, libraryName);
-    }
-
-    static @NonNull
-            <T> ArrayList<T> prefix(@Nullable ArrayList<T> cur, T val) {
-        if (cur == null) {
-            cur = new ArrayList<>();
-        }
-        cur.add(0, val);
-        return cur;
-    }
-
-    private static boolean isLibraryPresent(ArrayList<String> usesLibraries,
-            ArrayList<String> usesOptionalLibraries, String apacheHttpLegacy) {
-        return ArrayUtils.contains(usesLibraries, apacheHttpLegacy)
-                || ArrayUtils.contains(usesOptionalLibraries, apacheHttpLegacy);
-    }
-
-    /**
-     * Add an implicit dependency.
-     *
-     * <p>If the package has an existing dependency on {@code existingLibrary} then prefix it with
-     * the {@code implicitDependency} if it is not already in the list of libraries.
-     *
-     * @param pkg the {@link PackageParser.Package} to update.
-     * @param existingLibrary the existing library.
-     * @param implicitDependency the implicit dependency to add
-     */
-    void prefixImplicitDependency(PackageParser.Package pkg, String existingLibrary,
-            String implicitDependency) {
-        ArrayList<String> usesLibraries = pkg.usesLibraries;
-        ArrayList<String> usesOptionalLibraries = pkg.usesOptionalLibraries;
-
-        if (!isLibraryPresent(usesLibraries, usesOptionalLibraries, implicitDependency)) {
-            if (ArrayUtils.contains(usesLibraries, existingLibrary)) {
-                prefix(usesLibraries, implicitDependency);
-            } else if (ArrayUtils.contains(usesOptionalLibraries, existingLibrary)) {
-                prefix(usesOptionalLibraries, implicitDependency);
-            }
-
-            pkg.usesLibraries = usesLibraries;
-            pkg.usesOptionalLibraries = usesOptionalLibraries;
-        }
-    }
-
-    void prefixRequiredLibrary(PackageParser.Package pkg, String libraryName) {
-        ArrayList<String> usesLibraries = pkg.usesLibraries;
-        ArrayList<String> usesOptionalLibraries = pkg.usesOptionalLibraries;
-
-        boolean alreadyPresent = isLibraryPresent(
-                usesLibraries, usesOptionalLibraries, libraryName);
-        if (!alreadyPresent) {
-            usesLibraries = prefix(usesLibraries, libraryName);
-
-            pkg.usesLibraries = usesLibraries;
-        }
-    }
-}
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 5c74efb..55574c3 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -28,6 +28,7 @@
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
 
 import android.annotation.UnsupportedAppUsage;
+import android.content.pm.parsing.ComponentParseUtils;
 import android.os.BaseBundle;
 import android.os.Debug;
 import android.os.PersistableBundle;
@@ -127,6 +128,18 @@
                         && (!this.hidden || matchUninstalled));
     }
 
+    public boolean isMatch(ComponentInfo componentInfo, int flags) {
+        return isMatch(componentInfo.applicationInfo.isSystemApp(),
+                componentInfo.applicationInfo.enabled, componentInfo.enabled,
+                componentInfo.directBootAware, componentInfo.name, flags);
+    }
+
+    public boolean isMatch(boolean isSystem, boolean isPackageEnabled,
+            ComponentParseUtils.ParsedComponent component, int flags) {
+        return isMatch(isSystem, isPackageEnabled, component.isEnabled(),
+                component.isDirectBootAware(), component.getName(), flags);
+    }
+
     /**
      * Test if the given component is considered installed, enabled and a match
      * for the given flags.
@@ -135,28 +148,33 @@
      * Expects at least one of {@link PackageManager#MATCH_DIRECT_BOOT_AWARE} and
      * {@link PackageManager#MATCH_DIRECT_BOOT_UNAWARE} are specified in {@code flags}.
      * </p>
+     *
      */
-    public boolean isMatch(ComponentInfo componentInfo, int flags) {
-        final boolean isSystemApp = componentInfo.applicationInfo.isSystemApp();
+    public boolean isMatch(boolean isSystem, boolean isPackageEnabled, boolean isComponentEnabled,
+               boolean isComponentDirectBootAware, String componentName, int flags) {
         final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0;
-        if (!isAvailable(flags)
-                && !(isSystemApp && matchUninstalled)) return reportIfDebug(false, flags);
-        if (!isEnabled(componentInfo, flags)) return reportIfDebug(false, flags);
+        if (!isAvailable(flags) && !(isSystem && matchUninstalled)) {
+            return reportIfDebug(false, flags);
+        }
+
+        if (!isEnabled(isPackageEnabled, isComponentEnabled, componentName, flags)) {
+            return reportIfDebug(false, flags);
+        }
 
         if ((flags & MATCH_SYSTEM_ONLY) != 0) {
-            if (!isSystemApp) {
+            if (!isSystem) {
                 return reportIfDebug(false, flags);
             }
         }
 
         final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0)
-                && !componentInfo.directBootAware;
+                && !isComponentDirectBootAware;
         final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)
-                && componentInfo.directBootAware;
+                && isComponentDirectBootAware;
         return reportIfDebug(matchesUnaware || matchesAware, flags);
     }
 
-    private boolean reportIfDebug(boolean result, int flags) {
+    public boolean reportIfDebug(boolean result, int flags) {
         if (DEBUG && !result) {
             Slog.i(LOG_TAG, "No match!; flags: "
                     + DebugUtils.flagsToString(PackageManager.class, "MATCH_", flags) + " "
@@ -165,10 +183,22 @@
         return result;
     }
 
+    public boolean isEnabled(ComponentInfo componentInfo, int flags) {
+        return isEnabled(componentInfo.applicationInfo.enabled, componentInfo.enabled,
+                componentInfo.name, flags);
+    }
+
+    public boolean isEnabled(boolean isPackageEnabled,
+            ComponentParseUtils.ParsedComponent parsedComponent, int flags) {
+        return isEnabled(isPackageEnabled, parsedComponent.isEnabled(), parsedComponent.getName(),
+                flags);
+    }
+
     /**
      * Test if the given component is considered enabled.
      */
-    public boolean isEnabled(ComponentInfo componentInfo, int flags) {
+    public boolean isEnabled(boolean isPackageEnabled, boolean isComponentEnabled,
+            String componentName, int flags) {
         if ((flags & MATCH_DISABLED_COMPONENTS) != 0) {
             return true;
         }
@@ -183,24 +213,26 @@
                 if ((flags & MATCH_DISABLED_UNTIL_USED_COMPONENTS) == 0) {
                     return false;
                 }
+                // fallthrough
             case COMPONENT_ENABLED_STATE_DEFAULT:
-                if (!componentInfo.applicationInfo.enabled) {
+                if (!isPackageEnabled) {
                     return false;
                 }
+                // fallthrough
             case COMPONENT_ENABLED_STATE_ENABLED:
                 break;
         }
 
         // Check if component has explicit state before falling through to
         // the manifest default
-        if (ArrayUtils.contains(this.enabledComponents, componentInfo.name)) {
+        if (ArrayUtils.contains(this.enabledComponents, componentName)) {
             return true;
         }
-        if (ArrayUtils.contains(this.disabledComponents, componentInfo.name)) {
+        if (ArrayUtils.contains(this.disabledComponents, componentName)) {
             return false;
         }
 
-        return componentInfo.enabled;
+        return isComponentEnabled;
     }
 
     @Override
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index 3488cc3..2863b26 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -20,6 +20,7 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -38,20 +39,24 @@
 public final class SharedLibraryInfo implements Parcelable {
 
     /** @hide */
-    public static SharedLibraryInfo createForStatic(PackageParser.Package pkg) {
-        return new SharedLibraryInfo(null, pkg.packageName, pkg.getAllCodePaths(),
-                pkg.staticSharedLibName,
-                pkg.staticSharedLibVersion,
+    public static SharedLibraryInfo createForStatic(AndroidPackage pkg) {
+        return new SharedLibraryInfo(null, pkg.getPackageName(),
+                pkg.makeListAllCodePaths(),
+                pkg.getStaticSharedLibName(),
+                pkg.getStaticSharedLibVersion(),
                 TYPE_STATIC,
-                new VersionedPackage(pkg.manifestPackageName, pkg.getLongVersionCode()),
+                new VersionedPackage(pkg.getManifestPackageName(),
+                        pkg.getLongVersionCode()),
                 null, null);
     }
 
     /** @hide */
-    public static SharedLibraryInfo createForDynamic(PackageParser.Package pkg, String name) {
-        return new SharedLibraryInfo(null, pkg.packageName, pkg.getAllCodePaths(), name,
+    public static SharedLibraryInfo createForDynamic(AndroidPackage pkg, String name) {
+        return new SharedLibraryInfo(null, pkg.getPackageName(),
+                pkg.makeListAllCodePaths(), name,
                 (long) VERSION_UNDEFINED,
-                TYPE_DYNAMIC, new VersionedPackage(pkg.packageName, pkg.getLongVersionCode()),
+                TYPE_DYNAMIC, new VersionedPackage(pkg.getPackageName(),
+                pkg.getLongVersionCode()),
                 null, null);
     }
 
diff --git a/core/java/android/content/pm/SharedLibraryNames.java b/core/java/android/content/pm/SharedLibraryNames.java
deleted file mode 100644
index a607a9f..0000000
--- a/core/java/android/content/pm/SharedLibraryNames.java
+++ /dev/null
@@ -1,36 +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 android.content.pm;
-
-/**
- * A set of shared library names
- *
- * @hide
- */
-public class SharedLibraryNames {
-
-    static final String ANDROID_HIDL_BASE = "android.hidl.base-V1.0-java";
-
-    static final String ANDROID_HIDL_MANAGER = "android.hidl.manager-V1.0-java";
-
-    static final String ANDROID_TEST_BASE = "android.test.base";
-
-    static final String ANDROID_TEST_MOCK = "android.test.mock";
-
-    static final String ANDROID_TEST_RUNNER = "android.test.runner";
-
-    public static final String ORG_APACHE_HTTP_LEGACY = "org.apache.http.legacy";
-}
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index a83c3da..fff9cf3 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -26,6 +26,8 @@
 import android.os.UserManager;
 import android.util.DebugUtils;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -385,6 +387,13 @@
         }
     }
 
+    // TODO(b/142482943): Get rid of this (after removing it from all tests) if feasible.
+    /**
+     * @deprecated This is dangerous since it doesn't set the mandatory fields. Use a different
+     * constructor instead.
+     */
+    @Deprecated
+    @VisibleForTesting
     public UserInfo() {
     }
 
diff --git a/core/java/android/content/pm/dex/DexMetadataHelper.java b/core/java/android/content/pm/dex/DexMetadataHelper.java
index 5d10b88..4cd201f 100644
--- a/core/java/android/content/pm/dex/DexMetadataHelper.java
+++ b/core/java/android/content/pm/dex/DexMetadataHelper.java
@@ -22,6 +22,7 @@
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.parsing.AndroidPackage;
 import android.util.ArrayMap;
 import android.util.jar.StrictJarFile;
 
@@ -86,8 +87,8 @@
      *
      * NOTE: involves I/O checks.
      */
-    public static Map<String, String> getPackageDexMetadata(PackageParser.Package pkg) {
-        return buildPackageApkToDexMetadataMap(pkg.getAllCodePaths());
+    public static Map<String, String> getPackageDexMetadata(AndroidPackage pkg) {
+        return buildPackageApkToDexMetadataMap(pkg.makeListAllCodePaths());
     }
 
     /**
@@ -160,7 +161,7 @@
      *
      * @throws PackageParserException in case of errors.
      */
-    public static void validatePackageDexMetadata(PackageParser.Package pkg)
+    public static void validatePackageDexMetadata(AndroidPackage pkg)
             throws PackageParserException {
         Collection<String> apkToDexMetadataList = getPackageDexMetadata(pkg).values();
         for (String dexMetadata : apkToDexMetadataList) {
diff --git a/core/java/android/content/pm/parsing/AndroidPackage.aidl b/core/java/android/content/pm/parsing/AndroidPackage.aidl
new file mode 100644
index 0000000..ab3cf7c
--- /dev/null
+++ b/core/java/android/content/pm/parsing/AndroidPackage.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License")
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.content.pm.parsing;
+
+/* @hide */
+parcelable AndroidPackage;
diff --git a/core/java/android/content/pm/parsing/AndroidPackage.java b/core/java/android/content/pm/parsing/AndroidPackage.java
new file mode 100644
index 0000000..35df474
--- /dev/null
+++ b/core/java/android/content/pm/parsing/AndroidPackage.java
@@ -0,0 +1,480 @@
+/*
+ * 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.content.pm.parsing;
+
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.FeatureGroupInfo;
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageUserState;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
+import android.content.pm.parsing.ComponentParseUtils.ParsedService;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArraySet;
+import android.util.SparseArray;
+
+import java.security.PublicKey;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * The last state of a package during parsing/install before it is available in
+ * {@link com.android.server.pm.PackageManagerService#mPackages}.
+ *
+ * It is the responsibility of the caller to understand what data is available at what step of the
+ * parsing or install process.
+ *
+ * TODO(b/135203078): Nullability annotations
+ * TODO(b/135203078): Remove get/setAppInfo differences
+ *
+ * @hide
+ */
+public interface AndroidPackage extends Parcelable {
+
+    /**
+     * This will eventually be removed. Avoid calling this at all costs.
+     */
+    @Deprecated
+    AndroidPackageWrite mutate();
+
+    boolean canHaveOatDir();
+
+    boolean cantSaveState();
+
+    List<String> getAdoptPermissions();
+
+    List<String> getAllCodePaths();
+
+    List<String> getAllCodePathsExcludingResourceOnly();
+
+    String getAppComponentFactory();
+
+    /**
+     * TODO(b/135203078): Use non-AppInfo method
+     * @deprecated use {@link #getClassLoaderName()}
+     */
+    @Deprecated
+    String getAppInfoClassLoaderName();
+
+    /**
+     * TODO(b/135203078): Use non-AppInfo method
+     * @deprecated use {@link #getCodePath()}
+     */
+    @Deprecated
+    String getAppInfoCodePath();
+
+    /**
+     * TODO(b/135203078): Use non-AppInfo method
+     * @deprecated use {@link #getName()}
+     */
+    @Deprecated
+    String getAppInfoName();
+
+    /**
+     * TODO(b/135203078): Use non-AppInfo method
+     * @deprecated use {@link #getPackageName()}
+     */
+    @Deprecated
+    String getAppInfoPackageName();
+
+    /**
+     * TODO(b/135203078): Use non-AppInfo method
+     * @deprecated use {@link #getProcessName()}
+     */
+    @Deprecated
+    String getAppInfoProcessName();
+
+    /**
+     * TODO(b/135203078): Use non-AppInfo method
+     * @deprecated use {@link #getCodePath()}
+     */
+    @Deprecated
+    String getAppInfoResourcePath();
+
+    Bundle getAppMetaData();
+
+    /**
+     * TODO(b/135203078): Use non-AppInfo method
+     * @deprecated use {@link #getVolumeUuid()}
+     */
+    @Deprecated
+    String getApplicationInfoVolumeUuid();
+
+    String getBackupAgentName();
+
+    int getBanner();
+
+    String getBaseCodePath();
+
+    int getBaseRevisionCode();
+
+    int getCategory();
+
+    String getClassLoaderName();
+
+    String getClassName();
+
+    String getCodePath();
+
+    int getCompatibleWidthLimitDp();
+
+    int getCompileSdkVersion();
+
+    String getCompileSdkVersionCodeName();
+
+    @Nullable
+    List<ConfigurationInfo> getConfigPreferences();
+
+    String getCpuAbiOverride();
+
+    String getCredentialProtectedDataDir();
+
+    String getDataDir();
+
+    int getDescriptionRes();
+
+    String getDeviceProtectedDataDir();
+
+    List<FeatureGroupInfo> getFeatureGroups();
+
+    int getFlags();
+
+    int getFullBackupContent();
+
+    int getHiddenApiEnforcementPolicy();
+
+    int getIcon();
+
+    int getIconRes();
+
+    List<String> getImplicitPermissions();
+
+    int getInstallLocation();
+
+    Map<String, ArraySet<PublicKey>> getKeySetMapping();
+
+    int getLabelRes();
+
+    int getLargestWidthLimitDp();
+
+    long[] getLastPackageUsageTimeInMills();
+
+    long getLatestForegroundPackageUseTimeInMills();
+
+    long getLatestPackageUseTimeInMills();
+
+    List<String> getLibraryNames();
+
+    int getLogo();
+
+    long getLongVersionCode();
+
+    String getManageSpaceActivityName();
+
+    String getManifestPackageName();
+
+    float getMaxAspectRatio();
+
+    Bundle getMetaData(); // TODO(b/135203078): Make all the Bundles immutable
+
+    float getMinAspectRatio();
+
+    int getMinSdkVersion();
+
+    String getName();
+
+    String getNativeLibraryDir();
+
+    String getNativeLibraryRootDir();
+
+    int getNetworkSecurityConfigRes();
+
+    CharSequence getNonLocalizedLabel();
+
+    @Nullable
+    List<String> getOriginalPackages();
+
+    String getOverlayCategory();
+
+    int getOverlayPriority();
+
+    String getOverlayTarget();
+
+    String getOverlayTargetName();
+
+    /**
+     * Map of overlayable name to actor name.
+     */
+    Map<String, String> getOverlayables();
+
+    // TODO(b/135203078): Does this and getAppInfoPackageName have to be separate methods?
+    //  The refactor makes them the same value with no known consequences, so should be redundant.
+    String getPackageName();
+
+    @Nullable
+    List<ParsedActivity> getActivities();
+
+    @Nullable
+    List<ParsedInstrumentation> getInstrumentations();
+
+    @Nullable
+    List<ParsedPermissionGroup> getPermissionGroups();
+
+    @Nullable
+    List<ParsedPermission> getPermissions();
+
+    @Nullable
+    List<ParsedProvider> getProviders();
+
+    @Nullable
+    List<ParsedActivity> getReceivers();
+
+    @Nullable
+    List<ParsedService> getServices();
+
+    String getPermission();
+
+    @Nullable
+    List<ParsedActivityIntentInfo> getPreferredActivityFilters();
+
+    int getPreferredOrder();
+
+    String getPrimaryCpuAbi();
+
+    int getPrivateFlags();
+
+    String getProcessName();
+
+    @Nullable
+    List<String> getProtectedBroadcasts();
+
+    String getPublicSourceDir();
+
+    List<Intent> getQueriesIntents();
+
+    List<String> getQueriesPackages();
+
+    String getRealPackage();
+
+    // TODO(b/135203078): Rename to getRequiredFeatures? Somewhat ambiguous whether "Req" is
+    //  required or requested.
+    @Nullable
+    List<FeatureInfo> getReqFeatures();
+
+    List<String> getRequestedPermissions();
+
+    String getRequiredAccountType();
+
+    int getRequiresSmallestWidthDp();
+
+    byte[] getRestrictUpdateHash();
+
+    String getRestrictedAccountType();
+
+    int getRoundIconRes();
+
+    String getScanPublicSourceDir();
+
+    String getScanSourceDir();
+
+    String getSeInfo();
+
+    String getSeInfoUser();
+
+    String getSecondaryCpuAbi();
+
+    String getSecondaryNativeLibraryDir();
+
+    String getSharedUserId();
+
+    int getSharedUserLabel();
+
+    PackageParser.SigningDetails getSigningDetails();
+
+    String[] getSplitClassLoaderNames();
+
+    @Nullable
+    String[] getSplitCodePaths();
+
+    @Nullable
+    SparseArray<int[]> getSplitDependencies();
+
+    int[] getSplitFlags();
+
+    String[] getSplitNames();
+
+    String[] getSplitPublicSourceDirs();
+
+    int[] getSplitRevisionCodes();
+
+    String getStaticSharedLibName();
+
+    long getStaticSharedLibVersion();
+
+    // TODO(b/135203078): Return String directly
+    UUID getStorageUuid();
+
+    int getTargetSandboxVersion();
+
+    int getTargetSdkVersion();
+
+    String getTaskAffinity();
+
+    int getTheme();
+
+    int getUiOptions();
+
+    int getUid();
+
+    Set<String> getUpgradeKeySets();
+
+    @Nullable
+    List<String> getUsesLibraries();
+
+    @Nullable
+    String[] getUsesLibraryFiles();
+
+    List<SharedLibraryInfo> getUsesLibraryInfos();
+
+    @Nullable
+    List<String> getUsesOptionalLibraries();
+
+    @Nullable
+    List<String> getUsesStaticLibraries();
+
+    @Nullable
+    String[][] getUsesStaticLibrariesCertDigests();
+
+    @Nullable
+    long[] getUsesStaticLibrariesVersions();
+
+    int getVersionCode();
+
+    int getVersionCodeMajor();
+
+    String getVersionName();
+
+    String getVolumeUuid();
+
+    String getZygotePreloadName();
+
+    boolean hasComponentClassName(String className);
+
+    // App Info
+
+    boolean hasRequestedLegacyExternalStorage();
+
+    boolean isBaseHardwareAccelerated();
+
+    boolean isCoreApp();
+
+    boolean isDefaultToDeviceProtectedStorage();
+
+    boolean isDirectBootAware();
+
+    boolean isEmbeddedDexUsed();
+
+    boolean isEnabled();
+
+    boolean isEncryptionAware();
+
+    boolean isExternal();
+
+    boolean isForceQueryable();
+
+    boolean isForwardLocked();
+
+    boolean isHiddenUntilInstalled();
+
+    boolean isInstantApp();
+
+    boolean isInternal();
+
+    boolean isLibrary();
+
+    // TODO(b/135203078): Should probably be in a utility class
+    boolean isMatch(int flags);
+
+    boolean isNativeLibraryRootRequiresIsa();
+
+    boolean isOem();
+
+    boolean isOverlayIsStatic();
+
+    boolean isPrivileged();
+
+    boolean isProduct();
+
+    boolean isProfileableByShell();
+
+    boolean isRequiredForAllUsers();
+
+    boolean isStaticSharedLibrary();
+
+    boolean isStub();
+
+    boolean isSystem(); // TODO(b/135203078): Collapse with isSystemApp, should be exactly the same.
+
+    boolean isSystemApp();
+
+    boolean isSystemExt();
+
+    boolean isUpdatedSystemApp();
+
+    boolean isUse32BitAbi();
+
+    boolean isVendor();
+
+    boolean isVisibleToInstantApps();
+
+    List<String> makeListAllCodePaths(); // TODO(b/135203078): Collapse with getAllCodePaths
+
+    boolean requestsIsolatedSplitLoading();
+
+    /**
+     * Generates an {@link ApplicationInfo} object with only the data available in this object.
+     *
+     * This does not contain any system or user state data, and should be avoided. Prefer
+     * {@link PackageInfoUtils#generateApplicationInfo(AndroidPackage, int, PackageUserState, int)}.
+     */
+    ApplicationInfo toAppInfoWithoutState();
+
+    Creator<PackageImpl> CREATOR = new Creator<PackageImpl>() {
+        @Override
+        public PackageImpl createFromParcel(Parcel source) {
+            return new PackageImpl(source);
+        }
+
+        @Override
+        public PackageImpl[] newArray(int size) {
+            return new PackageImpl[size];
+        }
+    };
+}
diff --git a/core/java/android/content/pm/parsing/AndroidPackageWrite.java b/core/java/android/content/pm/parsing/AndroidPackageWrite.java
new file mode 100644
index 0000000..b7595d2
--- /dev/null
+++ b/core/java/android/content/pm/parsing/AndroidPackageWrite.java
@@ -0,0 +1,59 @@
+/*
+ * 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.content.pm.parsing;
+
+import android.annotation.Nullable;
+import android.content.pm.PackageParser;
+import android.content.pm.SharedLibraryInfo;
+
+import java.util.List;
+
+/**
+ * Contains remaining mutable fields after package parsing has completed.
+ *
+ * Most are state that can probably be tracked outside of the AndroidPackage object. New methods
+ * should never be added to this interface.
+ *
+ * TODO(b/135203078): Remove entirely
+ *
+ * @deprecated the eventual goal is that the object returned from parsing represents exactly what
+ * was parsed from the APK, and so further mutation should be disallowed,
+ * with any state being stored in another class
+ *
+ * @hide
+ */
+@Deprecated
+public interface AndroidPackageWrite extends AndroidPackage {
+
+    AndroidPackageWrite setUsesLibraryFiles(@Nullable String[] usesLibraryFiles);
+
+    // TODO(b/135203078): Remove or use a non-system wide representation of the shared libraries;
+    //  this doesn't represent what was parsed from the APK
+    AndroidPackageWrite setUsesLibraryInfos(@Nullable List<SharedLibraryInfo> usesLibraryInfos);
+
+    AndroidPackageWrite setHiddenUntilInstalled(boolean hidden);
+
+    AndroidPackageWrite setUpdatedSystemApp(boolean updatedSystemApp);
+
+    AndroidPackageWrite setLastPackageUsageTimeInMills(int reason, long time);
+
+    AndroidPackageWrite setPrimaryCpuAbi(String primaryCpuAbi);
+
+    AndroidPackageWrite setSeInfo(String seInfo);
+
+    AndroidPackageWrite setSigningDetails(PackageParser.SigningDetails signingDetails);
+}
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
new file mode 100644
index 0000000..ac2e373
--- /dev/null
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -0,0 +1,428 @@
+/*
+ * 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.content.pm.parsing;
+
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
+import android.annotation.UnsupportedAppUsage;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.VerifierInfo;
+import android.content.res.ApkAssets;
+import android.content.res.XmlResourceParser;
+import android.os.Trace;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+import android.util.Pair;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.internal.util.ArrayUtils;
+
+import libcore.io.IoUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/** @hide */
+public class ApkLiteParseUtils {
+
+    private static final String TAG = ApkParseUtils.TAG;
+
+    // TODO(b/135203078): Consolidate constants
+    private static final int DEFAULT_MIN_SDK_VERSION = 1;
+    private static final int DEFAULT_TARGET_SDK_VERSION = 0;
+
+    private static final int PARSE_DEFAULT_INSTALL_LOCATION =
+            PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
+
+    /**
+     * Parse only lightweight details about the package at the given location.
+     * Automatically detects if the package is a monolithic style (single APK
+     * file) or cluster style (directory of APKs).
+     * <p>
+     * This performs sanity checking on cluster style packages, such as
+     * requiring identical package name and version codes, a single base APK,
+     * and unique split names.
+     *
+     * @see PackageParser#parsePackage(File, int)
+     */
+    @UnsupportedAppUsage
+    public static PackageParser.PackageLite parsePackageLite(File packageFile, int flags)
+            throws PackageParser.PackageParserException {
+        if (packageFile.isDirectory()) {
+            return parseClusterPackageLite(packageFile, flags);
+        } else {
+            return parseMonolithicPackageLite(packageFile, flags);
+        }
+    }
+
+    public static PackageParser.PackageLite parseMonolithicPackageLite(File packageFile, int flags)
+            throws PackageParser.PackageParserException {
+        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
+        final PackageParser.ApkLite baseApk = parseApkLite(packageFile, flags);
+        final String packagePath = packageFile.getAbsolutePath();
+        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        return new PackageParser.PackageLite(packagePath, baseApk, null, null, null, null,
+                null, null);
+    }
+
+    public static PackageParser.PackageLite parseClusterPackageLite(File packageDir, int flags)
+            throws PackageParser.PackageParserException {
+        final File[] files = packageDir.listFiles();
+        if (ArrayUtils.isEmpty(files)) {
+            throw new PackageParser.PackageParserException(
+                    PackageManager.INSTALL_PARSE_FAILED_NOT_APK, "No packages found in split");
+        }
+
+        String packageName = null;
+        int versionCode = 0;
+
+        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
+        final ArrayMap<String, PackageParser.ApkLite> apks = new ArrayMap<>();
+        for (File file : files) {
+            if (PackageParser.isApkFile(file)) {
+                final PackageParser.ApkLite lite = parseApkLite(file, flags);
+
+                // Assert that all package names and version codes are
+                // consistent with the first one we encounter.
+                if (packageName == null) {
+                    packageName = lite.packageName;
+                    versionCode = lite.versionCode;
+                } else {
+                    if (!packageName.equals(lite.packageName)) {
+                        throw new PackageParser.PackageParserException(
+                                PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+                                "Inconsistent package " + lite.packageName + " in " + file
+                                        + "; expected " + packageName);
+                    }
+                    if (versionCode != lite.versionCode) {
+                        throw new PackageParser.PackageParserException(
+                                PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+                                "Inconsistent version " + lite.versionCode + " in " + file
+                                        + "; expected " + versionCode);
+                    }
+                }
+
+                // Assert that each split is defined only oncuses-static-libe
+                if (apks.put(lite.splitName, lite) != null) {
+                    throw new PackageParser.PackageParserException(
+                            PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+                            "Split name " + lite.splitName
+                                    + " defined more than once; most recent was " + file);
+                }
+            }
+        }
+        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+
+        final PackageParser.ApkLite baseApk = apks.remove(null);
+        if (baseApk == null) {
+            throw new PackageParser.PackageParserException(
+                    PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
+                    "Missing base APK in " + packageDir);
+        }
+
+        // Always apply deterministic ordering based on splitName
+        final int size = apks.size();
+
+        String[] splitNames = null;
+        boolean[] isFeatureSplits = null;
+        String[] usesSplitNames = null;
+        String[] configForSplits = null;
+        String[] splitCodePaths = null;
+        int[] splitRevisionCodes = null;
+        if (size > 0) {
+            splitNames = new String[size];
+            isFeatureSplits = new boolean[size];
+            usesSplitNames = new String[size];
+            configForSplits = new String[size];
+            splitCodePaths = new String[size];
+            splitRevisionCodes = new int[size];
+
+            splitNames = apks.keySet().toArray(splitNames);
+            Arrays.sort(splitNames, PackageParser.sSplitNameComparator);
+
+            for (int i = 0; i < size; i++) {
+                final PackageParser.ApkLite apk = apks.get(splitNames[i]);
+                usesSplitNames[i] = apk.usesSplitName;
+                isFeatureSplits[i] = apk.isFeatureSplit;
+                configForSplits[i] = apk.configForSplit;
+                splitCodePaths[i] = apk.codePath;
+                splitRevisionCodes[i] = apk.revisionCode;
+            }
+        }
+
+        final String codePath = packageDir.getAbsolutePath();
+        return new PackageParser.PackageLite(codePath, baseApk, splitNames, isFeatureSplits,
+                usesSplitNames, configForSplits, splitCodePaths, splitRevisionCodes);
+    }
+
+    /**
+     * Utility method that retrieves lightweight details about a single APK
+     * file, including package name, split name, and install location.
+     *
+     * @param apkFile path to a single APK
+     * @param flags optional parse flags, such as
+     *            {@link PackageParser#PARSE_COLLECT_CERTIFICATES}
+     */
+    public static PackageParser.ApkLite parseApkLite(File apkFile, int flags)
+            throws PackageParser.PackageParserException {
+        return parseApkLiteInner(apkFile, null, null, flags);
+    }
+
+    /**
+     * Utility method that retrieves lightweight details about a single APK
+     * file, including package name, split name, and install location.
+     *
+     * @param fd already open file descriptor of an apk file
+     * @param debugPathName arbitrary text name for this file, for debug output
+     * @param flags optional parse flags, such as
+     *            {@link PackageParser#PARSE_COLLECT_CERTIFICATES}
+     */
+    public static PackageParser.ApkLite parseApkLite(FileDescriptor fd, String debugPathName,
+            int flags) throws PackageParser.PackageParserException {
+        return parseApkLiteInner(null, fd, debugPathName, flags);
+    }
+
+    private static PackageParser.ApkLite parseApkLiteInner(File apkFile, FileDescriptor fd,
+            String debugPathName, int flags) throws PackageParser.PackageParserException {
+        final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath();
+
+        XmlResourceParser parser = null;
+        ApkAssets apkAssets = null;
+        try {
+            try {
+                apkAssets = fd != null
+                        ? ApkAssets.loadFromFd(fd, debugPathName, false, false)
+                        : ApkAssets.loadFromPath(apkPath);
+            } catch (IOException e) {
+                throw new PackageParser.PackageParserException(
+                        PackageManager.INSTALL_PARSE_FAILED_NOT_APK,
+                        "Failed to parse " + apkPath, e);
+            }
+
+            parser = apkAssets.openXml(PackageParser.ANDROID_MANIFEST_FILENAME);
+
+            final PackageParser.SigningDetails signingDetails;
+            if ((flags & PackageParser.PARSE_COLLECT_CERTIFICATES) != 0) {
+                final boolean skipVerify = (flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0;
+                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
+                try {
+                    signingDetails =
+                            ApkParseUtils.collectCertificates(apkFile.getAbsolutePath(), skipVerify,
+                                    false, PackageParser.SigningDetails.UNKNOWN);
+                } finally {
+                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+                }
+            } else {
+                signingDetails = PackageParser.SigningDetails.UNKNOWN;
+            }
+
+            final AttributeSet attrs = parser;
+            return parseApkLite(apkPath, parser, attrs, signingDetails);
+
+        } catch (XmlPullParserException | IOException | RuntimeException e) {
+            Slog.w(TAG, "Failed to parse " + apkPath, e);
+            throw new PackageParser.PackageParserException(
+                    PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+                    "Failed to parse " + apkPath, e);
+        } finally {
+            IoUtils.closeQuietly(parser);
+            if (apkAssets != null) {
+                try {
+                    apkAssets.close();
+                } catch (Throwable ignored) {
+                }
+            }
+            // TODO(b/72056911): Implement AutoCloseable on ApkAssets.
+        }
+    }
+
+    private static PackageParser.ApkLite parseApkLite(
+            String codePath, XmlPullParser parser, AttributeSet attrs,
+            PackageParser.SigningDetails signingDetails)
+            throws IOException, XmlPullParserException, PackageParser.PackageParserException {
+        final Pair<String, String> packageSplit = PackageParser.parsePackageSplitNames(
+                parser, attrs);
+
+        int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
+        int versionCode = 0;
+        int versionCodeMajor = 0;
+        int targetSdkVersion = DEFAULT_TARGET_SDK_VERSION;
+        int minSdkVersion = DEFAULT_MIN_SDK_VERSION;
+        int revisionCode = 0;
+        boolean coreApp = false;
+        boolean debuggable = false;
+        boolean multiArch = false;
+        boolean use32bitAbi = false;
+        boolean extractNativeLibs = true;
+        boolean isolatedSplits = false;
+        boolean isFeatureSplit = false;
+        boolean isSplitRequired = false;
+        boolean useEmbeddedDex = false;
+        String configForSplit = null;
+        String usesSplitName = null;
+
+        for (int i = 0; i < attrs.getAttributeCount(); i++) {
+            final String attr = attrs.getAttributeName(i);
+            switch (attr) {
+                case "installLocation":
+                    installLocation = attrs.getAttributeIntValue(i,
+                            PARSE_DEFAULT_INSTALL_LOCATION);
+                    break;
+                case "versionCode":
+                    versionCode = attrs.getAttributeIntValue(i, 0);
+                    break;
+                case "versionCodeMajor":
+                    versionCodeMajor = attrs.getAttributeIntValue(i, 0);
+                    break;
+                case "revisionCode":
+                    revisionCode = attrs.getAttributeIntValue(i, 0);
+                    break;
+                case "coreApp":
+                    coreApp = attrs.getAttributeBooleanValue(i, false);
+                    break;
+                case "isolatedSplits":
+                    isolatedSplits = attrs.getAttributeBooleanValue(i, false);
+                    break;
+                case "configForSplit":
+                    configForSplit = attrs.getAttributeValue(i);
+                    break;
+                case "isFeatureSplit":
+                    isFeatureSplit = attrs.getAttributeBooleanValue(i, false);
+                    break;
+                case "isSplitRequired":
+                    isSplitRequired = attrs.getAttributeBooleanValue(i, false);
+                    break;
+            }
+        }
+
+        // Only search the tree when the tag is the direct child of <manifest> tag
+        int type;
+        final int searchDepth = parser.getDepth() + 1;
+
+        final List<VerifierInfo> verifiers = new ArrayList<>();
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() >= searchDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            if (parser.getDepth() != searchDepth) {
+                continue;
+            }
+
+            if (PackageParser.TAG_PACKAGE_VERIFIER.equals(parser.getName())) {
+                final VerifierInfo verifier = parseVerifier(attrs);
+                if (verifier != null) {
+                    verifiers.add(verifier);
+                }
+            } else if (PackageParser.TAG_APPLICATION.equals(parser.getName())) {
+                for (int i = 0; i < attrs.getAttributeCount(); ++i) {
+                    final String attr = attrs.getAttributeName(i);
+                    switch (attr) {
+                        case "debuggable":
+                            debuggable = attrs.getAttributeBooleanValue(i, false);
+                            break;
+                        case "multiArch":
+                            multiArch = attrs.getAttributeBooleanValue(i, false);
+                            break;
+                        case "use32bitAbi":
+                            use32bitAbi = attrs.getAttributeBooleanValue(i, false);
+                            break;
+                        case "extractNativeLibs":
+                            extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
+                            break;
+                        case "useEmbeddedDex":
+                            useEmbeddedDex = attrs.getAttributeBooleanValue(i, false);
+                            break;
+                    }
+                }
+            } else if (PackageParser.TAG_USES_SPLIT.equals(parser.getName())) {
+                if (usesSplitName != null) {
+                    Slog.w(TAG, "Only one <uses-split> permitted. Ignoring others.");
+                    continue;
+                }
+
+                usesSplitName = attrs.getAttributeValue(PackageParser.ANDROID_RESOURCES, "name");
+                if (usesSplitName == null) {
+                    throw new PackageParser.PackageParserException(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            "<uses-split> tag requires 'android:name' attribute");
+                }
+            } else if (PackageParser.TAG_USES_SDK.equals(parser.getName())) {
+                for (int i = 0; i < attrs.getAttributeCount(); ++i) {
+                    final String attr = attrs.getAttributeName(i);
+                    if ("targetSdkVersion".equals(attr)) {
+                        targetSdkVersion = attrs.getAttributeIntValue(i,
+                                DEFAULT_TARGET_SDK_VERSION);
+                    }
+                    if ("minSdkVersion".equals(attr)) {
+                        minSdkVersion = attrs.getAttributeIntValue(i, DEFAULT_MIN_SDK_VERSION);
+                    }
+                }
+            }
+        }
+
+        return new PackageParser.ApkLite(codePath, packageSplit.first, packageSplit.second,
+                isFeatureSplit, configForSplit, usesSplitName, isSplitRequired, versionCode,
+                versionCodeMajor, revisionCode, installLocation, verifiers, signingDetails,
+                coreApp, debuggable, multiArch, use32bitAbi, useEmbeddedDex, extractNativeLibs,
+                isolatedSplits, minSdkVersion, targetSdkVersion);
+    }
+
+    public static VerifierInfo parseVerifier(AttributeSet attrs) {
+        String packageName = null;
+        String encodedPublicKey = null;
+
+        final int attrCount = attrs.getAttributeCount();
+        for (int i = 0; i < attrCount; i++) {
+            final int attrResId = attrs.getAttributeNameResource(i);
+            switch (attrResId) {
+                case R.attr.name:
+                    packageName = attrs.getAttributeValue(i);
+                    break;
+
+                case R.attr.publicKey:
+                    encodedPublicKey = attrs.getAttributeValue(i);
+                    break;
+            }
+        }
+
+        if (packageName == null || packageName.length() == 0) {
+            Slog.i(TAG, "verifier package name was null; skipping");
+            return null;
+        }
+
+        final PublicKey publicKey = PackageParser.parsePublicKey(encodedPublicKey);
+        if (publicKey == null) {
+            Slog.i(TAG, "Unable to parse verifier public key for " + packageName);
+            return null;
+        }
+
+        return new VerifierInfo(packageName, publicKey);
+    }
+}
diff --git a/core/java/android/content/pm/parsing/ApkParseUtils.java b/core/java/android/content/pm/parsing/ApkParseUtils.java
new file mode 100644
index 0000000..ffddbb6
--- /dev/null
+++ b/core/java/android/content/pm/parsing/ApkParseUtils.java
@@ -0,0 +1,3204 @@
+/*
+ * 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.content.pm.parsing;
+
+import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.PackageManager.FEATURE_WATCH;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
+import static android.os.Build.VERSION_CODES.O;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityTaskManager;
+import android.app.ActivityThread;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.FeatureGroupInfo;
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.PackageParser.SigningDetails;
+import android.content.pm.Signature;
+import android.content.pm.permission.SplitPermissionInfoParcelable;
+import android.content.pm.split.DefaultSplitAssetLoader;
+import android.content.pm.split.SplitAssetDependencyLoader;
+import android.content.pm.split.SplitAssetLoader;
+import android.content.res.ApkAssets;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.FileUtils;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.os.Trace;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TypedValue;
+import android.util.apk.ApkSignatureVerifier;
+
+import com.android.internal.R;
+import com.android.internal.os.ClassLoaderFactory;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.XmlUtils;
+
+import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/** @hide */
+public class ApkParseUtils {
+
+    // TODO(b/135203078): Consolidate log tags
+    static final String TAG = "PackageParsing";
+
+    /**
+     * Parse the package at the given location. Automatically detects if the
+     * package is a monolithic style (single APK file) or cluster style
+     * (directory of APKs).
+     * <p>
+     * This performs sanity checking on cluster style packages, such as
+     * requiring identical package name and version codes, a single base APK,
+     * and unique split names.
+     * <p>
+     * Note that this <em>does not</em> perform signature verification; that
+     * must be done separately in {@link #collectCertificates(ParsedPackage, boolean)}.
+     *
+     * If {@code useCaches} is true, the package parser might return a cached
+     * result from a previous parse of the same {@code packageFile} with the same
+     * {@code flags}. Note that this method does not check whether {@code packageFile}
+     * has changed since the last parse, it's up to callers to do so.
+     *
+     * @see PackageParser#parsePackageLite(File, int)
+     */
+    public static ParsingPackage parsePackage(
+            ParseInput parseInput,
+            String[] separateProcesses,
+            PackageParser.Callback callback,
+            DisplayMetrics displayMetrics,
+            boolean onlyCoreApps,
+            File packageFile,
+            int flags
+    ) throws PackageParserException {
+        if (packageFile.isDirectory()) {
+            return parseClusterPackage(parseInput, separateProcesses, callback, displayMetrics,
+                    onlyCoreApps, packageFile, flags);
+        } else {
+            return parseMonolithicPackage(parseInput, separateProcesses, callback, displayMetrics,
+                    onlyCoreApps, packageFile, flags);
+        }
+    }
+
+    /**
+     * Parse all APKs contained in the given directory, treating them as a
+     * single package. This also performs sanity checking, such as requiring
+     * identical package name and version codes, a single base APK, and unique
+     * split names.
+     * <p>
+     * Note that this <em>does not</em> perform signature verification; that
+     * must be done separately in {@link #collectCertificates(ParsedPackage, boolean)}.
+     */
+    private static ParsingPackage parseClusterPackage(
+            ParseInput parseInput,
+            String[] separateProcesses,
+            PackageParser.Callback callback,
+            DisplayMetrics displayMetrics,
+            boolean onlyCoreApps,
+            File packageDir,
+            int flags
+    ) throws PackageParserException {
+        final PackageParser.PackageLite lite = ApkLiteParseUtils.parseClusterPackageLite(packageDir,
+                0);
+        if (onlyCoreApps && !lite.coreApp) {
+            throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "Not a coreApp: " + packageDir);
+        }
+
+        // Build the split dependency tree.
+        SparseArray<int[]> splitDependencies = null;
+        final SplitAssetLoader assetLoader;
+        if (lite.isolatedSplits && !ArrayUtils.isEmpty(lite.splitNames)) {
+            try {
+                splitDependencies = SplitAssetDependencyLoader.createDependenciesFromPackage(lite);
+                assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags);
+            } catch (SplitAssetDependencyLoader.IllegalDependencyException e) {
+                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage());
+            }
+        } else {
+            assetLoader = new DefaultSplitAssetLoader(lite, flags);
+        }
+
+        try {
+            final AssetManager assets = assetLoader.getBaseAssetManager();
+            final File baseApk = new File(lite.baseCodePath);
+            ParsingPackage parsingPackage = parseBaseApk(parseInput, separateProcesses, callback,
+                    displayMetrics, baseApk, assets, flags);
+            if (parsingPackage == null) {
+                throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+                        "Failed to parse base APK: " + baseApk);
+            }
+
+            if (!ArrayUtils.isEmpty(lite.splitNames)) {
+                parsingPackage.asSplit(
+                        lite.splitNames,
+                        lite.splitCodePaths,
+                        lite.splitRevisionCodes,
+                        splitDependencies
+                );
+                final int num = lite.splitNames.length;
+
+                for (int i = 0; i < num; i++) {
+                    final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
+                    parseSplitApk(parseInput, displayMetrics, separateProcesses, parsingPackage, i,
+                            splitAssets, flags);
+                }
+            }
+
+            return parsingPackage.setCodePath(packageDir.getCanonicalPath())
+                    .setUse32BitAbi(lite.use32bitAbi);
+        } catch (IOException e) {
+            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+                    "Failed to get path: " + lite.baseCodePath, e);
+        } finally {
+            IoUtils.closeQuietly(assetLoader);
+        }
+    }
+
+    /**
+     * Parse the given APK file, treating it as as a single monolithic package.
+     * <p>
+     * Note that this <em>does not</em> perform signature verification; that
+     * must be done separately in {@link #collectCertificates(AndroidPackage, boolean)}.
+     */
+    public static ParsingPackage parseMonolithicPackage(
+            ParseInput parseInput,
+            String[] separateProcesses,
+            PackageParser.Callback callback,
+            DisplayMetrics displayMetrics,
+            boolean onlyCoreApps,
+            File apkFile,
+            int flags
+    ) throws PackageParserException {
+        final PackageParser.PackageLite lite = ApkLiteParseUtils.parseMonolithicPackageLite(apkFile,
+                flags);
+        if (onlyCoreApps) {
+            if (!lite.coreApp) {
+                throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                        "Not a coreApp: " + apkFile);
+            }
+        }
+
+        final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
+        try {
+            return parseBaseApk(parseInput, separateProcesses, callback,
+                    displayMetrics, apkFile, assetLoader.getBaseAssetManager(), flags)
+                    .setCodePath(apkFile.getCanonicalPath())
+                    .setUse32BitAbi(lite.use32bitAbi);
+        } catch (IOException e) {
+            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+                    "Failed to get path: " + apkFile, e);
+        } finally {
+            IoUtils.closeQuietly(assetLoader);
+        }
+    }
+
+    private static ParsingPackage parseBaseApk(
+            ParseInput parseInput,
+            String[] separateProcesses,
+            PackageParser.Callback callback,
+            DisplayMetrics displayMetrics,
+            File apkFile,
+            AssetManager assets,
+            int flags
+    ) throws PackageParserException {
+        final String apkPath = apkFile.getAbsolutePath();
+
+        String volumeUuid = null;
+        if (apkPath.startsWith(PackageParser.MNT_EXPAND)) {
+            final int end = apkPath.indexOf('/', PackageParser.MNT_EXPAND.length());
+            volumeUuid = apkPath.substring(PackageParser.MNT_EXPAND.length(), end);
+        }
+
+        if (PackageParser.DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
+
+        XmlResourceParser parser = null;
+        try {
+            final int cookie = assets.findCookieForPath(apkPath);
+            if (cookie == 0) {
+                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
+                        "Failed adding asset path: " + apkPath);
+            }
+            parser = assets.openXmlResourceParser(cookie, PackageParser.ANDROID_MANIFEST_FILENAME);
+            final Resources res = new Resources(assets, displayMetrics, null);
+
+            ParseResult result = parseBaseApk(parseInput, separateProcesses, callback, apkPath, res,
+                    parser, flags);
+            if (!result.isSuccess()) {
+                throw new PackageParserException(result.getParseError(),
+                        apkPath + " (at " + parser.getPositionDescription() + "): "
+                                + result.getErrorMessage());
+            }
+
+            ParsingPackage pkg = result.getResultAndNull();
+            ApkAssets apkAssets = assets.getApkAssets()[0];
+            if (apkAssets.definesOverlayable()) {
+                SparseArray<String> packageNames = assets.getAssignedPackageIdentifiers();
+                int size = packageNames.size();
+                for (int index = 0; index < size; index++) {
+                    String packageName = packageNames.get(index);
+                    Map<String, String> overlayableToActor = assets.getOverlayableMap(packageName);
+                    if (overlayableToActor != null && !overlayableToActor.isEmpty()) {
+                        for (String overlayable : overlayableToActor.keySet()) {
+                            pkg.addOverlayable(overlayable, overlayableToActor.get(overlayable));
+                        }
+                    }
+                }
+            }
+
+            return pkg.setVolumeUuid(volumeUuid)
+                    .setApplicationVolumeUuid(volumeUuid)
+                    .setSigningDetails(SigningDetails.UNKNOWN);
+        } catch (PackageParserException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+                    "Failed to read manifest from " + apkPath, e);
+        } finally {
+            IoUtils.closeQuietly(parser);
+        }
+    }
+
+    private static void parseSplitApk(
+            ParseInput parseInput,
+            DisplayMetrics displayMetrics,
+            String[] separateProcesses,
+            ParsingPackage parsingPackage,
+            int splitIndex,
+            AssetManager assets,
+            int flags
+    ) throws PackageParserException {
+        final String apkPath = parsingPackage.getSplitCodePaths()[splitIndex];
+
+        if (PackageParser.DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath);
+
+        final Resources res;
+        XmlResourceParser parser = null;
+        try {
+            // This must always succeed, as the path has been added to the AssetManager before.
+            final int cookie = assets.findCookieForPath(apkPath);
+            if (cookie == 0) {
+                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
+                        "Failed adding asset path: " + apkPath);
+            }
+
+            parser = assets.openXmlResourceParser(cookie, PackageParser.ANDROID_MANIFEST_FILENAME);
+            res = new Resources(assets, displayMetrics, null);
+
+            final String[] outError = new String[1];
+            ParseResult parseResult = parseSplitApk(parseInput, separateProcesses, parsingPackage,
+                    res, parser, flags, splitIndex, outError);
+            if (!parseResult.isSuccess()) {
+                throw new PackageParserException(parseResult.getParseError(),
+                        apkPath + " (at " + parser.getPositionDescription() + "): "
+                                + parseResult.getErrorMessage());
+            }
+        } catch (PackageParserException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+                    "Failed to read manifest from " + apkPath, e);
+        } finally {
+            IoUtils.closeQuietly(parser);
+        }
+    }
+
+    /**
+     * Parse the manifest of a <em>base APK</em>. When adding new features you
+     * need to consider whether they should be supported by split APKs and child
+     * packages.
+     *
+     * @param apkPath  The package apk file path
+     * @param res      The resources from which to resolve values
+     * @param parser   The manifest parser
+     * @param flags    Flags how to parse
+     * @return Parsed package or null on error.
+     */
+    private static ParseResult parseBaseApk(
+            ParseInput parseInput,
+            String[] separateProcesses,
+            PackageParser.Callback callback,
+            String apkPath,
+            Resources res,
+            XmlResourceParser parser,
+            int flags
+    ) throws XmlPullParserException, IOException {
+        final String splitName;
+        final String pkgName;
+
+        try {
+            Pair<String, String> packageSplit = PackageParser.parsePackageSplitNames(parser,
+                    parser);
+            pkgName = packageSplit.first;
+            splitName = packageSplit.second;
+
+            if (!TextUtils.isEmpty(splitName)) {
+                return parseInput.error(
+                        PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
+                        "Expected base APK, but found split " + splitName
+                );
+            }
+        } catch (PackageParserException e) {
+            return parseInput.error(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME);
+        }
+
+        TypedArray manifestArray = null;
+
+        try {
+            manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest);
+
+            boolean isCoreApp = parser.getAttributeBooleanValue(null, "coreApp", false);
+
+            ParsingPackage parsingPackage = PackageImpl.forParsing(
+                    pkgName,
+                    apkPath,
+                    manifestArray,
+                    isCoreApp
+            );
+
+            ParseResult result = parseBaseApkTags(parseInput, separateProcesses, callback,
+                    parsingPackage, manifestArray, res, parser, flags);
+            if (!result.isSuccess()) {
+                return result;
+            }
+
+            return parseInput.success(parsingPackage);
+        } finally {
+            if (manifestArray != null) {
+                manifestArray.recycle();
+            }
+        }
+    }
+
+    /**
+     * Parse the manifest of a <em>split APK</em>.
+     * <p>
+     * Note that split APKs have many more restrictions on what they're capable
+     * of doing, so many valid features of a base APK have been carefully
+     * omitted here.
+     *
+     * @param parsingPackage builder to fill
+     * @return false on failure
+     */
+    private static ParseResult parseSplitApk(
+            ParseInput parseInput,
+            String[] separateProcesses,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser,
+            int flags,
+            int splitIndex,
+            String[] outError
+    ) throws XmlPullParserException, IOException, PackageParserException {
+        AttributeSet attrs = parser;
+
+        // We parsed manifest tag earlier; just skip past it
+        PackageParser.parsePackageSplitNames(parser, attrs);
+
+        int type;
+
+        boolean foundApp = false;
+
+        int outerDepth = parser.getDepth();
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+            if (tagName.equals(PackageParser.TAG_APPLICATION)) {
+                if (foundApp) {
+                    if (PackageParser.RIGID_PARSER) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                "<manifest> has more than one <application>"
+                        );
+                    } else {
+                        Slog.w(TAG, "<manifest> has more than one <application>");
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                }
+
+                foundApp = true;
+                ParseResult parseResult = parseSplitApplication(parseInput, separateProcesses,
+                        parsingPackage, res,
+                        parser, flags,
+                        splitIndex, outError);
+                if (!parseResult.isSuccess()) {
+                    return parseResult;
+                }
+
+            } else if (PackageParser.RIGID_PARSER) {
+                return parseInput.error(
+                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                        "Bad element under <manifest>: " + parser.getName()
+                );
+
+            } else {
+                Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
+                        + " at " + parsingPackage.getBaseCodePath() + " "
+                        + parser.getPositionDescription());
+                XmlUtils.skipCurrentTag(parser);
+                continue;
+            }
+        }
+
+        if (!foundApp) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY,
+                    "<manifest> does not contain an <application>"
+            );
+        }
+
+        return parseInput.success(parsingPackage);
+    }
+
+    /**
+     * Parse the {@code application} XML tree at the current parse location in a
+     * <em>split APK</em> manifest.
+     * <p>
+     * Note that split APKs have many more restrictions on what they're capable
+     * of doing, so many valid features of a base APK have been carefully
+     * omitted here.
+     */
+    private static ParseResult parseSplitApplication(
+            ParseInput parseInput,
+            String[] separateProcesses,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser,
+            int flags,
+            int splitIndex,
+            String[] outError
+    ) throws XmlPullParserException, IOException {
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestApplication);
+
+        parsingPackage.setSplitHasCode(splitIndex, sa.getBoolean(
+                R.styleable.AndroidManifestApplication_hasCode, true));
+
+        final String classLoaderName = sa.getString(
+                R.styleable.AndroidManifestApplication_classLoader);
+        if (classLoaderName == null || ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) {
+            parsingPackage.setSplitClassLoaderName(splitIndex, classLoaderName);
+        } else {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "Invalid class loader name: " + classLoaderName
+            );
+        }
+
+        final int innerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            ComponentParseUtils.ParsedComponent parsedComponent = null;
+
+            String tagName = parser.getName();
+            switch (tagName) {
+                case "activity":
+                    ComponentParseUtils.ParsedActivity activity =
+                            ComponentParseUtils.parseActivity(separateProcesses,
+                                    parsingPackage,
+                                    res, parser, flags,
+                                    outError,
+                                    false,
+                                    parsingPackage.isBaseHardwareAccelerated());
+                    if (activity == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    parsingPackage.addActivity(activity);
+                    parsedComponent = activity;
+                    break;
+                case "receiver":
+                    activity = ComponentParseUtils.parseActivity(
+                            separateProcesses, parsingPackage,
+                            res, parser, flags, outError,
+                            true, false);
+                    if (activity == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    parsingPackage.addReceiver(activity);
+                    parsedComponent = activity;
+                    break;
+                case "service":
+                    ComponentParseUtils.ParsedService s = ComponentParseUtils.parseService(
+                            separateProcesses,
+                            parsingPackage,
+                            res, parser, flags, outError
+                    );
+                    if (s == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    parsingPackage.addService(s);
+                    parsedComponent = s;
+                    break;
+                case "provider":
+                    ComponentParseUtils.ParsedProvider p = ComponentParseUtils.parseProvider(
+                            separateProcesses,
+                            parsingPackage,
+                            res, parser, flags, outError);
+                    if (p == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    parsingPackage.addProvider(p);
+                    parsedComponent = p;
+                    break;
+                case "activity-alias":
+                    activity = ComponentParseUtils.parseActivityAlias(
+                            parsingPackage,
+                            res,
+                            parser,
+                            outError
+                    );
+                    if (activity == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    parsingPackage.addActivity(activity);
+                    parsedComponent = activity;
+                    break;
+                case "meta-data":
+                    // note: application meta-data is stored off to the side, so it can
+                    // remain null in the primary copy (we like to avoid extra copies because
+                    // it can be large)
+                    Bundle appMetaData = parseMetaData(parsingPackage, res, parser,
+                            parsingPackage.getAppMetaData(),
+                            outError);
+                    if (appMetaData == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    parsingPackage.setAppMetaData(appMetaData);
+                    break;
+                case "uses-static-library":
+                    ParseResult parseResult = parseUsesStaticLibrary(parseInput, parsingPackage,
+                            res, parser);
+                    if (!parseResult.isSuccess()) {
+                        return parseResult;
+                    }
+
+                    break;
+                case "uses-library":
+                    sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesLibrary);
+
+                    // Note: don't allow this value to be a reference to a resource
+                    // that may change.
+                    String lname = sa.getNonResourceString(
+                            R.styleable.AndroidManifestUsesLibrary_name);
+                    boolean req = sa.getBoolean(
+                            R.styleable.AndroidManifestUsesLibrary_required, true);
+
+                    sa.recycle();
+
+                    if (lname != null) {
+                        lname = lname.intern();
+                        if (req) {
+                            // Upgrade to treat as stronger constraint
+                            parsingPackage.addUsesLibrary(lname)
+                                    .removeUsesOptionalLibrary(lname);
+                        } else {
+                            // Ignore if someone already defined as required
+                            if (!ArrayUtils.contains(parsingPackage.getUsesLibraries(), lname)) {
+                                parsingPackage.addUsesOptionalLibrary(lname);
+                            }
+                        }
+                    }
+
+                    XmlUtils.skipCurrentTag(parser);
+                    break;
+                case "uses-package":
+                    // Dependencies for app installers; we don't currently try to
+                    // enforce this.
+                    XmlUtils.skipCurrentTag(parser);
+                    break;
+                default:
+                    if (!PackageParser.RIGID_PARSER) {
+                        Slog.w(TAG, "Unknown element under <application>: " + tagName
+                                + " at " + parsingPackage.getBaseCodePath() + " "
+                                + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    } else {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                "Bad element under <application>: " + tagName
+                        );
+                    }
+            }
+
+            if (parsedComponent != null && parsedComponent.getSplitName() == null) {
+                // If the loaded component did not specify a split, inherit the split name
+                // based on the split it is defined in.
+                // This is used to later load the correct split when starting this
+                // component.
+                parsedComponent.setSplitName(parsingPackage.getSplitNames()[splitIndex]);
+            }
+        }
+
+        return parseInput.success(parsingPackage);
+    }
+
+    private static ParseResult parseBaseApkTags(
+            ParseInput parseInput,
+            String[] separateProcesses,
+            PackageParser.Callback callback,
+            ParsingPackage parsingPackage,
+            TypedArray manifestArray,
+            Resources res,
+            XmlResourceParser parser,
+            int flags
+    ) throws XmlPullParserException, IOException {
+        int type;
+        boolean foundApp = false;
+
+        TypedArray sa = manifestArray;
+
+        ParseResult sharedUserResult = parseSharedUser(parseInput, parsingPackage, sa);
+        if (!sharedUserResult.isSuccess()) {
+            return sharedUserResult;
+        }
+
+        parseManifestAttributes(sa, parsingPackage, flags);
+
+        int outerDepth = parser.getDepth();
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+
+            // All methods return a boolean, even if they can't fail. This can be enforced
+            // by making this final and not assigned, forcing the switch to assign success
+            // once in every branch.
+            final boolean success;
+            ParseResult parseResult = null;
+
+            // TODO(b/135203078): Either use all booleans or all ParseResults
+            // TODO(b/135203078): Convert to instance methods to share variables
+            switch (tagName) {
+                case PackageParser.TAG_APPLICATION:
+                    if (foundApp) {
+                        if (PackageParser.RIGID_PARSER) {
+                            return parseInput.error(
+                                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                    "<manifest> has more than one <application>"
+                            );
+                        } else {
+                            Slog.w(TAG, "<manifest> has more than one <application>");
+                            XmlUtils.skipCurrentTag(parser);
+                            success = true;
+                        }
+                    } else {
+                        foundApp = true;
+                        parseResult = parseBaseApplication(parseInput, separateProcesses,
+                                callback,
+                                parsingPackage, res, parser, flags);
+                        success = parseResult.isSuccess();
+                    }
+                    break;
+                case PackageParser.TAG_OVERLAY:
+                    parseResult = parseOverlay(parseInput, parsingPackage, res, parser);
+                    success = parseResult.isSuccess();
+                    break;
+                case PackageParser.TAG_KEY_SETS:
+                    parseResult = parseKeySets(parseInput, parsingPackage, res, parser);
+                    success = parseResult.isSuccess();
+                    break;
+                case PackageParser.TAG_PERMISSION_GROUP:
+                    parseResult = parsePermissionGroup(parseInput, parsingPackage, res,
+                            parser);
+                    success = parseResult.isSuccess();
+                    break;
+                case PackageParser.TAG_PERMISSION:
+                    parseResult = parsePermission(parseInput, parsingPackage, res, parser);
+                    success = parseResult.isSuccess();
+                    break;
+                case PackageParser.TAG_PERMISSION_TREE:
+                    parseResult = parsePermissionTree(parseInput, parsingPackage, res, parser);
+                    success = parseResult.isSuccess();
+                    break;
+                case PackageParser.TAG_USES_PERMISSION:
+                case PackageParser.TAG_USES_PERMISSION_SDK_M:
+                case PackageParser.TAG_USES_PERMISSION_SDK_23:
+                    parseResult = parseUsesPermission(parseInput, parsingPackage, res, parser,
+                            callback);
+                    success = parseResult.isSuccess();
+                    break;
+                case PackageParser.TAG_USES_CONFIGURATION:
+                    success = parseUsesConfiguration(parsingPackage, res, parser);
+                    break;
+                case PackageParser.TAG_USES_FEATURE:
+                    success = parseUsesFeature(parsingPackage, res, parser);
+                    break;
+                case PackageParser.TAG_FEATURE_GROUP:
+                    success = parseFeatureGroup(parsingPackage, res, parser);
+                    break;
+                case PackageParser.TAG_USES_SDK:
+                    parseResult = parseUsesSdk(parseInput, parsingPackage, res, parser);
+                    success = parseResult.isSuccess();
+                    break;
+                case PackageParser.TAG_SUPPORT_SCREENS:
+                    success = parseSupportScreens(parsingPackage, res, parser);
+                    break;
+                case PackageParser.TAG_PROTECTED_BROADCAST:
+                    success = parseProtectedBroadcast(parsingPackage, res, parser);
+                    break;
+                case PackageParser.TAG_INSTRUMENTATION:
+                    parseResult = parseInstrumentation(parseInput, parsingPackage, res,
+                            parser);
+                    success = parseResult.isSuccess();
+                    break;
+                case PackageParser.TAG_ORIGINAL_PACKAGE:
+                    success = parseOriginalPackage(parsingPackage, res, parser);
+                    break;
+                case PackageParser.TAG_ADOPT_PERMISSIONS:
+                    success = parseAdoptPermissions(parsingPackage, res, parser);
+                    break;
+                case PackageParser.TAG_USES_GL_TEXTURE:
+                case PackageParser.TAG_COMPATIBLE_SCREENS:
+                case PackageParser.TAG_SUPPORTS_INPUT:
+                case PackageParser.TAG_EAT_COMMENT:
+                    // Just skip this tag
+                    XmlUtils.skipCurrentTag(parser);
+                    success = true;
+                    break;
+                case PackageParser.TAG_RESTRICT_UPDATE:
+                    success = parseRestrictUpdateHash(flags, parsingPackage, res, parser);
+                    break;
+                case PackageParser.TAG_QUERIES:
+                    parseResult = parseQueries(parseInput, parsingPackage, res, parser);
+                    success = parseResult.isSuccess();
+                    break;
+                default:
+                    parseResult = parseUnknownTag(parseInput, parsingPackage, parser);
+                    success = parseResult.isSuccess();
+                    break;
+            }
+
+            if (parseResult != null && !parseResult.isSuccess()) {
+                return parseResult;
+            }
+
+            if (!success) {
+                return parseResult;
+            }
+        }
+
+        if (!foundApp && ArrayUtils.size(parsingPackage.getInstrumentations()) == 0) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY,
+                    "<manifest> does not contain an <application> or <instrumentation>"
+            );
+        }
+
+        convertNewPermissions(parsingPackage);
+
+        convertSplitPermissions(parsingPackage);
+
+        // At this point we can check if an application is not supporting densities and hence
+        // cannot be windowed / resized. Note that an SDK version of 0 is common for
+        // pre-Doughnut applications.
+        if (parsingPackage.usesCompatibilityMode()) {
+            adjustPackageToBeUnresizeableAndUnpipable(parsingPackage);
+        }
+
+        return parseInput.success(parsingPackage);
+    }
+
+    private static ParseResult parseUnknownTag(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+        if (PackageParser.RIGID_PARSER) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "Bad element under <manifest>: " + parser.getName()
+            );
+        } else {
+            Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
+                    + " at " + parsingPackage.getBaseCodePath() + " "
+                    + parser.getPositionDescription());
+            XmlUtils.skipCurrentTag(parser);
+            return parseInput.success(parsingPackage);
+        }
+    }
+
+    private static ParseResult parseSharedUser(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            TypedArray manifestArray
+    ) {
+        String str = manifestArray.getNonConfigurationString(
+                R.styleable.AndroidManifest_sharedUserId, 0);
+        if (TextUtils.isEmpty(str)) {
+            return parseInput.success(parsingPackage);
+        }
+
+        String nameError = validateName(str, true, true);
+        if (nameError != null && !"android".equals(parsingPackage.getPackageName())) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID,
+                    "<manifest> specifies bad sharedUserId name \"" + str + "\": "
+                            + nameError
+            );
+        }
+
+        int sharedUserLabel = manifestArray.getResourceId(
+                R.styleable.AndroidManifest_sharedUserLabel, 0);
+        parsingPackage.setSharedUserId(str.intern())
+                .setSharedUserLabel(sharedUserLabel);
+
+        return parseInput.success(parsingPackage);
+    }
+
+    private static void parseManifestAttributes(
+            TypedArray manifestArray,
+            ParsingPackage parsingPackage,
+            int flags
+    ) {
+        int installLocation = manifestArray.getInteger(R.styleable.AndroidManifest_installLocation,
+                PackageParser.PARSE_DEFAULT_INSTALL_LOCATION);
+
+        final int targetSandboxVersion = manifestArray.getInteger(
+                R.styleable.AndroidManifest_targetSandboxVersion,
+                PackageParser.PARSE_DEFAULT_TARGET_SANDBOX);
+
+        parsingPackage.setInstallLocation(installLocation)
+                .setTargetSandboxVersion(targetSandboxVersion);
+
+        /* Set the global "on SD card" flag */
+        parsingPackage.setExternalStorage((flags & PackageParser.PARSE_EXTERNAL_STORAGE) != 0);
+
+        parsingPackage.setIsolatedSplitLoading(manifestArray.getBoolean(
+                R.styleable.AndroidManifest_isolatedSplits, false));
+    }
+
+    private static ParseResult parseKeySets(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws XmlPullParserException, IOException {
+        // we've encountered the 'key-sets' tag
+        // all the keys and keysets that we want must be defined here
+        // so we're going to iterate over the parser and pull out the things we want
+        int outerDepth = parser.getDepth();
+        int currentKeySetDepth = -1;
+        int type;
+        String currentKeySet = null;
+        ArrayMap<String, PublicKey> publicKeys = new ArrayMap<>();
+        ArraySet<String> upgradeKeySets = new ArraySet<>();
+        ArrayMap<String, ArraySet<String>> definedKeySets =
+                new ArrayMap<>();
+        ArraySet<String> improperKeySets = new ArraySet<>();
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG) {
+                if (parser.getDepth() == currentKeySetDepth) {
+                    currentKeySet = null;
+                    currentKeySetDepth = -1;
+                }
+                continue;
+            }
+            String tagName = parser.getName();
+            if (tagName.equals("key-set")) {
+                if (currentKeySet != null) {
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            "Improperly nested 'key-set' tag at " + parser.getPositionDescription()
+                    );
+                }
+                final TypedArray sa = res.obtainAttributes(parser,
+                        R.styleable.AndroidManifestKeySet);
+                final String keysetName = sa.getNonResourceString(
+                        R.styleable.AndroidManifestKeySet_name);
+                definedKeySets.put(keysetName, new ArraySet<>());
+                currentKeySet = keysetName;
+                currentKeySetDepth = parser.getDepth();
+                sa.recycle();
+            } else if (tagName.equals("public-key")) {
+                if (currentKeySet == null) {
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            "Improperly nested 'key-set' tag at " + parser.getPositionDescription()
+                    );
+                }
+                final TypedArray sa = res.obtainAttributes(parser,
+                        R.styleable.AndroidManifestPublicKey);
+                final String publicKeyName = sa.getNonResourceString(
+                        R.styleable.AndroidManifestPublicKey_name);
+                final String encodedKey = sa.getNonResourceString(
+                        R.styleable.AndroidManifestPublicKey_value);
+                if (encodedKey == null && publicKeys.get(publicKeyName) == null) {
+                    sa.recycle();
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            "'public-key' " + publicKeyName + " must define a public-key value"
+                                    + " on first use at " + parser.getPositionDescription()
+                    );
+                } else if (encodedKey != null) {
+                    PublicKey currentKey = PackageParser.parsePublicKey(encodedKey);
+                    if (currentKey == null) {
+                        Slog.w(TAG, "No recognized valid key in 'public-key' tag at "
+                                + parser.getPositionDescription() + " key-set " + currentKeySet
+                                + " will not be added to the package's defined key-sets.");
+                        sa.recycle();
+                        improperKeySets.add(currentKeySet);
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    if (publicKeys.get(publicKeyName) == null
+                            || publicKeys.get(publicKeyName).equals(currentKey)) {
+
+                        /* public-key first definition, or matches old definition */
+                        publicKeys.put(publicKeyName, currentKey);
+                    } else {
+                        sa.recycle();
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                "Value of 'public-key' " + publicKeyName
+                                        + " conflicts with previously defined value at "
+                                        + parser.getPositionDescription()
+                        );
+                    }
+                }
+                definedKeySets.get(currentKeySet).add(publicKeyName);
+                sa.recycle();
+                XmlUtils.skipCurrentTag(parser);
+            } else if (tagName.equals("upgrade-key-set")) {
+                final TypedArray sa = res.obtainAttributes(parser,
+                        R.styleable.AndroidManifestUpgradeKeySet);
+                String name = sa.getNonResourceString(
+                        R.styleable.AndroidManifestUpgradeKeySet_name);
+                upgradeKeySets.add(name);
+                sa.recycle();
+                XmlUtils.skipCurrentTag(parser);
+            } else if (PackageParser.RIGID_PARSER) {
+                return parseInput.error(
+                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                        "Bad element under <key-sets>: " + parser.getName()
+                                + " at " + parsingPackage.getBaseCodePath() + " "
+                                + parser.getPositionDescription()
+                );
+            } else {
+                Slog.w(TAG, "Unknown element under <key-sets>: " + parser.getName()
+                        + " at " + parsingPackage.getBaseCodePath() + " "
+                        + parser.getPositionDescription());
+                XmlUtils.skipCurrentTag(parser);
+                continue;
+            }
+        }
+        String packageName = parsingPackage.getPackageName();
+        Set<String> publicKeyNames = publicKeys.keySet();
+        if (publicKeyNames.removeAll(definedKeySets.keySet())) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "Package" + packageName + " AndroidManifest.xml "
+                            + "'key-set' and 'public-key' names must be distinct."
+            );
+        }
+
+        for (ArrayMap.Entry<String, ArraySet<String>> e : definedKeySets.entrySet()) {
+            final String keySetName = e.getKey();
+            if (e.getValue().size() == 0) {
+                Slog.w(TAG, "Package" + packageName + " AndroidManifest.xml "
+                        + "'key-set' " + keySetName + " has no valid associated 'public-key'."
+                        + " Not including in package's defined key-sets.");
+                continue;
+            } else if (improperKeySets.contains(keySetName)) {
+                Slog.w(TAG, "Package" + packageName + " AndroidManifest.xml "
+                        + "'key-set' " + keySetName + " contained improper 'public-key'"
+                        + " tags. Not including in package's defined key-sets.");
+                continue;
+            }
+
+            for (String s : e.getValue()) {
+                parsingPackage.addKeySet(keySetName, publicKeys.get(s));
+            }
+        }
+        if (parsingPackage.getKeySetMapping().keySet().containsAll(upgradeKeySets)) {
+            parsingPackage.setUpgradeKeySets(upgradeKeySets);
+        } else {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "Package" + packageName + " AndroidManifest.xml "
+                            + "does not define all 'upgrade-key-set's ."
+            );
+        }
+
+        return parseInput.success(parsingPackage);
+    }
+
+    public static boolean parsePackageItemInfo(String packageName, PackageItemInfo outInfo,
+            String[] outError, String tag, TypedArray sa, boolean nameRequired,
+            int nameRes, int labelRes, int iconRes, int roundIconRes, int logoRes, int bannerRes) {
+        // This case can only happen in unit tests where we sometimes need to create fakes
+        // of various package parser data structures.
+        if (sa == null) {
+            outError[0] = tag + " does not contain any attributes";
+            return false;
+        }
+
+        String name = sa.getNonConfigurationString(nameRes, 0);
+        if (name == null) {
+            if (nameRequired) {
+                outError[0] = tag + " does not specify android:name";
+                return false;
+            }
+        } else {
+            String outInfoName = buildClassName(packageName, name);
+            if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(outInfoName)) {
+                outError[0] = tag + " invalid android:name";
+                return false;
+            }
+            outInfo.name = outInfoName;
+            if (outInfoName == null) {
+                return false;
+            }
+        }
+
+        int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0;
+        if (roundIconVal != 0) {
+            outInfo.icon = roundIconVal;
+            outInfo.nonLocalizedLabel = null;
+        } else {
+            int iconVal = sa.getResourceId(iconRes, 0);
+            if (iconVal != 0) {
+                outInfo.icon = iconVal;
+                outInfo.nonLocalizedLabel = null;
+            }
+        }
+
+        int logoVal = sa.getResourceId(logoRes, 0);
+        if (logoVal != 0) {
+            outInfo.logo = logoVal;
+        }
+
+        int bannerVal = sa.getResourceId(bannerRes, 0);
+        if (bannerVal != 0) {
+            outInfo.banner = bannerVal;
+        }
+
+        TypedValue v = sa.peekValue(labelRes);
+        if (v != null && (outInfo.labelRes = v.resourceId) == 0) {
+            outInfo.nonLocalizedLabel = v.coerceToString();
+        }
+
+        outInfo.packageName = packageName;
+
+        return true;
+    }
+
+    private static ParseResult parsePackageItemInfo(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            String tag,
+            TypedArray sa,
+            boolean nameRequired,
+            int nameRes,
+            int labelRes,
+            int iconRes,
+            int roundIconRes,
+            int logoRes,
+            int bannerRes
+    ) {
+        // This case can only happen in unit tests where we sometimes need to create fakes
+        // of various package parser data structures.
+        if (sa == null) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    tag + " does not contain any attributes"
+            );
+        }
+
+        String name = sa.getNonConfigurationString(nameRes, 0);
+        if (name == null) {
+            if (nameRequired) {
+                return parseInput.error(
+                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                        tag + " does not specify android:name"
+                );
+            }
+        } else {
+            String packageName = parsingPackage.getPackageName();
+            String outInfoName = buildClassName(packageName, name);
+            if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(outInfoName)) {
+                return parseInput.error(
+                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                        tag + " invalid android:name"
+                );
+            } else if (outInfoName == null) {
+                return parseInput.error(
+                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                        "Empty class name in package " + packageName
+                );
+            }
+
+            parsingPackage.setName(outInfoName);
+        }
+
+        int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0;
+        if (roundIconVal != 0) {
+            parsingPackage.setIcon(roundIconVal)
+                    .setNonLocalizedLabel(null);
+        } else {
+            int iconVal = sa.getResourceId(iconRes, 0);
+            if (iconVal != 0) {
+                parsingPackage.setIcon(iconVal)
+                        .setNonLocalizedLabel(null);
+            }
+        }
+
+        int logoVal = sa.getResourceId(logoRes, 0);
+        if (logoVal != 0) {
+            parsingPackage.setLogo(logoVal);
+        }
+
+        int bannerVal = sa.getResourceId(bannerRes, 0);
+        if (bannerVal != 0) {
+            parsingPackage.setBanner(bannerVal);
+        }
+
+        TypedValue v = sa.peekValue(labelRes);
+        if (v != null) {
+            parsingPackage.setLabelRes(v.resourceId);
+            if (v.resourceId == 0) {
+                parsingPackage.setNonLocalizedLabel(v.coerceToString());
+            }
+        }
+
+        return parseInput.success(parsingPackage);
+    }
+
+    private static ParseResult parsePermissionGroup(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws XmlPullParserException, IOException {
+        // TODO(b/135203078): Remove, replace with ParseResult
+        String[] outError = new String[1];
+
+        ComponentParseUtils.ParsedPermissionGroup parsedPermissionGroup =
+                ComponentParseUtils.parsePermissionGroup(parsingPackage,
+                        res, parser, outError);
+
+        if (parsedPermissionGroup == null || outError[0] != null) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    outError[0]
+            );
+        }
+
+        parsingPackage.addPermissionGroup(parsedPermissionGroup);
+
+        return parseInput.success(parsingPackage);
+    }
+
+    private static ParseResult parsePermission(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws XmlPullParserException, IOException {
+        // TODO(b/135203078): Remove, replace with ParseResult
+        String[] outError = new String[1];
+
+        ComponentParseUtils.ParsedPermission parsedPermission =
+                ComponentParseUtils.parsePermission(parsingPackage,
+                        res, parser, outError);
+
+        if (parsedPermission == null || outError[0] != null) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    outError[0]
+            );
+        }
+
+        parsingPackage.addPermission(parsedPermission);
+
+        return parseInput.success(parsingPackage);
+    }
+
+    private static ParseResult parsePermissionTree(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws XmlPullParserException, IOException {
+        // TODO(b/135203078): Remove, replace with ParseResult
+        String[] outError = new String[1];
+
+        ComponentParseUtils.ParsedPermission parsedPermission =
+                ComponentParseUtils.parsePermissionTree(parsingPackage,
+                        res, parser, outError);
+
+        if (parsedPermission == null || outError[0] != null) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    outError[0]
+            );
+        }
+
+        parsingPackage.addPermission(parsedPermission);
+
+        return parseInput.success(parsingPackage);
+    }
+
+    private static ParseResult parseUsesPermission(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser,
+            PackageParser.Callback callback
+    )
+            throws XmlPullParserException, IOException {
+        TypedArray sa = res.obtainAttributes(parser,
+                R.styleable.AndroidManifestUsesPermission);
+
+        // Note: don't allow this value to be a reference to a resource
+        // that may change.
+        String name = sa.getNonResourceString(
+                R.styleable.AndroidManifestUsesPermission_name);
+
+        int maxSdkVersion = 0;
+        TypedValue val = sa.peekValue(
+                R.styleable.AndroidManifestUsesPermission_maxSdkVersion);
+        if (val != null) {
+            if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) {
+                maxSdkVersion = val.data;
+            }
+        }
+
+        final String requiredFeature = sa.getNonConfigurationString(
+                R.styleable.AndroidManifestUsesPermission_requiredFeature, 0);
+
+        final String requiredNotfeature = sa.getNonConfigurationString(
+                R.styleable.AndroidManifestUsesPermission_requiredNotFeature,
+                0);
+
+        sa.recycle();
+
+        XmlUtils.skipCurrentTag(parser);
+
+        // Can only succeed from here on out
+        ParseResult success = parseInput.success(parsingPackage);
+
+        if (name == null) {
+            return success;
+        }
+
+        if ((maxSdkVersion != 0) && (maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT)) {
+            return success;
+        }
+
+        // Only allow requesting this permission if the platform supports the given feature.
+        if (requiredFeature != null && callback != null && !callback.hasFeature(requiredFeature)) {
+            return success;
+        }
+
+        // Only allow requesting this permission if the platform doesn't support the given feature.
+        if (requiredNotfeature != null && callback != null
+                && callback.hasFeature(requiredNotfeature)) {
+            return success;
+        }
+
+        if (!parsingPackage.getRequestedPermissions().contains(name)) {
+            parsingPackage.addRequestedPermission(name.intern());
+        } else {
+            Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
+                    + name + " in package: " + parsingPackage.getPackageName() + " at: "
+                    + parser.getPositionDescription());
+        }
+
+        return success;
+    }
+
+    private static boolean parseUsesConfiguration(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+        ConfigurationInfo cPref = new ConfigurationInfo();
+        TypedArray sa = res.obtainAttributes(parser,
+                R.styleable.AndroidManifestUsesConfiguration);
+        cPref.reqTouchScreen = sa.getInt(
+                R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen,
+                Configuration.TOUCHSCREEN_UNDEFINED);
+        cPref.reqKeyboardType = sa.getInt(
+                R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType,
+                Configuration.KEYBOARD_UNDEFINED);
+        if (sa.getBoolean(
+                R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard,
+                false)) {
+            cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
+        }
+        cPref.reqNavigation = sa.getInt(
+                R.styleable.AndroidManifestUsesConfiguration_reqNavigation,
+                Configuration.NAVIGATION_UNDEFINED);
+        if (sa.getBoolean(
+                R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav,
+                false)) {
+            cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
+        }
+        sa.recycle();
+        parsingPackage.addConfigPreference(cPref);
+
+        XmlUtils.skipCurrentTag(parser);
+        return true;
+    }
+
+    private static boolean parseUsesFeature(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+        FeatureInfo fi = parseFeatureInfo(res, parser);
+        parsingPackage.addReqFeature(fi);
+
+        if (fi.name == null) {
+            ConfigurationInfo cPref = new ConfigurationInfo();
+            cPref.reqGlEsVersion = fi.reqGlEsVersion;
+            parsingPackage.addConfigPreference(cPref);
+        }
+
+        XmlUtils.skipCurrentTag(parser);
+        return true;
+    }
+
+    private static FeatureInfo parseFeatureInfo(Resources res, AttributeSet attrs) {
+        FeatureInfo fi = new FeatureInfo();
+        TypedArray sa = res.obtainAttributes(attrs,
+                R.styleable.AndroidManifestUsesFeature);
+        // Note: don't allow this value to be a reference to a resource
+        // that may change.
+        fi.name = sa.getNonResourceString(R.styleable.AndroidManifestUsesFeature_name);
+        fi.version = sa.getInt(R.styleable.AndroidManifestUsesFeature_version, 0);
+        if (fi.name == null) {
+            fi.reqGlEsVersion = sa.getInt(R.styleable.AndroidManifestUsesFeature_glEsVersion,
+                    FeatureInfo.GL_ES_VERSION_UNDEFINED);
+        }
+        if (sa.getBoolean(R.styleable.AndroidManifestUsesFeature_required, true)) {
+            fi.flags |= FeatureInfo.FLAG_REQUIRED;
+        }
+        sa.recycle();
+        return fi;
+    }
+
+    private static boolean parseFeatureGroup(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+        FeatureGroupInfo group = new FeatureGroupInfo();
+        ArrayList<FeatureInfo> features = null;
+        final int innerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > innerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            final String innerTagName = parser.getName();
+            if (innerTagName.equals("uses-feature")) {
+                FeatureInfo featureInfo = parseFeatureInfo(res, parser);
+                // FeatureGroups are stricter and mandate that
+                // any <uses-feature> declared are mandatory.
+                featureInfo.flags |= FeatureInfo.FLAG_REQUIRED;
+                features = ArrayUtils.add(features, featureInfo);
+            } else {
+                Slog.w(TAG,
+                        "Unknown element under <feature-group>: " + innerTagName +
+                                " at " + parsingPackage.getBaseCodePath() + " " +
+                                parser.getPositionDescription());
+            }
+            XmlUtils.skipCurrentTag(parser);
+        }
+
+        if (features != null) {
+            group.features = new FeatureInfo[features.size()];
+            group.features = features.toArray(group.features);
+        }
+
+        parsingPackage.addFeatureGroup(group);
+        return true;
+    }
+
+    private static ParseResult parseUsesSdk(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+        if (PackageParser.SDK_VERSION > 0) {
+            TypedArray sa = res.obtainAttributes(parser,
+                    R.styleable.AndroidManifestUsesSdk);
+
+            int minVers = 1;
+            String minCode = null;
+            int targetVers = 0;
+            String targetCode = null;
+
+            TypedValue val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_minSdkVersion);
+            if (val != null) {
+                if (val.type == TypedValue.TYPE_STRING && val.string != null) {
+                    minCode = val.string.toString();
+                } else {
+                    // If it's not a string, it's an integer.
+                    minVers = val.data;
+                }
+            }
+
+            val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
+            if (val != null) {
+                if (val.type == TypedValue.TYPE_STRING && val.string != null) {
+                    targetCode = val.string.toString();
+                    if (minCode == null) {
+                        minCode = targetCode;
+                    }
+                } else {
+                    // If it's not a string, it's an integer.
+                    targetVers = val.data;
+                }
+            } else {
+                targetVers = minVers;
+                targetCode = minCode;
+            }
+
+            sa.recycle();
+
+            // TODO(b/135203078): Remove, replace with ParseResult
+            String[] outError = new String[1];
+            final int minSdkVersion = PackageParser.computeMinSdkVersion(minVers,
+                    minCode,
+                    PackageParser.SDK_VERSION, PackageParser.SDK_CODENAMES, outError);
+            if (minSdkVersion < 0) {
+                return parseInput.error(
+                        PackageManager.INSTALL_FAILED_OLDER_SDK
+                );
+            }
+
+            final int targetSdkVersion = PackageParser.computeTargetSdkVersion(
+                    targetVers,
+                    targetCode, PackageParser.SDK_CODENAMES, outError);
+            if (targetSdkVersion < 0) {
+                return parseInput.error(
+                        PackageManager.INSTALL_FAILED_OLDER_SDK
+                );
+            }
+
+            parsingPackage.setMinSdkVersion(minSdkVersion)
+                    .setTargetSdkVersion(targetSdkVersion);
+        }
+
+        XmlUtils.skipCurrentTag(parser);
+        return parseInput.success(parsingPackage);
+    }
+
+    private static boolean parseRestrictUpdateHash(
+            int flags,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+        if ((flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0) {
+            TypedArray sa = res.obtainAttributes(parser,
+                    R.styleable.AndroidManifestRestrictUpdate);
+            final String hash = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestRestrictUpdate_hash,
+                    0);
+            sa.recycle();
+
+            if (hash != null) {
+                final int hashLength = hash.length();
+                final byte[] hashBytes = new byte[hashLength / 2];
+                for (int i = 0; i < hashLength; i += 2) {
+                    hashBytes[i / 2] = (byte) ((Character.digit(hash.charAt(i), 16)
+                            << 4)
+                            + Character.digit(hash.charAt(i + 1), 16));
+                }
+                parsingPackage.setRestrictUpdateHash(hashBytes);
+            } else {
+                parsingPackage.setRestrictUpdateHash(null);
+            }
+        }
+
+        XmlUtils.skipCurrentTag(parser);
+        return true;
+    }
+
+    private static ParseResult parseQueries(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+
+        final int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+            if (parser.getName().equals("intent")) {
+                String[] outError = new String[1];
+                ComponentParseUtils.ParsedQueriesIntentInfo intentInfo =
+                        ComponentParseUtils.parsedParsedQueriesIntentInfo(
+                                parsingPackage, res, parser, outError
+                        );
+                if (intentInfo == null) {
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            outError[0]
+                    );
+                }
+
+                Uri data = null;
+                String dataType = null;
+                String host = "";
+                final int numActions = intentInfo.countActions();
+                final int numSchemes = intentInfo.countDataSchemes();
+                final int numTypes = intentInfo.countDataTypes();
+                final int numHosts = intentInfo.getHosts().length;
+                if ((numSchemes == 0 && numTypes == 0 && numActions == 0)) {
+                    outError[0] = "intent tags must contain either an action or data.";
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            outError[0]
+                    );
+                }
+                if (numActions > 1) {
+                    outError[0] = "intent tag may have at most one action.";
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            outError[0]
+                    );
+                }
+                if (numTypes > 1) {
+                    outError[0] = "intent tag may have at most one data type.";
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            outError[0]
+                    );
+                }
+                if (numSchemes > 1) {
+                    outError[0] = "intent tag may have at most one data scheme.";
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            outError[0]
+                    );
+                }
+                if (numHosts > 1) {
+                    outError[0] = "intent tag may have at most one data host.";
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            outError[0]
+                    );
+                }
+                Intent intent = new Intent();
+                for (int i = 0, max = intentInfo.countCategories(); i < max; i++) {
+                    intent.addCategory(intentInfo.getCategory(i));
+                }
+                if (numHosts == 1) {
+                    host = intentInfo.getHosts()[0];
+                }
+                if (numSchemes == 1) {
+                    data = new Uri.Builder()
+                            .scheme(intentInfo.getDataScheme(0))
+                            .authority(host)
+                            .build();
+                }
+                if (numTypes == 1) {
+                    dataType = intentInfo.getDataType(0);
+                }
+                intent.setDataAndType(data, dataType);
+                if (numActions == 1) {
+                    intent.setAction(intentInfo.getAction(0));
+                }
+                parsingPackage.addQueriesIntent(intent);
+            } else if (parser.getName().equals("package")) {
+                final TypedArray sa = res.obtainAttributes(parser,
+                        R.styleable.AndroidManifestQueriesPackage);
+                final String packageName =
+                        sa.getString(R.styleable.AndroidManifestQueriesPackage_name);
+                if (TextUtils.isEmpty(packageName)) {
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            "Package name is missing from package tag."
+                    );
+                }
+                parsingPackage.addQueriesPackage(packageName.intern());
+            }
+        }
+        return parseInput.success(parsingPackage);
+    }
+
+    /**
+     * Parse the {@code application} XML tree at the current parse location in a
+     * <em>base APK</em> manifest.
+     * <p>
+     * When adding new features, carefully consider if they should also be
+     * supported by split APKs.
+     *
+     * @hide
+     */
+    public static ParseResult parseBaseApplication(
+            ParseInput parseInput,
+            String[] separateProcesses,
+            PackageParser.Callback callback,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser,
+            int flags
+    ) throws XmlPullParserException, IOException {
+        final String pkgName = parsingPackage.getPackageName();
+
+        // TODO(b/135203078): Remove, replace with ParseResult
+        String[] outError = new String[1];
+        TypedArray sa = null;
+
+        try {
+            sa = res.obtainAttributes(parser,
+                    R.styleable.AndroidManifestApplication);
+
+
+            parsingPackage
+                    .setIconRes(
+                            sa.getResourceId(R.styleable.AndroidManifestApplication_icon, 0))
+                    .setRoundIconRes(
+                            sa.getResourceId(R.styleable.AndroidManifestApplication_roundIcon, 0));
+
+            ParseResult result = parsePackageItemInfo(
+                    parseInput,
+                    parsingPackage,
+                    "<application>",
+                    sa, false /*nameRequired*/,
+                    R.styleable.AndroidManifestApplication_name,
+                    R.styleable.AndroidManifestApplication_label,
+                    R.styleable.AndroidManifestApplication_icon,
+                    R.styleable.AndroidManifestApplication_roundIcon,
+                    R.styleable.AndroidManifestApplication_logo,
+                    R.styleable.AndroidManifestApplication_banner
+            );
+            if (!result.isSuccess()) {
+                return result;
+            }
+
+            String name = parsingPackage.getName();
+            if (name != null) {
+                parsingPackage.setClassName(name);
+            }
+
+            String manageSpaceActivity = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestApplication_manageSpaceActivity,
+                    Configuration.NATIVE_CONFIG_VERSION);
+            if (manageSpaceActivity != null) {
+                String manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity);
+
+                if (manageSpaceActivityName == null) {
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            "Empty class name in package " + pkgName
+                    );
+                }
+
+                parsingPackage.setManageSpaceActivityName(manageSpaceActivityName);
+            }
+
+            boolean allowBackup = sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_allowBackup, true);
+            parsingPackage.setAllowBackup(allowBackup);
+
+            if (allowBackup) {
+                // backupAgent, killAfterRestore, fullBackupContent, backupInForeground,
+                // and restoreAnyVersion are only relevant if backup is possible for the
+                // given application.
+                String backupAgent = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestApplication_backupAgent,
+                        Configuration.NATIVE_CONFIG_VERSION);
+                if (backupAgent != null) {
+                    String backupAgentName = buildClassName(pkgName, backupAgent);
+                    if (backupAgentName == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                "Empty class name in package " + pkgName
+                        );
+                    }
+
+                    if (PackageParser.DEBUG_BACKUP) {
+                        Slog.v(TAG, "android:backupAgent = " + backupAgentName
+                                + " from " + pkgName + "+" + backupAgent);
+                    }
+
+                    parsingPackage.setBackupAgentName(backupAgentName);
+
+                    parsingPackage.setKillAfterRestore(sa.getBoolean(
+                            R.styleable.AndroidManifestApplication_killAfterRestore, true));
+
+                    parsingPackage.setRestoreAnyVersion(sa.getBoolean(
+                            R.styleable.AndroidManifestApplication_restoreAnyVersion, false));
+
+                    parsingPackage.setFullBackupOnly(sa.getBoolean(
+                            R.styleable.AndroidManifestApplication_fullBackupOnly, false));
+
+                    parsingPackage.setBackupInForeground(sa.getBoolean(
+                            R.styleable.AndroidManifestApplication_backupInForeground,
+                            false));
+                }
+
+                TypedValue v = sa.peekValue(
+                        R.styleable.AndroidManifestApplication_fullBackupContent);
+                int fullBackupContent = 0;
+
+                if (v != null) {
+                    fullBackupContent = v.resourceId;
+
+                    if (v.resourceId == 0) {
+                        if (PackageParser.DEBUG_BACKUP) {
+                            Slog.v(TAG, "fullBackupContent specified as boolean=" +
+                                    (v.data == 0 ? "false" : "true"));
+                        }
+                        // "false" => -1, "true" => 0
+                        fullBackupContent = v.data == 0 ? -1 : 0;
+                    }
+
+                    parsingPackage.setFullBackupContent(fullBackupContent);
+                }
+                if (PackageParser.DEBUG_BACKUP) {
+                    Slog.v(TAG, "fullBackupContent=" + fullBackupContent + " for " + pkgName);
+                }
+            }
+
+            parsingPackage
+                    .setTheme(
+                            sa.getResourceId(R.styleable.AndroidManifestApplication_theme, 0))
+                    .setDescriptionRes(
+                            sa.getResourceId(R.styleable.AndroidManifestApplication_description,
+                                    0));
+
+            if (sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_persistent,
+                    false)) {
+                // Check if persistence is based on a feature being present
+                final String requiredFeature = sa.getNonResourceString(R.styleable
+                        .AndroidManifestApplication_persistentWhenFeatureAvailable);
+                parsingPackage.setPersistent(requiredFeature == null
+                        || callback.hasFeature(requiredFeature));
+            }
+
+            boolean requiredForAllUsers = sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_requiredForAllUsers,
+                    false);
+            parsingPackage.setRequiredForAllUsers(requiredForAllUsers);
+
+            String restrictedAccountType = sa.getString(R.styleable
+                    .AndroidManifestApplication_restrictedAccountType);
+            if (restrictedAccountType != null && restrictedAccountType.length() > 0) {
+                parsingPackage.setRestrictedAccountType(restrictedAccountType);
+            }
+
+            String requiredAccountType = sa.getString(R.styleable
+                    .AndroidManifestApplication_requiredAccountType);
+            if (requiredAccountType != null && requiredAccountType.length() > 0) {
+                parsingPackage.setRequiredAccountType(requiredAccountType);
+            }
+
+            parsingPackage.setForceQueryable(
+                    sa.getBoolean(R.styleable.AndroidManifestApplication_forceQueryable, false)
+            );
+
+            boolean debuggable = sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_debuggable,
+                    false
+            );
+
+            parsingPackage.setDebuggable(debuggable);
+
+            if (debuggable) {
+                // Debuggable implies profileable
+                parsingPackage.setProfileableByShell(true);
+            }
+
+            parsingPackage.setVmSafeMode(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_vmSafeMode, false));
+
+            boolean baseHardwareAccelerated = sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_hardwareAccelerated,
+                    parsingPackage.getTargetSdkVersion()
+                            >= Build.VERSION_CODES.ICE_CREAM_SANDWICH);
+            parsingPackage.setBaseHardwareAccelerated(baseHardwareAccelerated);
+
+            parsingPackage.setHasCode(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_hasCode, true));
+
+            parsingPackage.setAllowTaskReparenting(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_allowTaskReparenting, false));
+
+            parsingPackage.setAllowClearUserData(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_allowClearUserData, true));
+
+            parsingPackage.setTestOnly(sa.getBoolean(
+                    com.android.internal.R.styleable.AndroidManifestApplication_testOnly,
+                    false));
+
+            parsingPackage.setLargeHeap(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_largeHeap, false));
+
+            parsingPackage.setUsesCleartextTraffic(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_usesCleartextTraffic,
+                    parsingPackage.getTargetSdkVersion() < Build.VERSION_CODES.P));
+
+            parsingPackage.setSupportsRtl(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_supportsRtl,
+                    false /* default is no RTL support*/));
+
+            parsingPackage.setMultiArch(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_multiArch, false));
+
+            parsingPackage.setExtractNativeLibs(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_extractNativeLibs, true));
+
+            parsingPackage.setUseEmbeddedDex(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_useEmbeddedDex, false));
+
+            parsingPackage.setDefaultToDeviceProtectedStorage(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage,
+                    false));
+
+            parsingPackage.setDirectBootAware(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_directBootAware, false));
+
+            if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) {
+                parsingPackage.setActivitiesResizeModeResizeable(sa.getBoolean(
+                        R.styleable.AndroidManifestApplication_resizeableActivity, true));
+            } else {
+                parsingPackage.setActivitiesResizeModeResizeableViaSdkVersion(
+                        parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.N);
+            }
+
+            parsingPackage.setAllowClearUserDataOnFailedRestore(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_allowClearUserDataOnFailedRestore,
+                    true));
+
+
+            parsingPackage.setAllowAudioPlaybackCapture(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture,
+                    parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.Q));
+
+            parsingPackage.setRequestLegacyExternalStorage(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_requestLegacyExternalStorage,
+                    parsingPackage.getTargetSdkVersion() < Build.VERSION_CODES.Q));
+
+            parsingPackage
+                    .setMaxAspectRatio(
+                            sa.getFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, 0))
+                    .setMinAspectRatio(
+                            sa.getFloat(R.styleable.AndroidManifestApplication_minAspectRatio, 0))
+                    .setNetworkSecurityConfigRes(sa.getResourceId(
+                            R.styleable.AndroidManifestApplication_networkSecurityConfig, 0))
+                    .setCategory(sa.getInt(R.styleable.AndroidManifestApplication_appCategory,
+                            ApplicationInfo.CATEGORY_UNDEFINED));
+
+            String str;
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestApplication_permission, 0);
+            parsingPackage.setPermission((str != null && str.length() > 0) ? str.intern() : null);
+
+            if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
+                str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestApplication_taskAffinity,
+                        Configuration.NATIVE_CONFIG_VERSION);
+            } else {
+                // Some older apps have been seen to use a resource reference
+                // here that on older builds was ignored (with a warning).  We
+                // need to continue to do this for them so they don't break.
+                str = sa.getNonResourceString(
+                        R.styleable.AndroidManifestApplication_taskAffinity);
+            }
+            String packageName = parsingPackage.getPackageName();
+            String taskAffinity = PackageParser.buildTaskAffinityName(packageName,
+                    packageName,
+                    str, outError);
+
+            if (outError[0] != null) {
+                return parseInput.error(
+                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                        outError[0]
+                );
+            }
+
+            parsingPackage.setTaskAffinity(taskAffinity);
+            String factory = sa.getNonResourceString(
+                    R.styleable.AndroidManifestApplication_appComponentFactory);
+            if (factory != null) {
+                String appComponentFactory = buildClassName(packageName, factory);
+                if (appComponentFactory == null) {
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            "Empty class name in package " + pkgName
+                    );
+                }
+
+                parsingPackage.setAppComponentFactory(appComponentFactory);
+            }
+
+            parsingPackage.setUsesNonSdkApi(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_usesNonSdkApi, false));
+
+            parsingPackage.setHasFragileUserData(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_hasFragileUserData, false));
+
+            CharSequence pname;
+            if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
+                pname = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestApplication_process,
+                        Configuration.NATIVE_CONFIG_VERSION);
+            } else {
+                // Some older apps have been seen to use a resource reference
+                // here that on older builds was ignored (with a warning).  We
+                // need to continue to do this for them so they don't break.
+                pname = sa.getNonResourceString(
+                        R.styleable.AndroidManifestApplication_process);
+            }
+            String processName = PackageParser.buildProcessName(packageName, null, pname, flags,
+                    separateProcesses, outError);
+
+            if (outError[0] != null) {
+                return parseInput.error(
+                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                        outError[0]
+                );
+            }
+
+            parsingPackage
+                    .setProcessName(processName)
+                    .setEnabled(
+                            sa.getBoolean(R.styleable.AndroidManifestApplication_enabled,
+                                    true));
+
+            parsingPackage.setIsGame(sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_isGame, false));
+
+            boolean cantSaveState = sa.getBoolean(
+                    R.styleable.AndroidManifestApplication_cantSaveState, false);
+            parsingPackage.setCantSaveState(cantSaveState);
+            if (cantSaveState) {
+                // A heavy-weight application can not be in a custom process.
+                // We can do direct compare because we intern all strings.
+                if (processName != null && !processName.equals(packageName)) {
+                    return parseInput.error(
+                            PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                            "cantSaveState applications can not use custom processes"
+                    );
+                }
+            }
+
+            String classLoaderName = sa.getString(
+                    R.styleable.AndroidManifestApplication_classLoader);
+            parsingPackage
+                    .setUiOptions(sa.getInt(R.styleable.AndroidManifestApplication_uiOptions, 0))
+                    .setClassLoaderName(classLoaderName)
+                    .setZygotePreloadName(
+                            sa.getString(R.styleable.AndroidManifestApplication_zygotePreloadName));
+
+            if (classLoaderName != null
+                    && !ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) {
+                return parseInput.error(
+                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                        "Invalid class loader name: " + classLoaderName
+                );
+            }
+        } finally {
+            if (sa != null) {
+                sa.recycle();
+            }
+        }
+
+        final int innerDepth = parser.getDepth();
+        int type;
+        boolean hasActivityOrder = false;
+        boolean hasReceiverOrder = false;
+        boolean hasServiceOrder = false;
+
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+            switch (tagName) {
+                case "activity":
+                    ComponentParseUtils.ParsedActivity activity =
+                            ComponentParseUtils.parseActivity(separateProcesses,
+                                    parsingPackage,
+                                    res, parser, flags,
+                                    outError, false,
+                                    parsingPackage.isBaseHardwareAccelerated());
+                    if (activity == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    hasActivityOrder |= (activity.order != 0);
+                    parsingPackage.addActivity(activity);
+                    break;
+                case "receiver":
+                    activity = ComponentParseUtils.parseActivity(separateProcesses,
+                            parsingPackage,
+                            res, parser,
+                            flags, outError,
+                            true, false);
+                    if (activity == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    hasReceiverOrder |= (activity.order != 0);
+                    parsingPackage.addReceiver(activity);
+                    break;
+                case "service":
+                    ComponentParseUtils.ParsedService s = ComponentParseUtils.parseService(
+                            separateProcesses,
+                            parsingPackage,
+                            res, parser, flags,
+                            outError);
+                    if (s == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    hasServiceOrder |= (s.order != 0);
+                    parsingPackage.addService(s);
+                    break;
+                case "provider":
+                    ComponentParseUtils.ParsedProvider p = ComponentParseUtils.parseProvider(
+                            separateProcesses,
+                            parsingPackage,
+                            res, parser, flags,
+                            outError
+                    );
+                    if (p == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    parsingPackage.addProvider(p);
+                    break;
+                case "activity-alias":
+                    activity = ComponentParseUtils.parseActivityAlias(
+                            parsingPackage,
+                            res,
+                            parser,
+                            outError
+                    );
+                    if (activity == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    hasActivityOrder |= (activity.order != 0);
+                    parsingPackage.addActivity(activity);
+                    break;
+                case "meta-data":
+                    // note: application meta-data is stored off to the side, so it can
+                    // remain null in the primary copy (we like to avoid extra copies because
+                    // it can be large)
+                    Bundle appMetaData = parseMetaData(parsingPackage, res, parser,
+                            parsingPackage.getAppMetaData(),
+                            outError);
+                    if (appMetaData == null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                outError[0]
+                        );
+                    }
+
+                    parsingPackage.setAppMetaData(appMetaData);
+                    break;
+                case "static-library":
+                    sa = res.obtainAttributes(parser,
+                            R.styleable.AndroidManifestStaticLibrary);
+
+                    // Note: don't allow this value to be a reference to a resource
+                    // that may change.
+                    String lname = sa.getNonResourceString(
+                            R.styleable.AndroidManifestStaticLibrary_name);
+                    final int version = sa.getInt(
+                            R.styleable.AndroidManifestStaticLibrary_version, -1);
+                    final int versionMajor = sa.getInt(
+                            R.styleable.AndroidManifestStaticLibrary_versionMajor,
+                            0);
+
+                    sa.recycle();
+
+                    // Since the app canot run without a static lib - fail if malformed
+                    if (lname == null || version < 0) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                "Bad static-library declaration name: " + lname
+                                        + " version: " + version
+                        );
+                    }
+
+                    if (parsingPackage.getSharedUserId() != null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID,
+                                "sharedUserId not allowed in static shared library"
+                        );
+                    }
+
+                    if (parsingPackage.getStaticSharedLibName() != null) {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                "Multiple static-shared libs for package " + pkgName
+                        );
+                    }
+
+                    parsingPackage.setStaticSharedLibName(lname.intern());
+                    if (version >= 0) {
+                        parsingPackage.setStaticSharedLibVersion(
+                                PackageInfo.composeLongVersionCode(versionMajor, version));
+                    } else {
+                        parsingPackage.setStaticSharedLibVersion(version);
+                    }
+                    parsingPackage.setStaticSharedLibrary(true);
+
+                    XmlUtils.skipCurrentTag(parser);
+
+                    break;
+                case "library":
+                    sa = res.obtainAttributes(parser,
+                            R.styleable.AndroidManifestLibrary);
+
+                    // Note: don't allow this value to be a reference to a resource
+                    // that may change.
+                    lname = sa.getNonResourceString(
+                            R.styleable.AndroidManifestLibrary_name);
+
+                    sa.recycle();
+
+                    if (lname != null) {
+                        lname = lname.intern();
+                        if (!ArrayUtils.contains(parsingPackage.getLibraryNames(), lname)) {
+                            parsingPackage.addLibraryName(lname);
+                        }
+                    }
+
+                    XmlUtils.skipCurrentTag(parser);
+
+                    break;
+                case "uses-static-library":
+                    ParseResult parseResult = parseUsesStaticLibrary(parseInput, parsingPackage,
+                            res, parser);
+                    if (!parseResult.isSuccess()) {
+                        return parseResult;
+                    }
+                    break;
+                case "uses-library":
+                    sa = res.obtainAttributes(parser,
+                            R.styleable.AndroidManifestUsesLibrary);
+
+                    // Note: don't allow this value to be a reference to a resource
+                    // that may change.
+                    lname = sa.getNonResourceString(
+                            R.styleable.AndroidManifestUsesLibrary_name);
+                    boolean req = sa.getBoolean(
+                            R.styleable.AndroidManifestUsesLibrary_required,
+                            true);
+
+                    sa.recycle();
+
+                    if (lname != null) {
+                        lname = lname.intern();
+                        if (req) {
+                            parsingPackage.addUsesLibrary(lname);
+                        } else {
+                            parsingPackage.addUsesOptionalLibrary(lname);
+                        }
+                    }
+
+                    XmlUtils.skipCurrentTag(parser);
+
+                    break;
+                case "uses-package":
+                    // Dependencies for app installers; we don't currently try to
+                    // enforce this.
+                    XmlUtils.skipCurrentTag(parser);
+                    break;
+                case "profileable":
+                    sa = res.obtainAttributes(parser,
+                            R.styleable.AndroidManifestProfileable);
+                    if (sa.getBoolean(
+                            R.styleable.AndroidManifestProfileable_shell, false)) {
+                        parsingPackage.setProfileableByShell(true);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+
+                default:
+                    if (!PackageParser.RIGID_PARSER) {
+                        Slog.w(TAG, "Unknown element under <application>: " + tagName
+                                + " at " + parsingPackage.getBaseCodePath() + " "
+                                + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    } else {
+                        return parseInput.error(
+                                PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                                "Bad element under <application>: " + tagName
+                        );
+                    }
+            }
+        }
+
+        if (TextUtils.isEmpty(parsingPackage.getStaticSharedLibName())) {
+            // Add a hidden app detail activity to normal apps which forwards user to App Details
+            // page.
+            ComponentParseUtils.ParsedActivity a = generateAppDetailsHiddenActivity(
+                    parsingPackage,
+                    outError
+            );
+            // Ignore errors here
+            parsingPackage.addActivity(a);
+        }
+
+        if (hasActivityOrder) {
+            parsingPackage.sortActivities();
+        }
+        if (hasReceiverOrder) {
+            parsingPackage.sortReceivers();
+        }
+        if (hasServiceOrder) {
+            parsingPackage.sortServices();
+        }
+        // Must be ran after the entire {@link ApplicationInfo} has been fully processed and after
+        // every activity info has had a chance to set it from its attributes.
+        setMaxAspectRatio(parsingPackage);
+        setMinAspectRatio(parsingPackage, callback);
+
+        parsingPackage.setHasDomainUrls(hasDomainURLs(parsingPackage));
+
+        return parseInput.success(parsingPackage);
+    }
+
+    private static ParseResult parseUsesStaticLibrary(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws XmlPullParserException, IOException {
+        TypedArray sa = res.obtainAttributes(parser,
+                R.styleable.AndroidManifestUsesStaticLibrary);
+
+        // Note: don't allow this value to be a reference to a resource that may change.
+        String lname = sa.getNonResourceString(
+                R.styleable.AndroidManifestUsesLibrary_name);
+        final int version = sa.getInt(
+                R.styleable.AndroidManifestUsesStaticLibrary_version, -1);
+        String certSha256Digest = sa.getNonResourceString(com.android.internal.R.styleable
+                .AndroidManifestUsesStaticLibrary_certDigest);
+        sa.recycle();
+
+        // Since an APK providing a static shared lib can only provide the lib - fail if malformed
+        if (lname == null || version < 0 || certSha256Digest == null) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "Bad uses-static-library declaration name: " + lname + " version: "
+                            + version + " certDigest" + certSha256Digest
+            );
+        }
+
+        // Can depend only on one version of the same library
+        List<String> usesStaticLibraries = parsingPackage.getUsesStaticLibraries();
+        if (usesStaticLibraries != null && usesStaticLibraries.contains(lname)) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "Depending on multiple versions of static library " + lname
+            );
+        }
+
+        lname = lname.intern();
+        // We allow ":" delimiters in the SHA declaration as this is the format
+        // emitted by the certtool making it easy for developers to copy/paste.
+        certSha256Digest = certSha256Digest.replace(":", "").toLowerCase();
+
+        // Fot apps targeting O-MR1 we require explicit enumeration of all certs.
+        String[] additionalCertSha256Digests = EmptyArray.STRING;
+        if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.O_MR1) {
+            // TODO(b/135203078): Remove, replace with ParseResult
+            String[] outError = new String[1];
+            additionalCertSha256Digests = parseAdditionalCertificates(res, parser, outError);
+            if (additionalCertSha256Digests == null || outError[0] != null) {
+                return parseInput.error(
+                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                        outError[0]
+                );
+            }
+        } else {
+            XmlUtils.skipCurrentTag(parser);
+        }
+
+        final String[] certSha256Digests = new String[additionalCertSha256Digests.length + 1];
+        certSha256Digests[0] = certSha256Digest;
+        System.arraycopy(additionalCertSha256Digests, 0, certSha256Digests,
+                1, additionalCertSha256Digests.length);
+
+        parsingPackage.addUsesStaticLibrary(lname)
+                .addUsesStaticLibraryVersion(version)
+                .addUsesStaticLibraryCertDigests(certSha256Digests);
+
+        return parseInput.success(parsingPackage);
+    }
+
+    private static String[] parseAdditionalCertificates(
+            Resources resources,
+            XmlResourceParser parser,
+            String[] outError
+    ) throws XmlPullParserException, IOException {
+        String[] certSha256Digests = EmptyArray.STRING;
+
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            final String nodeName = parser.getName();
+            if (nodeName.equals("additional-certificate")) {
+                final TypedArray sa = resources.obtainAttributes(parser, com.android.internal.
+                        R.styleable.AndroidManifestAdditionalCertificate);
+                String certSha256Digest = sa.getNonResourceString(com.android.internal.
+                        R.styleable.AndroidManifestAdditionalCertificate_certDigest);
+                sa.recycle();
+
+                if (TextUtils.isEmpty(certSha256Digest)) {
+                    outError[0] = "Bad additional-certificate declaration with empty"
+                            + " certDigest:" + certSha256Digest;
+                    XmlUtils.skipCurrentTag(parser);
+                    sa.recycle();
+                    return null;
+                }
+
+                // We allow ":" delimiters in the SHA declaration as this is the format
+                // emitted by the certtool making it easy for developers to copy/paste.
+                certSha256Digest = certSha256Digest.replace(":", "").toLowerCase();
+                certSha256Digests = ArrayUtils.appendElement(String.class,
+                        certSha256Digests, certSha256Digest);
+            } else {
+                XmlUtils.skipCurrentTag(parser);
+            }
+        }
+
+        return certSha256Digests;
+    }
+
+    /**
+     * Generate activity object that forwards user to App Details page automatically.
+     * This activity should be invisible to user and user should not know or see it.
+     *
+     * @hide
+     */
+    @NonNull
+    private static ComponentParseUtils.ParsedActivity generateAppDetailsHiddenActivity(
+            ParsingPackage parsingPackage,
+            String[] outError
+    ) {
+        String packageName = parsingPackage.getPackageName();
+        String processName = parsingPackage.getProcessName();
+        boolean hardwareAccelerated = parsingPackage.isBaseHardwareAccelerated();
+        int uiOptions = parsingPackage.getUiOptions();
+
+        // Build custom App Details activity info instead of parsing it from xml
+        ComponentParseUtils.ParsedActivity activity = new ComponentParseUtils.ParsedActivity();
+        activity.setPackageName(packageName);
+
+        activity.theme = android.R.style.Theme_NoDisplay;
+        activity.exported = true;
+        activity.className = PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME;
+        activity.setProcessName(processName, processName);
+        activity.uiOptions = uiOptions;
+        activity.taskAffinity = PackageParser.buildTaskAffinityName(packageName,
+                packageName,
+                ":app_details", outError);
+        activity.enabled = true;
+        activity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+        activity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NONE;
+        activity.maxRecents = ActivityTaskManager.getDefaultAppRecentsLimitStatic();
+        activity.configChanges = PackageParser.getActivityConfigChanges(0, 0);
+        activity.softInputMode = 0;
+        activity.persistableMode = ActivityInfo.PERSIST_NEVER;
+        activity.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
+        activity.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
+        activity.lockTaskLaunchMode = 0;
+        activity.directBootAware = false;
+        activity.rotationAnimation = ROTATION_ANIMATION_UNSPECIFIED;
+        activity.colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
+        if (hardwareAccelerated) {
+            activity.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
+        }
+
+        return activity;
+    }
+
+    /**
+     * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI
+     */
+    private static boolean hasDomainURLs(
+            ParsingPackage parsingPackage) {
+        final List<ComponentParseUtils.ParsedActivity> activities = parsingPackage.getActivities();
+        final int countActivities = activities.size();
+        for (int n = 0; n < countActivities; n++) {
+            ComponentParseUtils.ParsedActivity activity = activities.get(n);
+            List<ComponentParseUtils.ParsedActivityIntentInfo> filters = activity.intents;
+            if (filters == null) continue;
+            final int countFilters = filters.size();
+            for (int m = 0; m < countFilters; m++) {
+                ComponentParseUtils.ParsedActivityIntentInfo aii = filters.get(m);
+                if (!aii.hasAction(Intent.ACTION_VIEW)) continue;
+                if (!aii.hasAction(Intent.ACTION_DEFAULT)) continue;
+                if (aii.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
+                        aii.hasDataScheme(IntentFilter.SCHEME_HTTPS)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Sets the max aspect ratio of every child activity that doesn't already have an aspect
+     * ratio set.
+     */
+    private static void setMaxAspectRatio(
+            ParsingPackage parsingPackage) {
+        // Default to (1.86) 16.7:9 aspect ratio for pre-O apps and unset for O and greater.
+        // NOTE: 16.7:9 was the max aspect ratio Android devices can support pre-O per the CDD.
+        float maxAspectRatio = parsingPackage.getTargetSdkVersion() < O
+                ? PackageParser.DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0;
+
+        float packageMaxAspectRatio = parsingPackage.getMaxAspectRatio();
+        if (packageMaxAspectRatio != 0) {
+            // Use the application max aspect ration as default if set.
+            maxAspectRatio = packageMaxAspectRatio;
+        } else {
+            Bundle appMetaData = parsingPackage.getAppMetaData();
+            if (appMetaData != null && appMetaData.containsKey(
+                    PackageParser.METADATA_MAX_ASPECT_RATIO)) {
+                maxAspectRatio = appMetaData.getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO,
+                        maxAspectRatio);
+            }
+        }
+
+        if (parsingPackage.getActivities() != null) {
+            for (ComponentParseUtils.ParsedActivity activity : parsingPackage.getActivities()) {
+                // If the max aspect ratio for the activity has already been set, skip.
+                if (activity.hasMaxAspectRatio()) {
+                    continue;
+                }
+
+                // By default we prefer to use a values defined on the activity directly than values
+                // defined on the application. We do not check the styled attributes on the activity
+                // as it would have already been set when we processed the activity. We wait to
+                // process the meta data here since this method is called at the end of processing
+                // the application and all meta data is guaranteed.
+                final float activityAspectRatio = activity.metaData != null
+                        ? activity.metaData.getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO,
+                        maxAspectRatio)
+                        : maxAspectRatio;
+
+                activity.setMaxAspectRatio(activity.resizeMode, activityAspectRatio);
+            }
+        }
+    }
+
+    /**
+     * Sets the min aspect ratio of every child activity that doesn't already have an aspect
+     * ratio set.
+     */
+    private static void setMinAspectRatio(
+            ParsingPackage parsingPackage,
+            PackageParser.Callback callback
+    ) {
+        final float minAspectRatio;
+        float packageMinAspectRatio = parsingPackage.getMinAspectRatio();
+        if (packageMinAspectRatio != 0) {
+            // Use the application max aspect ration as default if set.
+            minAspectRatio = packageMinAspectRatio;
+        } else {
+            // Default to (1.33) 4:3 aspect ratio for pre-Q apps and unset for Q and greater.
+            // NOTE: 4:3 was the min aspect ratio Android devices can support pre-Q per the CDD,
+            // except for watches which always supported 1:1.
+            minAspectRatio = parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.Q
+                    ? 0
+                    : (callback != null && callback.hasFeature(FEATURE_WATCH))
+                            ? PackageParser.DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH
+                            : PackageParser.DEFAULT_PRE_Q_MIN_ASPECT_RATIO;
+        }
+
+        if (parsingPackage.getActivities() != null) {
+            for (ComponentParseUtils.ParsedActivity activity : parsingPackage.getActivities()) {
+                if (activity.hasMinAspectRatio()) {
+                    continue;
+                }
+                activity.setMinAspectRatio(activity.resizeMode, minAspectRatio);
+            }
+        }
+    }
+
+    private static ParseResult parseOverlay(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestResourceOverlay);
+        String target = sa.getString(
+                R.styleable.AndroidManifestResourceOverlay_targetPackage);
+        String targetName = sa.getString(
+                R.styleable.AndroidManifestResourceOverlay_targetName);
+        String category = sa.getString(
+                R.styleable.AndroidManifestResourceOverlay_category);
+        int priority = sa.getInt(R.styleable.AndroidManifestResourceOverlay_priority,
+                0);
+        boolean isStatic = sa.getBoolean(
+                R.styleable.AndroidManifestResourceOverlay_isStatic, false);
+
+        if (target == null) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "<overlay> does not specify a target package"
+            );
+        }
+
+        if (priority < 0 || priority > 9999) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "<overlay> priority must be between 0 and 9999"
+            );
+        }
+
+        // check to see if overlay should be excluded based on system property condition
+        String propName = sa.getString(
+                R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyName);
+        String propValue = sa.getString(
+                R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyValue);
+        if (!checkOverlayRequiredSystemProperty(propName, propValue)) {
+            Slog.i(TAG, "Skipping target and overlay pair " + target + " and "
+                    + parsingPackage.getBaseCodePath()
+                    + ": overlay ignored due to required system property: "
+                    + propName + " with value: " + propValue);
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    "Skipping target and overlay pair " + target + " and "
+                            + parsingPackage.getBaseCodePath()
+                            + ": overlay ignored due to required system property: "
+                            + propName + " with value: " + propValue
+            );
+        }
+
+        parsingPackage
+                .setIsOverlay(true)
+                .setOverlayTarget(target)
+                .setOverlayTargetName(targetName)
+                .setOverlayCategory(category)
+                .setOverlayPriority(priority)
+                .setOverlayIsStatic(isStatic);
+
+        sa.recycle();
+
+        XmlUtils.skipCurrentTag(parser);
+        return parseInput.success(parsingPackage);
+    }
+
+    private static boolean parseProtectedBroadcast(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+        TypedArray sa = res.obtainAttributes(parser,
+                R.styleable.AndroidManifestProtectedBroadcast);
+
+        // Note: don't allow this value to be a reference to a resource
+        // that may change.
+        String name = sa.getNonResourceString(R.styleable.AndroidManifestProtectedBroadcast_name);
+
+        sa.recycle();
+
+        if (name != null) {
+            parsingPackage.addProtectedBroadcast(name);
+        }
+
+        XmlUtils.skipCurrentTag(parser);
+        return true;
+    }
+
+    private static boolean parseSupportScreens(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+        TypedArray sa = res.obtainAttributes(parser,
+                R.styleable.AndroidManifestSupportsScreens);
+
+        int requiresSmallestWidthDp = sa.getInteger(
+                R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp,
+                0);
+        int compatibleWidthLimitDp = sa.getInteger(
+                R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp,
+                0);
+        int largestWidthLimitDp = sa.getInteger(
+                R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp,
+                0);
+
+        // This is a trick to get a boolean and still able to detect
+        // if a value was actually set.
+        parsingPackage
+                .setSupportsSmallScreens(
+                        sa.getInteger(R.styleable.AndroidManifestSupportsScreens_smallScreens, 1))
+                .setSupportsNormalScreens(
+                        sa.getInteger(R.styleable.AndroidManifestSupportsScreens_normalScreens, 1))
+                .setSupportsLargeScreens(
+                        sa.getInteger(R.styleable.AndroidManifestSupportsScreens_largeScreens, 1))
+                .setSupportsXLargeScreens(
+                        sa.getInteger(R.styleable.AndroidManifestSupportsScreens_xlargeScreens, 1))
+                .setResizeable(
+                        sa.getInteger(R.styleable.AndroidManifestSupportsScreens_resizeable, 1))
+                .setAnyDensity(
+                        sa.getInteger(R.styleable.AndroidManifestSupportsScreens_anyDensity, 1))
+                .setRequiresSmallestWidthDp(requiresSmallestWidthDp)
+                .setCompatibleWidthLimitDp(compatibleWidthLimitDp)
+                .setLargestWidthLimitDp(largestWidthLimitDp);
+
+        sa.recycle();
+
+        XmlUtils.skipCurrentTag(parser);
+        return true;
+    }
+
+    private static ParseResult parseInstrumentation(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws XmlPullParserException, IOException {
+        // TODO(b/135203078): Remove, replace with ParseResult
+        String[] outError = new String[1];
+
+        ComponentParseUtils.ParsedInstrumentation parsedInstrumentation =
+                ComponentParseUtils.parseInstrumentation(parsingPackage,
+                        res, parser, outError);
+
+        if (parsedInstrumentation == null || outError[0] != null) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    outError[0]
+            );
+        }
+
+        parsingPackage.addInstrumentation(parsedInstrumentation);
+
+        return parseInput.success(parsingPackage);
+    }
+
+    private static boolean parseOriginalPackage(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+        TypedArray sa = res.obtainAttributes(parser,
+                R.styleable.AndroidManifestOriginalPackage);
+
+        String orig = sa.getNonConfigurationString(
+                R.styleable.AndroidManifestOriginalPackage_name,
+                0);
+        if (!parsingPackage.getPackageName().equals(orig)) {
+            if (parsingPackage.getOriginalPackages() == null) {
+                parsingPackage.setRealPackage(parsingPackage.getPackageName());
+            }
+            parsingPackage.addOriginalPackage(orig);
+        }
+
+        sa.recycle();
+
+        XmlUtils.skipCurrentTag(parser);
+        return true;
+    }
+
+    private static boolean parseAdoptPermissions(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+        TypedArray sa = res.obtainAttributes(parser,
+                R.styleable.AndroidManifestOriginalPackage);
+
+        String name = sa.getNonConfigurationString(
+                R.styleable.AndroidManifestOriginalPackage_name,
+                0);
+
+        sa.recycle();
+
+        if (name != null) {
+            parsingPackage.addAdoptPermission(name);
+        }
+
+        XmlUtils.skipCurrentTag(parser);
+        return true;
+    }
+
+    private static void convertNewPermissions(
+            ParsingPackage packageToParse) {
+        final int NP = PackageParser.NEW_PERMISSIONS.length;
+        StringBuilder newPermsMsg = null;
+        for (int ip = 0; ip < NP; ip++) {
+            final PackageParser.NewPermissionInfo npi
+                    = PackageParser.NEW_PERMISSIONS[ip];
+            if (packageToParse.getTargetSdkVersion() >= npi.sdkVersion) {
+                break;
+            }
+            if (!packageToParse.getRequestedPermissions().contains(npi.name)) {
+                if (newPermsMsg == null) {
+                    newPermsMsg = new StringBuilder(128);
+                    newPermsMsg.append(packageToParse.getPackageName());
+                    newPermsMsg.append(": compat added ");
+                } else {
+                    newPermsMsg.append(' ');
+                }
+                newPermsMsg.append(npi.name);
+                packageToParse.addRequestedPermission(npi.name);
+                packageToParse.addImplicitPermission(npi.name);
+            }
+        }
+        if (newPermsMsg != null) {
+            Slog.i(TAG, newPermsMsg.toString());
+        }
+    }
+
+    private static void convertSplitPermissions(ParsingPackage packageToParse) {
+        List<SplitPermissionInfoParcelable> splitPermissions;
+
+        try {
+            splitPermissions = ActivityThread.getPermissionManager().getSplitPermissions();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+
+        final int listSize = splitPermissions.size();
+        for (int is = 0; is < listSize; is++) {
+            final SplitPermissionInfoParcelable spi = splitPermissions.get(is);
+            List<String> requestedPermissions = packageToParse.getRequestedPermissions();
+            if (packageToParse.getTargetSdkVersion() >= spi.getTargetSdk()
+                    || !requestedPermissions.contains(spi.getSplitPermission())) {
+                continue;
+            }
+            final List<String> newPerms = spi.getNewPermissions();
+            for (int in = 0; in < newPerms.size(); in++) {
+                final String perm = newPerms.get(in);
+                if (!requestedPermissions.contains(perm)) {
+                    packageToParse.addRequestedPermission(perm);
+                    packageToParse.addImplicitPermission(perm);
+                }
+            }
+        }
+    }
+
+    private static boolean checkOverlayRequiredSystemProperty(String propName, String propValue) {
+        if (TextUtils.isEmpty(propName) || TextUtils.isEmpty(propValue)) {
+            if (!TextUtils.isEmpty(propName) || !TextUtils.isEmpty(propValue)) {
+                // malformed condition - incomplete
+                Slog.w(TAG, "Disabling overlay - incomplete property :'" + propName
+                        + "=" + propValue + "' - require both requiredSystemPropertyName"
+                        + " AND requiredSystemPropertyValue to be specified.");
+                return false;
+            }
+            // no valid condition set - so no exclusion criteria, overlay will be included.
+            return true;
+        }
+
+        // check property value - make sure it is both set and equal to expected value
+        final String currValue = SystemProperties.get(propName);
+        return (currValue != null && currValue.equals(propValue));
+    }
+
+    /**
+     * This is a pre-density application which will get scaled - instead of being pixel perfect.
+     * This type of application is not resizable.
+     *
+     * @param parsingPackage The package which needs to be marked as unresizable.
+     */
+    private static void adjustPackageToBeUnresizeableAndUnpipable(
+            ParsingPackage parsingPackage) {
+        if (parsingPackage.getActivities() != null) {
+            for (ComponentParseUtils.ParsedActivity a : parsingPackage.getActivities()) {
+                a.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+                a.flags &= ~FLAG_SUPPORTS_PICTURE_IN_PICTURE;
+            }
+        }
+    }
+
+    private static String validateName(String name, boolean requireSeparator,
+            boolean requireFilename) {
+        final int N = name.length();
+        boolean hasSep = false;
+        boolean front = true;
+        for (int i = 0; i < N; i++) {
+            final char c = name.charAt(i);
+            if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+                front = false;
+                continue;
+            }
+            if (!front) {
+                if ((c >= '0' && c <= '9') || c == '_') {
+                    continue;
+                }
+            }
+            if (c == '.') {
+                hasSep = true;
+                front = true;
+                continue;
+            }
+            return "bad character '" + c + "'";
+        }
+        if (requireFilename && !FileUtils.isValidExtFilename(name)) {
+            return "Invalid filename";
+        }
+        return hasSep || !requireSeparator
+                ? null : "must have at least one '.' separator";
+    }
+
+    public static Bundle parseMetaData(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser, Bundle data, String[] outError)
+            throws XmlPullParserException, IOException {
+
+        TypedArray sa = res.obtainAttributes(parser,
+                R.styleable.AndroidManifestMetaData);
+
+        if (data == null) {
+            data = new Bundle();
+        }
+
+        String name = sa.getNonConfigurationString(
+                R.styleable.AndroidManifestMetaData_name, 0);
+        if (name == null) {
+            outError[0] = "<meta-data> requires an android:name attribute";
+            sa.recycle();
+            return null;
+        }
+
+        name = name.intern();
+
+        TypedValue v = sa.peekValue(
+                R.styleable.AndroidManifestMetaData_resource);
+        if (v != null && v.resourceId != 0) {
+            //Slog.i(TAG, "Meta data ref " + name + ": " + v);
+            data.putInt(name, v.resourceId);
+        } else {
+            v = sa.peekValue(
+                    R.styleable.AndroidManifestMetaData_value);
+            //Slog.i(TAG, "Meta data " + name + ": " + v);
+            if (v != null) {
+                if (v.type == TypedValue.TYPE_STRING) {
+                    CharSequence cs = v.coerceToString();
+                    data.putString(name, cs != null ? cs.toString() : null);
+                } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
+                    data.putBoolean(name, v.data != 0);
+                } else if (v.type >= TypedValue.TYPE_FIRST_INT
+                        && v.type <= TypedValue.TYPE_LAST_INT) {
+                    data.putInt(name, v.data);
+                } else if (v.type == TypedValue.TYPE_FLOAT) {
+                    data.putFloat(name, v.getFloat());
+                } else {
+                    if (!PackageParser.RIGID_PARSER) {
+                        Slog.w(TAG,
+                                "<meta-data> only supports string, integer, float, color, "
+                                        + "boolean, and resource reference types: "
+                                        + parser.getName() + " at "
+                                        + parsingPackage.getBaseCodePath() + " "
+                                        + parser.getPositionDescription());
+                    } else {
+                        outError[0] =
+                                "<meta-data> only supports string, integer, float, color, "
+                                        + "boolean, and resource reference types";
+                        data = null;
+                    }
+                }
+            } else {
+                outError[0] = "<meta-data> requires an android:value or android:resource attribute";
+                data = null;
+            }
+        }
+
+        sa.recycle();
+
+        XmlUtils.skipCurrentTag(parser);
+
+        return data;
+    }
+
+    /**
+     * Collect certificates from all the APKs described in the given package,
+     * populating {@link AndroidPackageWrite#setSigningDetails(SigningDetails)}. Also asserts that
+     * all APK contents are signed correctly and consistently.
+     */
+    public static void collectCertificates(AndroidPackage pkg, boolean skipVerify)
+            throws PackageParserException {
+        pkg.mutate().setSigningDetails(SigningDetails.UNKNOWN);
+
+        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
+        try {
+            pkg.mutate().setSigningDetails(collectCertificates(
+                    pkg.getBaseCodePath(),
+                    skipVerify,
+                    pkg.isStaticSharedLibrary(),
+                    pkg.getSigningDetails()
+            ));
+
+            String[] splitCodePaths = pkg.getSplitCodePaths();
+            if (!ArrayUtils.isEmpty(splitCodePaths)) {
+                for (int i = 0; i < splitCodePaths.length; i++) {
+                    pkg.mutate().setSigningDetails(collectCertificates(
+                            splitCodePaths[i],
+                            skipVerify,
+                            pkg.isStaticSharedLibrary(),
+                            pkg.getSigningDetails()
+                    ));
+                }
+            }
+        } finally {
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        }
+    }
+
+    public static SigningDetails collectCertificates(
+            String baseCodePath,
+            boolean skipVerify,
+            boolean isStaticSharedLibrary,
+            @NonNull SigningDetails existingSigningDetails
+    ) throws PackageParserException {
+        int minSignatureScheme = SigningDetails.SignatureSchemeVersion.JAR;
+        if (isStaticSharedLibrary) {
+            // must use v2 signing scheme
+            minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2;
+        }
+        SigningDetails verified;
+        if (skipVerify) {
+            // systemDir APKs are already trusted, save time by not verifying
+            verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
+                    baseCodePath, minSignatureScheme);
+        } else {
+            verified = ApkSignatureVerifier.verify(baseCodePath, minSignatureScheme);
+        }
+
+        // Verify that entries are signed consistently with the first pkg
+        // we encountered. Note that for splits, certificates may have
+        // already been populated during an earlier parse of a base APK.
+        if (existingSigningDetails == SigningDetails.UNKNOWN) {
+            return verified;
+        } else {
+            if (!Signature.areExactMatch(existingSigningDetails.signatures, verified.signatures)) {
+                throw new PackageParserException(
+                        INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
+                        baseCodePath + " has mismatched certificates");
+            }
+
+            return existingSigningDetails;
+        }
+    }
+
+    @Nullable
+    public static String buildClassName(String pkg, CharSequence clsSeq) {
+        if (clsSeq == null || clsSeq.length() <= 0) {
+            return null;
+        }
+        String cls = clsSeq.toString();
+        char c = cls.charAt(0);
+        if (c == '.') {
+            return pkg + cls;
+        }
+        if (cls.indexOf('.') < 0) {
+            StringBuilder b = new StringBuilder(pkg);
+            b.append('.');
+            b.append(cls);
+            return b.toString();
+        }
+        return cls;
+    }
+
+    public interface ParseInput {
+        ParseResult success(ParsingPackage result);
+
+        ParseResult error(int parseError);
+
+        ParseResult error(int parseError, String errorMessage);
+    }
+
+    public static class ParseResult implements ParseInput {
+
+        private static final boolean DEBUG_FILL_STACK_TRACE = false;
+
+        private ParsingPackage result;
+
+        private int parseError;
+        private String errorMessage;
+
+        public ParseInput reset() {
+            this.result = null;
+            this.parseError = PackageManager.INSTALL_SUCCEEDED;
+            this.errorMessage = null;
+            return this;
+        }
+
+        @Override
+        public ParseResult success(ParsingPackage result) {
+            if (parseError != PackageManager.INSTALL_SUCCEEDED || errorMessage != null) {
+                throw new IllegalStateException("Cannot set to success after set to error");
+            }
+            this.result = result;
+            return this;
+        }
+
+        @Override
+        public ParseResult error(int parseError) {
+            return error(parseError, null);
+        }
+
+        @Override
+        public ParseResult error(int parseError, String errorMessage) {
+            this.parseError = parseError;
+            this.errorMessage = errorMessage;
+
+            if (DEBUG_FILL_STACK_TRACE) {
+                this.errorMessage += Arrays.toString(new Exception().getStackTrace());
+            }
+
+            return this;
+        }
+
+        public ParsingPackage getResultAndNull() {
+            ParsingPackage result = this.result;
+            this.result = null;
+            return result;
+        }
+
+        public boolean isSuccess() {
+            return parseError == PackageManager.INSTALL_SUCCEEDED;
+        }
+
+        public int getParseError() {
+            return parseError;
+        }
+
+        public String getErrorMessage() {
+            return errorMessage;
+        }
+    }
+}
diff --git a/core/java/android/content/pm/parsing/ComponentParseUtils.java b/core/java/android/content/pm/parsing/ComponentParseUtils.java
new file mode 100644
index 0000000..5364313
--- /dev/null
+++ b/core/java/android/content/pm/parsing/ComponentParseUtils.java
@@ -0,0 +1,3250 @@
+/*
+ * 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.content.pm.parsing;
+
+import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
+
+import android.annotation.CallSuper;
+import android.annotation.UnsupportedAppUsage;
+import android.app.ActivityTaskManager;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PathPermission;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ServiceInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.PatternMatcher;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Slog;
+import android.util.TypedValue;
+import android.view.Gravity;
+
+import com.android.internal.R;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * TODO(b/135203078): Move the inner classes out to separate files.
+ * TODO(b/135203078): Expose inner classes as immutable through interface methods.
+ *
+ * @hide
+ */
+public class ComponentParseUtils {
+
+    private static final String TAG = ApkParseUtils.TAG;
+
+    // TODO(b/135203078): None of this class's subclasses do anything. Remove in favor of base?
+    public static class ParsedIntentInfo extends IntentFilter {
+
+        /**
+         * <p>
+         * Implementation note: The serialized form for the intent list also contains the name
+         * of the concrete class that's stored in the list, and assumes that every element of the
+         * list is of the same type. This is very similar to the original parcelable mechanism.
+         * We cannot use that directly because IntentInfo extends IntentFilter, which is parcelable
+         * and is public API. It also declares Parcelable related methods as final which means
+         * we can't extend them. The approach of using composition instead of inheritance leads to
+         * a large set of cascading changes in the PackageManagerService, which seem undesirable.
+         *
+         * <p>
+         * <b>WARNING: </b> The list of objects returned by this function might need to be fixed up
+         * to make sure their owner fields are consistent. See {@code fixupOwner}.
+         */
+        public static void writeIntentsList(List<? extends ParsedIntentInfo> list, Parcel out,
+                int flags) {
+            if (list == null) {
+                out.writeInt(-1);
+                return;
+            }
+
+            final int size = list.size();
+            out.writeInt(size);
+
+            // Don't bother writing the component name if the list is empty.
+            if (size > 0) {
+                ParsedIntentInfo info = list.get(0);
+                out.writeString(info.getClass().getName());
+
+                for (int i = 0; i < size; i++) {
+                    list.get(i).writeIntentInfoToParcel(out, flags);
+                }
+            }
+        }
+
+        public static <T extends ParsedIntentInfo> ArrayList<T> createIntentsList(Parcel in) {
+            int size = in.readInt();
+            if (size == -1) {
+                return null;
+            }
+
+            if (size == 0) {
+                return new ArrayList<>(0);
+            }
+
+            String className = in.readString();
+            final ArrayList<T> intentsList;
+            try {
+                final Class<T> cls = (Class<T>) Class.forName(className);
+                final Constructor<T> cons = cls.getConstructor(Parcel.class);
+
+                intentsList = new ArrayList<>(size);
+                for (int i = 0; i < size; ++i) {
+                    intentsList.add(cons.newInstance(in));
+                }
+            } catch (ReflectiveOperationException ree) {
+                throw new AssertionError("Unable to construct intent list for: "
+                        + className, ree);
+            }
+
+            return intentsList;
+        }
+
+        protected String packageName;
+        protected final String className;
+
+        public boolean hasDefault;
+        public int labelRes;
+        public CharSequence nonLocalizedLabel;
+        public int icon;
+
+        protected List<String> rawDataTypes;
+
+        public void addRawDataType(String dataType) throws MalformedMimeTypeException {
+            if (rawDataTypes == null) {
+                rawDataTypes = new ArrayList<>();
+            }
+
+            rawDataTypes.add(dataType);
+            addDataType(dataType);
+        }
+
+        public ParsedIntentInfo(String packageName, String className) {
+            this.packageName = packageName;
+            this.className = className;
+        }
+
+        public ParsedIntentInfo(Parcel in) {
+            super(in);
+            packageName = in.readString();
+            className = in.readString();
+            hasDefault = (in.readInt() == 1);
+            labelRes = in.readInt();
+            nonLocalizedLabel = in.readCharSequence();
+            icon = in.readInt();
+        }
+
+        public void writeIntentInfoToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeString(packageName);
+            dest.writeString(className);
+            dest.writeInt(hasDefault ? 1 : 0);
+            dest.writeInt(labelRes);
+            dest.writeCharSequence(nonLocalizedLabel);
+            dest.writeInt(icon);
+        }
+
+        public String getPackageName() {
+            return packageName;
+        }
+
+        public String getClassName() {
+            return className;
+        }
+    }
+
+    public static class ParsedActivityIntentInfo extends ParsedIntentInfo {
+
+        public ParsedActivityIntentInfo(String packageName, String className) {
+            super(packageName, className);
+        }
+
+        public ParsedActivityIntentInfo(Parcel in) {
+            super(in);
+        }
+
+        public static final Creator<ParsedActivityIntentInfo> CREATOR =
+                new Creator<ParsedActivityIntentInfo>() {
+                    @Override
+                    public ParsedActivityIntentInfo createFromParcel(Parcel source) {
+                        return new ParsedActivityIntentInfo(source);
+                    }
+
+                    @Override
+                    public ParsedActivityIntentInfo[] newArray(int size) {
+                        return new ParsedActivityIntentInfo[size];
+                    }
+                };
+    }
+
+    public static class ParsedServiceIntentInfo extends ParsedIntentInfo {
+
+        public ParsedServiceIntentInfo(String packageName, String className) {
+            super(packageName, className);
+        }
+
+        public ParsedServiceIntentInfo(Parcel in) {
+            super(in);
+        }
+
+        public static final Creator<ParsedServiceIntentInfo> CREATOR =
+                new Creator<ParsedServiceIntentInfo>() {
+                    @Override
+                    public ParsedServiceIntentInfo createFromParcel(Parcel source) {
+                        return new ParsedServiceIntentInfo(source);
+                    }
+
+                    @Override
+                    public ParsedServiceIntentInfo[] newArray(int size) {
+                        return new ParsedServiceIntentInfo[size];
+                    }
+                };
+    }
+
+    public static class ParsedProviderIntentInfo extends ParsedIntentInfo {
+
+        public ParsedProviderIntentInfo(String packageName, String className) {
+            super(packageName, className);
+        }
+
+        public ParsedProviderIntentInfo(Parcel in) {
+            super(in);
+        }
+
+        public static final Creator<ParsedProviderIntentInfo> CREATOR =
+                new Creator<ParsedProviderIntentInfo>() {
+                    @Override
+                    public ParsedProviderIntentInfo createFromParcel(Parcel source) {
+                        return new ParsedProviderIntentInfo(source);
+                    }
+
+                    @Override
+                    public ParsedProviderIntentInfo[] newArray(int size) {
+                        return new ParsedProviderIntentInfo[size];
+                    }
+                };
+    }
+
+    public static class ParsedQueriesIntentInfo extends ParsedIntentInfo {
+
+        public ParsedQueriesIntentInfo(String packageName, String className) {
+            super(packageName, className);
+        }
+
+        public ParsedQueriesIntentInfo(Parcel in) {
+            super(in);
+        }
+
+        public static final Creator<ParsedQueriesIntentInfo> CREATOR =
+                new Creator<ParsedQueriesIntentInfo>() {
+                    @Override
+                    public ParsedQueriesIntentInfo createFromParcel(Parcel source) {
+                        return new ParsedQueriesIntentInfo(source);
+                    }
+
+                    @Override
+                    public ParsedQueriesIntentInfo[] newArray(int size) {
+                        return new ParsedQueriesIntentInfo[size];
+                    }
+                };
+    }
+
+    public static class ParsedComponent<IntentInfoType extends ParsedIntentInfo> implements
+            Parcelable {
+
+        // TODO(b/135203078): Replace with "name", as not all usages are an actual class
+        public String className;
+        public int icon;
+        public int labelRes;
+        public CharSequence nonLocalizedLabel;
+        public int logo;
+        public int banner;
+
+        public int descriptionRes;
+
+        // TODO(b/135203078): Make subclass that contains these fields only for the necessary
+        //  subtypes
+        protected boolean enabled = true;
+        protected boolean directBootAware;
+        public int flags;
+
+        private String packageName;
+        private String splitName;
+
+        // TODO(b/135203078): Make nullable
+        public List<IntentInfoType> intents = new ArrayList<>();
+
+        private transient ComponentName componentName;
+
+        protected Bundle metaData;
+
+        public void setSplitName(String splitName) {
+            this.splitName = splitName;
+        }
+
+        public String getSplitName() {
+            return splitName;
+        }
+
+        @CallSuper
+        public void setPackageName(String packageName) {
+            this.packageName = packageName;
+            this.componentName = null;
+        }
+
+        void setPackageNameInternal(String packageName) {
+            this.packageName = packageName;
+            this.componentName = null;
+        }
+
+        public void setEnabled(boolean enabled) {
+            this.enabled = enabled;
+        }
+
+        public String getPackageName() {
+            return packageName;
+        }
+
+        public final boolean isDirectBootAware() {
+            return directBootAware;
+        }
+
+        public final boolean isEnabled() {
+            return enabled;
+        }
+
+        public final String getName() {
+            return className;
+        }
+
+        public final Bundle getMetaData() {
+            return metaData;
+        }
+
+        @UnsupportedAppUsage
+        public ComponentName getComponentName() {
+            if (componentName != null) {
+                return componentName;
+            }
+            if (className != null) {
+                componentName = new ComponentName(getPackageName(),
+                        className);
+            }
+            return componentName;
+        }
+
+        public void setFrom(ParsedComponent other) {
+            this.metaData = other.metaData;
+            this.className = other.className;
+            this.icon = other.icon;
+            this.labelRes = other.labelRes;
+            this.nonLocalizedLabel = other.nonLocalizedLabel;
+            this.logo = other.logo;
+            this.banner = other.banner;
+
+            this.descriptionRes = other.descriptionRes;
+
+            this.enabled = other.enabled;
+            this.directBootAware = other.directBootAware;
+            this.flags = other.flags;
+
+            this.setPackageName(other.packageName);
+            this.setSplitName(other.getSplitName());
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeString(this.className);
+            dest.writeInt(this.icon);
+            dest.writeInt(this.labelRes);
+            dest.writeCharSequence(this.nonLocalizedLabel);
+            dest.writeInt(this.logo);
+            dest.writeInt(this.banner);
+            dest.writeInt(this.descriptionRes);
+            dest.writeBoolean(this.enabled);
+            dest.writeBoolean(this.directBootAware);
+            dest.writeInt(this.flags);
+            dest.writeString(this.packageName);
+            dest.writeString(this.splitName);
+            ParsedIntentInfo.writeIntentsList(this.intents, dest, flags);
+            dest.writeBundle(this.metaData);
+        }
+
+        public ParsedComponent() {
+        }
+
+        protected ParsedComponent(Parcel in) {
+            // We use the boot classloader for all classes that we load.
+            final ClassLoader boot = Object.class.getClassLoader();
+            this.className = in.readString();
+            this.icon = in.readInt();
+            this.labelRes = in.readInt();
+            this.nonLocalizedLabel = in.readCharSequence();
+            this.logo = in.readInt();
+            this.banner = in.readInt();
+            this.descriptionRes = in.readInt();
+            this.enabled = in.readByte() != 0;
+            this.directBootAware = in.readByte() != 0;
+            this.flags = in.readInt();
+            this.packageName = in.readString();
+            this.splitName = in.readString();
+            this.intents = ParsedIntentInfo.createIntentsList(in);
+            this.metaData = in.readBundle(boot);
+        }
+    }
+
+    // TODO(b/135203078): Document this. Maybe split out ParsedComponent to be actual components
+    //  that can have their own processes, rather than something like permission which cannot.
+    public static class ParsedMainComponent<IntentInfoType extends ParsedIntentInfo> extends
+            ParsedComponent<IntentInfoType> {
+
+        private String processName;
+        private String permission;
+
+        public void setProcessName(String appProcessName, String processName) {
+            // TODO(b/135203078): Is this even necessary anymore?
+            this.processName = TextUtils.safeIntern(
+                    processName == null ? appProcessName : processName);
+        }
+
+        public String getProcessName() {
+            return processName;
+        }
+
+        public void setPermission(String permission) {
+            this.permission = TextUtils.safeIntern(permission);
+        }
+
+        public String getPermission() {
+            return permission;
+        }
+
+        @Override
+        public void setFrom(ParsedComponent other) {
+            super.setFrom(other);
+            if (other instanceof ParsedMainComponent) {
+                ParsedMainComponent otherMainComponent = (ParsedMainComponent) other;
+                this.setProcessName(otherMainComponent.getProcessName(),
+                        otherMainComponent.getProcessName());
+                this.setPermission(otherMainComponent.getPermission());
+            }
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeString(this.processName);
+            dest.writeString(this.permission);
+        }
+
+        public ParsedMainComponent() {
+        }
+
+        protected ParsedMainComponent(Parcel in) {
+            super(in);
+            this.processName = TextUtils.safeIntern(in.readString());
+            this.permission = TextUtils.safeIntern(in.readString());
+        }
+
+        public static final Creator<ParsedMainComponent> CREATOR =
+                new Creator<ParsedMainComponent>() {
+                    @Override
+                    public ParsedMainComponent createFromParcel(Parcel source) {
+                        return new ParsedMainComponent(source);
+                    }
+
+                    @Override
+                    public ParsedMainComponent[] newArray(int size) {
+                        return new ParsedMainComponent[size];
+                    }
+                };
+    }
+
+    public static class ParsedActivity extends ParsedMainComponent<ParsedActivityIntentInfo>
+            implements Parcelable {
+
+        public boolean exported;
+        public int theme;
+        public int uiOptions;
+
+        public String targetActivity;
+
+        public String parentActivityName;
+        public String taskAffinity;
+        public int privateFlags;
+
+        public int launchMode;
+        public int documentLaunchMode;
+        public int maxRecents;
+        public int configChanges;
+        public int softInputMode;
+        public int persistableMode;
+        public int lockTaskLaunchMode;
+
+        public int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+        public int resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
+
+        public float maxAspectRatio;
+        public boolean hasMaxAspectRatio;
+
+        public float minAspectRatio;
+        public boolean hasMinAspectRatio;
+
+        public String requestedVrComponent;
+        public int rotationAnimation = -1;
+        public int colorMode;
+        public int order;
+
+        public ActivityInfo.WindowLayout windowLayout;
+
+        @Override
+        public void setPackageName(String packageName) {
+            super.setPackageName(packageName);
+            for (ParsedIntentInfo intent : this.intents) {
+                intent.packageName = packageName;
+            }
+        }
+
+        public boolean hasMaxAspectRatio() {
+            return hasMaxAspectRatio;
+        }
+
+        public boolean hasMinAspectRatio() {
+            return hasMinAspectRatio;
+        }
+
+        public void setMaxAspectRatio(int resizeMode, float maxAspectRatio) {
+            if (resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE
+                    || resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
+                // Resizeable activities can be put in any aspect ratio.
+                return;
+            }
+
+            if (maxAspectRatio < 1.0f && maxAspectRatio != 0) {
+                // Ignore any value lesser than 1.0.
+                return;
+            }
+
+            this.maxAspectRatio = maxAspectRatio;
+            hasMaxAspectRatio = true;
+        }
+
+        public void setMinAspectRatio(int resizeMode, float minAspectRatio) {
+            if (resizeMode == RESIZE_MODE_RESIZEABLE
+                    || resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
+                // Resizeable activities can be put in any aspect ratio.
+                return;
+            }
+
+            if (minAspectRatio < 1.0f && minAspectRatio != 0) {
+                // Ignore any value lesser than 1.0.
+                return;
+            }
+
+            this.minAspectRatio = minAspectRatio;
+            hasMinAspectRatio = true;
+        }
+
+        public void addIntent(ParsedActivityIntentInfo intent) {
+            this.intents.add(intent);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeBoolean(this.exported);
+            dest.writeInt(this.theme);
+            dest.writeInt(this.uiOptions);
+            dest.writeString(this.targetActivity);
+            dest.writeString(this.parentActivityName);
+            dest.writeString(this.taskAffinity);
+            dest.writeInt(this.privateFlags);
+            dest.writeInt(this.launchMode);
+            dest.writeInt(this.documentLaunchMode);
+            dest.writeInt(this.maxRecents);
+            dest.writeInt(this.configChanges);
+            dest.writeInt(this.softInputMode);
+            dest.writeInt(this.persistableMode);
+            dest.writeInt(this.lockTaskLaunchMode);
+            dest.writeInt(this.screenOrientation);
+            dest.writeInt(this.resizeMode);
+            dest.writeFloat(this.maxAspectRatio);
+            dest.writeBoolean(this.hasMaxAspectRatio);
+            dest.writeFloat(this.minAspectRatio);
+            dest.writeBoolean(this.hasMinAspectRatio);
+            dest.writeString(this.requestedVrComponent);
+            dest.writeInt(this.rotationAnimation);
+            dest.writeInt(this.colorMode);
+            dest.writeInt(this.order);
+            dest.writeBundle(this.metaData);
+
+            if (windowLayout != null) {
+                dest.writeInt(1);
+                dest.writeInt(windowLayout.width);
+                dest.writeFloat(windowLayout.widthFraction);
+                dest.writeInt(windowLayout.height);
+                dest.writeFloat(windowLayout.heightFraction);
+                dest.writeInt(windowLayout.gravity);
+                dest.writeInt(windowLayout.minWidth);
+                dest.writeInt(windowLayout.minHeight);
+            } else {
+                dest.writeInt(0);
+            }
+        }
+
+        public ParsedActivity() {
+        }
+
+        protected ParsedActivity(Parcel in) {
+            super(in);
+            this.exported = in.readByte() != 0;
+            this.theme = in.readInt();
+            this.uiOptions = in.readInt();
+            this.targetActivity = in.readString();
+            this.parentActivityName = in.readString();
+            this.taskAffinity = in.readString();
+            this.privateFlags = in.readInt();
+            this.launchMode = in.readInt();
+            this.documentLaunchMode = in.readInt();
+            this.maxRecents = in.readInt();
+            this.configChanges = in.readInt();
+            this.softInputMode = in.readInt();
+            this.persistableMode = in.readInt();
+            this.lockTaskLaunchMode = in.readInt();
+            this.screenOrientation = in.readInt();
+            this.resizeMode = in.readInt();
+            this.maxAspectRatio = in.readFloat();
+            this.hasMaxAspectRatio = in.readByte() != 0;
+            this.minAspectRatio = in.readFloat();
+            this.hasMinAspectRatio = in.readByte() != 0;
+            this.requestedVrComponent = in.readString();
+            this.rotationAnimation = in.readInt();
+            this.colorMode = in.readInt();
+            this.order = in.readInt();
+            this.metaData = in.readBundle();
+            if (in.readInt() == 1) {
+                windowLayout = new ActivityInfo.WindowLayout(in);
+            }
+        }
+
+        public static final Creator<ParsedActivity> CREATOR = new Creator<ParsedActivity>() {
+            @Override
+            public ParsedActivity createFromParcel(Parcel source) {
+                return new ParsedActivity(source);
+            }
+
+            @Override
+            public ParsedActivity[] newArray(int size) {
+                return new ParsedActivity[size];
+            }
+        };
+    }
+
+    public static class ParsedService extends ParsedMainComponent<ParsedServiceIntentInfo> {
+
+        public boolean exported;
+        public int flags;
+        public int foregroundServiceType;
+        public int order;
+
+        @Override
+        public void setPackageName(String packageName) {
+            super.setPackageName(packageName);
+            for (ParsedIntentInfo intent : this.intents) {
+                intent.packageName = packageName;
+            }
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeBoolean(this.exported);
+            dest.writeBundle(this.metaData);
+            dest.writeInt(this.flags);
+            dest.writeInt(this.foregroundServiceType);
+            dest.writeInt(this.order);
+        }
+
+        public ParsedService() {
+        }
+
+        protected ParsedService(Parcel in) {
+            super(in);
+            this.exported = in.readByte() != 0;
+            this.metaData = in.readBundle();
+            this.flags = in.readInt();
+            this.foregroundServiceType = in.readInt();
+            this.order = in.readInt();
+        }
+
+        public static final Creator<ParsedService> CREATOR = new Creator<ParsedService>() {
+            @Override
+            public ParsedService createFromParcel(Parcel source) {
+                return new ParsedService(source);
+            }
+
+            @Override
+            public ParsedService[] newArray(int size) {
+                return new ParsedService[size];
+            }
+        };
+    }
+
+    public static class ParsedProvider extends ParsedMainComponent<ParsedProviderIntentInfo> {
+
+        protected boolean exported;
+        protected int flags;
+        protected int order;
+        private String authority;
+        protected boolean isSyncable;
+        private String readPermission;
+        private String writePermission;
+        protected boolean grantUriPermissions;
+        protected boolean forceUriPermissions;
+        protected boolean multiProcess;
+        protected int initOrder;
+        protected PatternMatcher[] uriPermissionPatterns;
+        protected PathPermission[] pathPermissions;
+
+        protected void setFrom(ParsedProvider other) {
+            super.setFrom(other);
+            this.exported = other.exported;
+
+            this.intents.clear();
+            if (other.intents != null) {
+                this.intents.addAll(other.intents);
+            }
+
+            this.flags = other.flags;
+            this.order = other.order;
+            this.setAuthority(other.getAuthority());
+            this.isSyncable = other.isSyncable;
+            this.setReadPermission(other.getReadPermission());
+            this.setWritePermission(other.getWritePermission());
+            this.grantUriPermissions = other.grantUriPermissions;
+            this.forceUriPermissions = other.forceUriPermissions;
+            this.multiProcess = other.multiProcess;
+            this.initOrder = other.initOrder;
+            this.uriPermissionPatterns = other.uriPermissionPatterns;
+            this.pathPermissions = other.pathPermissions;
+        }
+
+        @Override
+        public void setPackageName(String packageName) {
+            super.setPackageName(packageName);
+            for (ParsedIntentInfo intent : this.intents) {
+                intent.packageName = packageName;
+            }
+        }
+
+        public boolean isExported() {
+            return exported;
+        }
+
+        public List<ParsedProviderIntentInfo> getIntents() {
+            return intents;
+        }
+
+        public int getFlags() {
+            return flags;
+        }
+
+        public int getOrder() {
+            return order;
+        }
+
+        public void setAuthority(String authority) {
+            this.authority = TextUtils.safeIntern(authority);
+        }
+
+        public String getAuthority() {
+            return authority;
+        }
+
+        public boolean isSyncable() {
+            return isSyncable;
+        }
+
+        public void setReadPermission(String readPermission) {
+            this.readPermission = TextUtils.safeIntern(readPermission);
+        }
+
+        public String getReadPermission() {
+            return readPermission;
+        }
+
+        public void setWritePermission(String writePermission) {
+            this.writePermission = TextUtils.safeIntern(writePermission);
+        }
+
+        public String getWritePermission() {
+            return writePermission;
+        }
+
+        public boolean isGrantUriPermissions() {
+            return grantUriPermissions;
+        }
+
+        public boolean isForceUriPermissions() {
+            return forceUriPermissions;
+        }
+
+        public boolean isMultiProcess() {
+            return multiProcess;
+        }
+
+        public int getInitOrder() {
+            return initOrder;
+        }
+
+        public PatternMatcher[] getUriPermissionPatterns() {
+            return uriPermissionPatterns;
+        }
+
+        public PathPermission[] getPathPermissions() {
+            return pathPermissions;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeBoolean(this.exported);
+            dest.writeInt(this.flags);
+            dest.writeInt(this.order);
+            dest.writeString(this.authority);
+            dest.writeBoolean(this.isSyncable);
+            dest.writeString(this.readPermission);
+            dest.writeString(this.writePermission);
+            dest.writeBoolean(this.grantUriPermissions);
+            dest.writeBoolean(this.forceUriPermissions);
+            dest.writeBoolean(this.multiProcess);
+            dest.writeInt(this.initOrder);
+            dest.writeTypedArray(this.uriPermissionPatterns, flags);
+            dest.writeTypedArray(this.pathPermissions, flags);
+        }
+
+        public ParsedProvider() {
+        }
+
+        protected ParsedProvider(Parcel in) {
+            super(in);
+            this.exported = in.readByte() != 0;
+            this.flags = in.readInt();
+            this.order = in.readInt();
+            this.authority = TextUtils.safeIntern(in.readString());
+            this.isSyncable = in.readByte() != 0;
+            this.readPermission = TextUtils.safeIntern(in.readString());
+            this.writePermission = TextUtils.safeIntern(in.readString());
+            this.grantUriPermissions = in.readByte() != 0;
+            this.forceUriPermissions = in.readByte() != 0;
+            this.multiProcess = in.readByte() != 0;
+            this.initOrder = in.readInt();
+            this.uriPermissionPatterns = in.createTypedArray(PatternMatcher.CREATOR);
+            this.pathPermissions = in.createTypedArray(PathPermission.CREATOR);
+        }
+
+        public static final Creator<ParsedProvider> CREATOR = new Creator<ParsedProvider>() {
+            @Override
+            public ParsedProvider createFromParcel(Parcel source) {
+                return new ParsedProvider(source);
+            }
+
+            @Override
+            public ParsedProvider[] newArray(int size) {
+                return new ParsedProvider[size];
+            }
+        };
+    }
+
+    public static class ParsedPermission extends ParsedComponent<ParsedIntentInfo> {
+
+        public String backgroundPermission;
+        private String group;
+        public int requestRes;
+        public int protectionLevel;
+        public boolean tree;
+
+        public ParsedPermissionGroup parsedPermissionGroup;
+
+        public void setName(String className) {
+            this.className = className;
+        }
+
+        public void setGroup(String group) {
+            this.group = TextUtils.safeIntern(group);
+        }
+
+        public String getGroup() {
+            return group;
+        }
+
+        public boolean isRuntime() {
+            return getProtection() == PermissionInfo.PROTECTION_DANGEROUS;
+        }
+
+        public boolean isAppOp() {
+            return (protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0;
+        }
+
+        @PermissionInfo.Protection
+        public int getProtection() {
+            return protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
+        }
+
+        public int getProtectionFlags() {
+            return protectionLevel & ~PermissionInfo.PROTECTION_MASK_BASE;
+        }
+
+        public int calculateFootprint() {
+            int size = getName().length();
+            if (nonLocalizedLabel != null) {
+                size += nonLocalizedLabel.length();
+            }
+            return size;
+        }
+
+        public ParsedPermission() {
+        }
+
+        public ParsedPermission(ParsedPermission other) {
+            // TODO(b/135203078): Better way to copy this? Maybe refactor to the point where copy
+            //  isn't needed.
+            this.className = other.className;
+            this.icon = other.icon;
+            this.labelRes = other.labelRes;
+            this.nonLocalizedLabel = other.nonLocalizedLabel;
+            this.logo = other.logo;
+            this.banner = other.banner;
+            this.descriptionRes = other.descriptionRes;
+            this.enabled = other.enabled;
+            this.directBootAware = other.directBootAware;
+            this.flags = other.flags;
+            this.setSplitName(other.getSplitName());
+            this.setPackageName(other.getPackageName());
+
+            this.intents.addAll(other.intents);
+
+            if (other.metaData != null) {
+                this.metaData = new Bundle();
+                this.metaData.putAll(other.metaData);
+            }
+
+            this.backgroundPermission = other.backgroundPermission;
+            this.setGroup(other.group);
+            this.requestRes = other.requestRes;
+            this.protectionLevel = other.protectionLevel;
+            this.tree = other.tree;
+
+            this.parsedPermissionGroup = other.parsedPermissionGroup;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeString(this.backgroundPermission);
+            dest.writeString(this.group);
+            dest.writeInt(this.requestRes);
+            dest.writeInt(this.protectionLevel);
+            dest.writeBoolean(this.tree);
+            dest.writeParcelable(this.parsedPermissionGroup, flags);
+        }
+
+        protected ParsedPermission(Parcel in) {
+            super(in);
+            // We use the boot classloader for all classes that we load.
+            final ClassLoader boot = Object.class.getClassLoader();
+            this.backgroundPermission = in.readString();
+            this.group = TextUtils.safeIntern(in.readString());
+            this.requestRes = in.readInt();
+            this.protectionLevel = in.readInt();
+            this.tree = in.readBoolean();
+            this.parsedPermissionGroup = in.readParcelable(boot);
+        }
+
+        public static final Creator<ParsedPermission> CREATOR = new Creator<ParsedPermission>() {
+            @Override
+            public ParsedPermission createFromParcel(Parcel source) {
+                return new ParsedPermission(source);
+            }
+
+            @Override
+            public ParsedPermission[] newArray(int size) {
+                return new ParsedPermission[size];
+            }
+        };
+    }
+
+    public static class ParsedPermissionGroup extends ParsedComponent<ParsedIntentInfo> {
+
+        public int requestDetailResourceId;
+        public int backgroundRequestResourceId;
+        public int backgroundRequestDetailResourceId;
+
+        public int requestRes;
+        public int priority;
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeInt(this.requestDetailResourceId);
+            dest.writeInt(this.backgroundRequestResourceId);
+            dest.writeInt(this.backgroundRequestDetailResourceId);
+            dest.writeInt(this.requestRes);
+            dest.writeInt(this.priority);
+        }
+
+        public ParsedPermissionGroup() {
+        }
+
+        protected ParsedPermissionGroup(Parcel in) {
+            super(in);
+            this.requestDetailResourceId = in.readInt();
+            this.backgroundRequestResourceId = in.readInt();
+            this.backgroundRequestDetailResourceId = in.readInt();
+            this.requestRes = in.readInt();
+            this.priority = in.readInt();
+        }
+
+        public static final Creator<ParsedPermissionGroup> CREATOR =
+                new Creator<ParsedPermissionGroup>() {
+                    @Override
+                    public ParsedPermissionGroup createFromParcel(Parcel source) {
+                        return new ParsedPermissionGroup(source);
+                    }
+
+                    @Override
+                    public ParsedPermissionGroup[] newArray(int size) {
+                        return new ParsedPermissionGroup[size];
+                    }
+                };
+    }
+
+    public static class ParsedInstrumentation extends ParsedComponent<ParsedIntentInfo> {
+
+        private String targetPackage;
+        private String targetProcesses;
+        public boolean handleProfiling;
+        public boolean functionalTest;
+
+        public ParsedInstrumentation() {
+        }
+
+        public void setTargetPackage(String targetPackage) {
+            this.targetPackage = TextUtils.safeIntern(targetPackage);
+        }
+
+        public String getTargetPackage() {
+            return targetPackage;
+        }
+
+        public void setTargetProcesses(String targetProcesses) {
+            this.targetProcesses = TextUtils.safeIntern(targetProcesses);
+        }
+
+        public String getTargetProcesses() {
+            return targetProcesses;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeString(this.targetPackage);
+            dest.writeString(this.targetProcesses);
+            dest.writeBoolean(this.handleProfiling);
+            dest.writeBoolean(this.functionalTest);
+        }
+
+        protected ParsedInstrumentation(Parcel in) {
+            super(in);
+            this.targetPackage = TextUtils.safeIntern(in.readString());
+            this.targetProcesses = TextUtils.safeIntern(in.readString());
+            this.handleProfiling = in.readByte() != 0;
+            this.functionalTest = in.readByte() != 0;
+        }
+
+        public static final Creator<ParsedInstrumentation> CREATOR =
+                new Creator<ParsedInstrumentation>() {
+                    @Override
+                    public ParsedInstrumentation createFromParcel(Parcel source) {
+                        return new ParsedInstrumentation(source);
+                    }
+
+                    @Override
+                    public ParsedInstrumentation[] newArray(int size) {
+                        return new ParsedInstrumentation[size];
+                    }
+                };
+    }
+
+    public static ParsedActivity parseActivity(
+            String[] separateProcesses,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser, int flags, String[] outError,
+            boolean receiver, boolean hardwareAccelerated)
+            throws XmlPullParserException, IOException {
+
+        TypedArray sa = null;
+        boolean visibleToEphemeral;
+        boolean setExported;
+
+        int targetSdkVersion = parsingPackage.getTargetSdkVersion();
+        String packageName = parsingPackage.getPackageName();
+        String packageProcessName = parsingPackage.getProcessName();
+        ParsedActivity result = new ParsedActivity();
+
+        try {
+            sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity);
+
+            String tag = receiver ? "<receiver>" : "<activity>";
+
+            String name = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_name, 0);
+            if (name == null) {
+                outError[0] = tag + " does not specify android:name";
+                return null;
+            } else {
+                String className = ApkParseUtils.buildClassName(packageName, name);
+                if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+                    outError[0] = tag + " invalid android:name";
+                    return null;
+                } else if (className == null) {
+                    outError[0] = "Empty class name in package " + packageName;
+                    return null;
+                }
+
+                result.className = className;
+            }
+
+            int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+                    R.styleable.AndroidManifestActivity_roundIcon, 0) : 0;
+            if (roundIconVal != 0) {
+                result.icon = roundIconVal;
+                result.nonLocalizedLabel = null;
+            } else {
+                int iconVal = sa.getResourceId(R.styleable.AndroidManifestActivity_icon, 0);
+                if (iconVal != 0) {
+                    result.icon = iconVal;
+                    result.nonLocalizedLabel = null;
+                }
+            }
+
+            int logoVal = sa.getResourceId(R.styleable.AndroidManifestActivity_logo, 0);
+            if (logoVal != 0) {
+                result.logo = logoVal;
+            }
+
+            int bannerVal = sa.getResourceId(R.styleable.AndroidManifestActivity_banner, 0);
+            if (bannerVal != 0) {
+                result.banner = bannerVal;
+            }
+
+            TypedValue v = sa.peekValue(R.styleable.AndroidManifestActivity_label);
+            if (v != null && (result.labelRes = v.resourceId) == 0) {
+                result.nonLocalizedLabel = v.coerceToString();
+            }
+
+            result.setPackageNameInternal(packageName);
+
+            CharSequence pname;
+            if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
+                pname = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_process,
+                        Configuration.NATIVE_CONFIG_VERSION);
+            } else {
+                // Some older apps have been seen to use a resource reference
+                // here that on older builds was ignored (with a warning).  We
+                // need to continue to do this for them so they don't break.
+                pname = sa.getNonResourceString(R.styleable.AndroidManifestActivity_process);
+            }
+
+            result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName,
+                    packageProcessName, pname,
+                    flags, separateProcesses, outError));
+
+            result.descriptionRes = sa.getResourceId(
+                    R.styleable.AndroidManifestActivity_description, 0);
+
+            result.enabled = sa.getBoolean(R.styleable.AndroidManifestActivity_enabled, true);
+
+            setExported = sa.hasValue(R.styleable.AndroidManifestActivity_exported);
+            if (setExported) {
+                result.exported = sa.getBoolean(R.styleable.AndroidManifestActivity_exported,
+                        false);
+            }
+
+            result.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0);
+
+            result.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions,
+                    parsingPackage.getUiOptions());
+
+            String parentName = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestActivity_parentActivityName,
+                    Configuration.NATIVE_CONFIG_VERSION);
+            if (parentName != null) {
+                String parentClassName = ApkParseUtils.buildClassName(packageName, parentName);
+                if (parentClassName == null) {
+                    Log.e(TAG,
+                            "Activity " + result.className
+                                    + " specified invalid parentActivityName " +
+                                    parentName);
+                } else {
+                    result.parentActivityName = parentClassName;
+                }
+            }
+
+            String str;
+            str = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_permission, 0);
+            if (str == null) {
+                result.setPermission(parsingPackage.getPermission());
+            } else {
+                result.setPermission(str);
+            }
+
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestActivity_taskAffinity,
+                    Configuration.NATIVE_CONFIG_VERSION);
+            result.taskAffinity = PackageParser.buildTaskAffinityName(
+                    packageName,
+                    parsingPackage.getTaskAffinity(), str, outError);
+
+            result.setSplitName(
+                    sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_splitName, 0));
+
+            result.flags = 0;
+            if (sa.getBoolean(
+                    R.styleable.AndroidManifestActivity_multiprocess, false)) {
+                result.flags |= ActivityInfo.FLAG_MULTIPROCESS;
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnTaskLaunch, false)) {
+                result.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH;
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_clearTaskOnLaunch, false)) {
+                result.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH;
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_noHistory, false)) {
+                result.flags |= ActivityInfo.FLAG_NO_HISTORY;
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysRetainTaskState, false)) {
+                result.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE;
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_stateNotNeeded, false)) {
+                result.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED;
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_excludeFromRecents, false)) {
+                result.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowTaskReparenting,
+                    (parsingPackage.getFlags() & ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING)
+                            != 0)) {
+                result.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING;
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs,
+                    false)) {
+                result.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_showOnLockScreen, false)
+                    || sa.getBoolean(R.styleable.AndroidManifestActivity_showForAllUsers, false)) {
+                result.flags |= ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_immersive, false)) {
+                result.flags |= ActivityInfo.FLAG_IMMERSIVE;
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_systemUserOnly, false)) {
+                result.flags |= ActivityInfo.FLAG_SYSTEM_USER_ONLY;
+            }
+
+            boolean directBootAware;
+
+            if (!receiver) {
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_hardwareAccelerated,
+                        hardwareAccelerated)) {
+                    result.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
+                }
+
+                result.launchMode = sa.getInt(
+                        R.styleable.AndroidManifestActivity_launchMode,
+                        ActivityInfo.LAUNCH_MULTIPLE);
+                result.documentLaunchMode = sa.getInt(
+                        R.styleable.AndroidManifestActivity_documentLaunchMode,
+                        ActivityInfo.DOCUMENT_LAUNCH_NONE);
+                result.maxRecents = sa.getInt(
+                        R.styleable.AndroidManifestActivity_maxRecents,
+                        ActivityTaskManager.getDefaultAppRecentsLimitStatic());
+                result.configChanges = PackageParser.getActivityConfigChanges(
+                        sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0),
+                        sa.getInt(R.styleable.AndroidManifestActivity_recreateOnConfigChanges, 0));
+                result.softInputMode = sa.getInt(
+                        R.styleable.AndroidManifestActivity_windowSoftInputMode, 0);
+
+                result.persistableMode = sa.getInteger(
+                        R.styleable.AndroidManifestActivity_persistableMode,
+                        ActivityInfo.PERSIST_ROOT_ONLY);
+
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowEmbedded, false)) {
+                    result.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
+                }
+
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_autoRemoveFromRecents,
+                        false)) {
+                    result.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS;
+                }
+
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_relinquishTaskIdentity,
+                        false)) {
+                    result.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
+                }
+
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_resumeWhilePausing, false)) {
+                    result.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
+                }
+
+                int screenOrientation = sa.getInt(
+                        R.styleable.AndroidManifestActivity_screenOrientation,
+                        SCREEN_ORIENTATION_UNSPECIFIED);
+                result.screenOrientation = screenOrientation;
+
+                int resizeMode = getActivityResizeMode(parsingPackage, sa, screenOrientation);
+                result.resizeMode = resizeMode;
+
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture,
+                        false)) {
+                    result.flags |= FLAG_SUPPORTS_PICTURE_IN_PICTURE;
+                }
+
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) {
+                    result.flags |= FLAG_ALWAYS_FOCUSABLE;
+                }
+
+                if (sa.hasValue(R.styleable.AndroidManifestActivity_maxAspectRatio)
+                        && sa.getType(R.styleable.AndroidManifestActivity_maxAspectRatio)
+                        == TypedValue.TYPE_FLOAT) {
+                    result.setMaxAspectRatio(resizeMode,
+                            sa.getFloat(R.styleable.AndroidManifestActivity_maxAspectRatio,
+                                    0 /*default*/));
+                }
+
+                if (sa.hasValue(R.styleable.AndroidManifestActivity_minAspectRatio)
+                        && sa.getType(R.styleable.AndroidManifestActivity_minAspectRatio)
+                        == TypedValue.TYPE_FLOAT) {
+                    result.setMinAspectRatio(resizeMode,
+                            sa.getFloat(R.styleable.AndroidManifestActivity_minAspectRatio,
+                                    0 /*default*/));
+                }
+
+                result.lockTaskLaunchMode =
+                        sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
+
+                directBootAware = sa.getBoolean(
+                        R.styleable.AndroidManifestActivity_directBootAware,
+                        false);
+
+                result.requestedVrComponent =
+                        sa.getString(R.styleable.AndroidManifestActivity_enableVrMode);
+
+                result.rotationAnimation =
+                        sa.getInt(R.styleable.AndroidManifestActivity_rotationAnimation,
+                                ROTATION_ANIMATION_UNSPECIFIED);
+
+                result.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode,
+                        ActivityInfo.COLOR_MODE_DEFAULT);
+
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_showWhenLocked, false)) {
+                    result.flags |= ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
+                }
+
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_turnScreenOn, false)) {
+                    result.flags |= ActivityInfo.FLAG_TURN_SCREEN_ON;
+                }
+
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_inheritShowWhenLocked,
+                        false)) {
+                    result.privateFlags |= ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED;
+                }
+            } else {
+                result.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+                result.configChanges = 0;
+
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_singleUser, false)) {
+                    result.flags |= ActivityInfo.FLAG_SINGLE_USER;
+                }
+                directBootAware = sa.getBoolean(
+                        R.styleable.AndroidManifestActivity_directBootAware,
+                        false);
+            }
+
+            result.directBootAware = directBootAware;
+
+            if (directBootAware) {
+                parsingPackage.setPartiallyDirectBootAware(true);
+            }
+
+            // can't make this final; we may set it later via meta-data
+            visibleToEphemeral = sa.getBoolean(
+                    R.styleable.AndroidManifestActivity_visibleToInstantApps, false);
+            if (visibleToEphemeral) {
+                result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+                parsingPackage.setVisibleToInstantApps(true);
+            }
+        } finally {
+            if (sa != null) {
+                sa.recycle();
+            }
+        }
+
+
+        if (receiver && (parsingPackage.getPrivateFlags()
+                & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
+            // A heavy-weight application can not have receives in its main process
+            if (result.getProcessName().equals(packageName)) {
+                outError[0] = "Heavy-weight applications can not have receivers in main process";
+                return null;
+            }
+        }
+
+        if (outError[0] != null) {
+            return null;
+        }
+
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            if (parser.getName().equals("intent-filter")) {
+                ParsedActivityIntentInfo intentInfo = new ParsedActivityIntentInfo(packageName,
+                        result.className);
+                if (!parseIntentInfo(intentInfo, parsingPackage, res, parser,
+                        true /*allowGlobs*/,
+                        true /*allowAutoVerify*/, outError)) {
+                    return null;
+                }
+                if (intentInfo.countActions() == 0) {
+                    Slog.w(TAG, "No actions in intent filter at "
+                            + parsingPackage.getBaseCodePath() + " "
+                            + parser.getPositionDescription());
+                } else {
+                    result.order = Math.max(intentInfo.getOrder(), result.order);
+                    result.addIntent(intentInfo);
+                }
+                // adjust activity flags when we implicitly expose it via a browsable filter
+                final int visibility = visibleToEphemeral
+                        ? IntentFilter.VISIBILITY_EXPLICIT
+                        : !receiver && isImplicitlyExposedIntent(intentInfo)
+                                ? IntentFilter.VISIBILITY_IMPLICIT
+                                : IntentFilter.VISIBILITY_NONE;
+                intentInfo.setVisibilityToInstantApp(visibility);
+                if (intentInfo.isVisibleToInstantApp()) {
+                    result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+                }
+                if (intentInfo.isImplicitlyVisibleToInstantApp()) {
+                    result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
+                }
+                if (PackageParser.LOG_UNSAFE_BROADCASTS && receiver
+                        && (targetSdkVersion >= Build.VERSION_CODES.O)) {
+                    for (int i = 0; i < intentInfo.countActions(); i++) {
+                        final String action = intentInfo.getAction(i);
+                        if (action == null || !action.startsWith("android.")) continue;
+                        if (!PackageParser.SAFE_BROADCASTS.contains(action)) {
+                            Slog.w(TAG, "Broadcast " + action + " may never be delivered to "
+                                    + packageName + " as requested at: "
+                                    + parser.getPositionDescription());
+                        }
+                    }
+                }
+            } else if (!receiver && parser.getName().equals("preferred")) {
+                ParsedActivityIntentInfo intentInfo = new ParsedActivityIntentInfo(packageName,
+                        result.className);
+                if (!parseIntentInfo(intentInfo, parsingPackage, res, parser,
+                        false /*allowGlobs*/,
+                        false /*allowAutoVerify*/, outError)) {
+                    return null;
+                }
+                // adjust activity flags when we implicitly expose it via a browsable filter
+                final int visibility = visibleToEphemeral
+                        ? IntentFilter.VISIBILITY_EXPLICIT
+                        : !receiver && isImplicitlyExposedIntent(intentInfo)
+                                ? IntentFilter.VISIBILITY_IMPLICIT
+                                : IntentFilter.VISIBILITY_NONE;
+                intentInfo.setVisibilityToInstantApp(visibility);
+                if (intentInfo.isVisibleToInstantApp()) {
+                    result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+                }
+                if (intentInfo.isImplicitlyVisibleToInstantApp()) {
+                    result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
+                }
+
+                if (intentInfo.countActions() == 0) {
+                    Slog.w(TAG, "No actions in preferred at "
+                            + parsingPackage.getBaseCodePath() + " "
+                            + parser.getPositionDescription());
+                } else {
+                    parsingPackage.addPreferredActivityFilter(intentInfo);
+                }
+            } else if (parser.getName().equals("meta-data")) {
+                if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
+                        result.metaData,
+                        outError)) == null) {
+                    return null;
+                }
+            } else if (!receiver && parser.getName().equals("layout")) {
+                result.windowLayout = parseLayout(res, parser);
+            } else {
+                if (!PackageParser.RIGID_PARSER) {
+                    Slog.w(TAG, "Problem in package " + parsingPackage.getBaseCodePath() + ":");
+                    if (receiver) {
+                        Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName()
+                                + " at " + parsingPackage.getBaseCodePath() + " "
+                                + parser.getPositionDescription());
+                    } else {
+                        Slog.w(TAG, "Unknown element under <activity>: " + parser.getName()
+                                + " at " + parsingPackage.getBaseCodePath() + " "
+                                + parser.getPositionDescription());
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+                } else {
+                    if (receiver) {
+                        outError[0] = "Bad element under <receiver>: " + parser.getName();
+                    } else {
+                        outError[0] = "Bad element under <activity>: " + parser.getName();
+                    }
+                    return null;
+                }
+            }
+        }
+
+        if (!setExported) {
+            result.exported = result.intents.size() > 0;
+        }
+
+        return result;
+    }
+
+    public static boolean isImplicitlyExposedIntent(ParsedIntentInfo intentInfo) {
+        return intentInfo.hasCategory(Intent.CATEGORY_BROWSABLE)
+                || intentInfo.hasAction(Intent.ACTION_SEND)
+                || intentInfo.hasAction(Intent.ACTION_SENDTO)
+                || intentInfo.hasAction(Intent.ACTION_SEND_MULTIPLE);
+    }
+
+    public static int getActivityResizeMode(
+            ParsingPackage parsingPackage,
+            TypedArray sa,
+            int screenOrientation
+    ) {
+        int privateFlags = parsingPackage.getPrivateFlags();
+        final boolean appExplicitDefault = (privateFlags
+                & (ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE
+                | ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE)) != 0;
+
+        if (sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity)
+                || appExplicitDefault) {
+            // Activity or app explicitly set if it is resizeable or not;
+            final boolean appResizeable = (privateFlags
+                    & ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE) != 0;
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity,
+                    appResizeable)) {
+                return ActivityInfo.RESIZE_MODE_RESIZEABLE;
+            } else {
+                return ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+            }
+        }
+
+        if ((privateFlags
+                & ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION)
+                != 0) {
+            // The activity or app didn't explicitly set the resizing option, however we want to
+            // make it resize due to the sdk version it is targeting.
+            return ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
+        }
+
+        // resize preference isn't set and target sdk version doesn't support resizing apps by
+        // default. For the app to be resizeable if it isn't fixed orientation or immersive.
+        if (ActivityInfo.isFixedOrientationPortrait(screenOrientation)) {
+            return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
+        } else if (ActivityInfo.isFixedOrientationLandscape(screenOrientation)) {
+            return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
+        } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
+            return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
+        } else {
+            return ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
+        }
+    }
+
+    public static ParsedService parseService(
+            String[] separateProcesses,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser, int flags, String[] outError
+    ) throws XmlPullParserException, IOException {
+        TypedArray sa = null;
+        boolean visibleToEphemeral;
+        boolean setExported;
+
+        String packageName = parsingPackage.getPackageName();
+        String packageProcessName = parsingPackage.getProcessName();
+        ParsedService result = new ParsedService();
+
+        try {
+            sa = res.obtainAttributes(parser,
+                    R.styleable.AndroidManifestService);
+
+            String name = sa.getNonConfigurationString(R.styleable.AndroidManifestService_name, 0);
+            if (name == null) {
+                outError[0] = "<service> does not specify android:name";
+                return null;
+            } else {
+                String className = ApkParseUtils.buildClassName(packageName, name);
+                if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+                    outError[0] = "<service> invalid android:name";
+                    return null;
+                } else if (className == null) {
+                    outError[0] = "Empty class name in package " + packageName;
+                    return null;
+                }
+
+                result.className = className;
+            }
+
+            int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+                    R.styleable.AndroidManifestService_roundIcon, 0) : 0;
+            if (roundIconVal != 0) {
+                result.icon = roundIconVal;
+                result.nonLocalizedLabel = null;
+            } else {
+                int iconVal = sa.getResourceId(R.styleable.AndroidManifestService_icon, 0);
+                if (iconVal != 0) {
+                    result.icon = iconVal;
+                    result.nonLocalizedLabel = null;
+                }
+            }
+
+            int logoVal = sa.getResourceId(R.styleable.AndroidManifestService_logo, 0);
+            if (logoVal != 0) {
+                result.logo = logoVal;
+            }
+
+            int bannerVal = sa.getResourceId(R.styleable.AndroidManifestService_banner, 0);
+            if (bannerVal != 0) {
+                result.banner = bannerVal;
+            }
+
+            TypedValue v = sa.peekValue(R.styleable.AndroidManifestService_label);
+            if (v != null && (result.labelRes = v.resourceId) == 0) {
+                result.nonLocalizedLabel = v.coerceToString();
+            }
+
+            result.setPackageNameInternal(packageName);
+
+            CharSequence pname;
+            if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
+                pname = sa.getNonConfigurationString(R.styleable.AndroidManifestService_process,
+                        Configuration.NATIVE_CONFIG_VERSION);
+            } else {
+                // Some older apps have been seen to use a resource reference
+                // here that on older builds was ignored (with a warning).  We
+                // need to continue to do this for them so they don't break.
+                pname = sa.getNonResourceString(R.styleable.AndroidManifestService_process);
+            }
+
+            result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName,
+                    packageProcessName, pname,
+                    flags, separateProcesses, outError));
+
+            result.descriptionRes = sa.getResourceId(
+                    R.styleable.AndroidManifestService_description, 0);
+
+            result.enabled = sa.getBoolean(R.styleable.AndroidManifestService_enabled, true);
+
+            setExported = sa.hasValue(
+                    R.styleable.AndroidManifestService_exported);
+            if (setExported) {
+                result.exported = sa.getBoolean(
+                        R.styleable.AndroidManifestService_exported, false);
+            }
+
+            String str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestService_permission, 0);
+            if (str == null) {
+                result.setPermission(parsingPackage.getPermission());
+            } else {
+                result.setPermission(str);
+            }
+
+            result.setSplitName(
+                    sa.getNonConfigurationString(R.styleable.AndroidManifestService_splitName, 0));
+
+            result.foregroundServiceType = sa.getInt(
+                    R.styleable.AndroidManifestService_foregroundServiceType,
+                    ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE);
+
+            result.flags = 0;
+            if (sa.getBoolean(
+                    R.styleable.AndroidManifestService_stopWithTask,
+                    false)) {
+                result.flags |= ServiceInfo.FLAG_STOP_WITH_TASK;
+            }
+            if (sa.getBoolean(
+                    R.styleable.AndroidManifestService_isolatedProcess,
+                    false)) {
+                result.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS;
+            }
+            if (sa.getBoolean(
+                    R.styleable.AndroidManifestService_externalService,
+                    false)) {
+                result.flags |= ServiceInfo.FLAG_EXTERNAL_SERVICE;
+            }
+            if (sa.getBoolean(
+                    R.styleable.AndroidManifestService_useAppZygote,
+                    false)) {
+                result.flags |= ServiceInfo.FLAG_USE_APP_ZYGOTE;
+            }
+            if (sa.getBoolean(
+                    R.styleable.AndroidManifestService_singleUser,
+                    false)) {
+                result.flags |= ServiceInfo.FLAG_SINGLE_USER;
+            }
+
+            result.directBootAware = sa.getBoolean(
+                    R.styleable.AndroidManifestService_directBootAware,
+                    false);
+            if (result.directBootAware) {
+                parsingPackage.setPartiallyDirectBootAware(true);
+            }
+
+            visibleToEphemeral = sa.getBoolean(
+                    R.styleable.AndroidManifestService_visibleToInstantApps, false);
+            if (visibleToEphemeral) {
+                result.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+                parsingPackage.setVisibleToInstantApps(true);
+            }
+        } finally {
+            if (sa != null) {
+                sa.recycle();
+            }
+        }
+
+        if (parsingPackage.cantSaveState()) {
+            // A heavy-weight application can not have services in its main process
+            // We can do direct compare because we intern all strings.
+            if (Objects.equals(result.getProcessName(), parsingPackage.getPackageName())) {
+                outError[0] = "Heavy-weight applications can not have services in main process";
+                return null;
+            }
+        }
+
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            if (parser.getName().equals("intent-filter")) {
+                ParsedServiceIntentInfo intent = new ParsedServiceIntentInfo(packageName,
+                        result.className);
+                if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/,
+                        false /*allowAutoVerify*/,
+                        outError)) {
+                    return null;
+                }
+                if (visibleToEphemeral) {
+                    intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
+                    result.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+                }
+                result.order = Math.max(intent.getOrder(), result.order);
+                result.intents.add(intent);
+            } else if (parser.getName().equals("meta-data")) {
+                if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
+                        result.metaData,
+                        outError)) == null) {
+                    return null;
+                }
+            } else {
+                if (!PackageParser.RIGID_PARSER) {
+                    Slog.w(TAG, "Unknown element under <service>: "
+                            + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " "
+                            + parser.getPositionDescription());
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+                } else {
+                    outError[0] = "Bad element under <service>: " + parser.getName();
+                    return null;
+                }
+            }
+        }
+
+        if (!setExported) {
+            result.exported = result.intents.size() > 0;
+        }
+
+        return result;
+    }
+
+    public static ParsedProvider parseProvider(
+            String[] separateProcesses,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser, int flags, String[] outError)
+            throws XmlPullParserException, IOException {
+        TypedArray sa = null;
+        String cpname;
+        boolean visibleToEphemeral;
+
+        int targetSdkVersion = parsingPackage.getTargetSdkVersion();
+        String packageName = parsingPackage.getPackageName();
+        String packageProcessName = parsingPackage.getProcessName();
+        ParsedProvider result = new ParsedProvider();
+
+        try {
+            sa = res.obtainAttributes(parser,
+                    R.styleable.AndroidManifestProvider);
+
+            String name = sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_name, 0);
+            if (name == null) {
+                outError[0] = "<provider> does not specify android:name";
+                return null;
+            } else {
+                String className = ApkParseUtils.buildClassName(packageName, name);
+                if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+                    outError[0] = "<provider> invalid android:name";
+                    return null;
+                } else if (className == null) {
+                    outError[0] = "Empty class name in package " + packageName;
+                    return null;
+                }
+
+                result.className = className;
+            }
+
+            int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+                    R.styleable.AndroidManifestProvider_roundIcon, 0) : 0;
+            if (roundIconVal != 0) {
+                result.icon = roundIconVal;
+                result.nonLocalizedLabel = null;
+            } else {
+                int iconVal = sa.getResourceId(R.styleable.AndroidManifestProvider_icon, 0);
+                if (iconVal != 0) {
+                    result.icon = iconVal;
+                    result.nonLocalizedLabel = null;
+                }
+            }
+
+            int logoVal = sa.getResourceId(R.styleable.AndroidManifestProvider_logo, 0);
+            if (logoVal != 0) {
+                result.logo = logoVal;
+            }
+
+            int bannerVal = sa.getResourceId(R.styleable.AndroidManifestProvider_banner, 0);
+            if (bannerVal != 0) {
+                result.banner = bannerVal;
+            }
+
+            TypedValue v = sa.peekValue(R.styleable.AndroidManifestProvider_label);
+            if (v != null && (result.labelRes = v.resourceId) == 0) {
+                result.nonLocalizedLabel = v.coerceToString();
+            }
+
+            result.setPackageNameInternal(packageName);
+
+            CharSequence pname;
+            if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
+                pname = sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_process,
+                        Configuration.NATIVE_CONFIG_VERSION);
+            } else {
+                // Some older apps have been seen to use a resource reference
+                // here that on older builds was ignored (with a warning).  We
+                // need to continue to do this for them so they don't break.
+                pname = sa.getNonResourceString(R.styleable.AndroidManifestProvider_process);
+            }
+
+            result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName,
+                    packageProcessName, pname,
+                    flags, separateProcesses, outError));
+
+            result.descriptionRes = sa.getResourceId(
+                    R.styleable.AndroidManifestProvider_description, 0);
+
+            result.enabled = sa.getBoolean(R.styleable.AndroidManifestProvider_enabled, true);
+
+            boolean providerExportedDefault = false;
+
+            if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) {
+                // For compatibility, applications targeting API level 16 or lower
+                // should have their content providers exported by default, unless they
+                // specify otherwise.
+                providerExportedDefault = true;
+            }
+
+            result.exported = sa.getBoolean(
+                    R.styleable.AndroidManifestProvider_exported,
+                    providerExportedDefault);
+
+            cpname = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestProvider_authorities, 0);
+
+            result.isSyncable = sa.getBoolean(
+                    R.styleable.AndroidManifestProvider_syncable,
+                    false);
+
+            String permission = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestProvider_permission, 0);
+            String str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestProvider_readPermission, 0);
+            if (str == null) {
+                str = permission;
+            }
+            if (str == null) {
+                result.setReadPermission(parsingPackage.getPermission());
+            } else {
+                result.setReadPermission(str);
+            }
+            str = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestProvider_writePermission, 0);
+            if (str == null) {
+                str = permission;
+            }
+            if (str == null) {
+                result.setWritePermission(parsingPackage.getPermission());
+            } else {
+                result.setWritePermission(str);
+            }
+
+            result.grantUriPermissions = sa.getBoolean(
+                    R.styleable.AndroidManifestProvider_grantUriPermissions,
+                    false);
+
+            result.forceUriPermissions = sa.getBoolean(
+                    R.styleable.AndroidManifestProvider_forceUriPermissions,
+                    false);
+
+            result.multiProcess = sa.getBoolean(
+                    R.styleable.AndroidManifestProvider_multiprocess,
+                    false);
+
+            result.initOrder = sa.getInt(
+                    R.styleable.AndroidManifestProvider_initOrder,
+                    0);
+
+            result.setSplitName(
+                    sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_splitName, 0));
+
+            result.flags = 0;
+
+            if (sa.getBoolean(
+                    R.styleable.AndroidManifestProvider_singleUser,
+                    false)) {
+                result.flags |= ProviderInfo.FLAG_SINGLE_USER;
+            }
+
+            result.directBootAware = sa.getBoolean(
+                    R.styleable.AndroidManifestProvider_directBootAware,
+                    false);
+            if (result.directBootAware) {
+                parsingPackage.setPartiallyDirectBootAware(true);
+            }
+
+            visibleToEphemeral =
+                    sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToInstantApps, false);
+            if (visibleToEphemeral) {
+                result.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+                parsingPackage.setVisibleToInstantApps(true);
+            }
+        } finally {
+            if (sa != null) {
+                sa.recycle();
+            }
+        }
+
+        if ((parsingPackage.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
+                != 0) {
+            // A heavy-weight application can not have providers in its main process
+            if (result.getProcessName().equals(packageName)) {
+                outError[0] = "Heavy-weight applications can not have providers in main process";
+                return null;
+            }
+        }
+
+        if (cpname == null) {
+            outError[0] = "<provider> does not include authorities attribute";
+            return null;
+        }
+        if (cpname.length() <= 0) {
+            outError[0] = "<provider> has empty authorities attribute";
+            return null;
+        }
+        result.setAuthority(cpname);
+
+        if (!parseProviderTags(parsingPackage, res, parser, visibleToEphemeral, result, outError)) {
+            return null;
+        }
+
+        return result;
+    }
+
+    public static ParsedQueriesIntentInfo parsedParsedQueriesIntentInfo(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser,
+            String[] outError
+    ) throws IOException, XmlPullParserException {
+        ParsedQueriesIntentInfo intentInfo = new ParsedQueriesIntentInfo(
+                parsingPackage.getPackageName(),
+                null
+        );
+        if (!parseIntentInfo(
+                intentInfo,
+                parsingPackage,
+                res,
+                parser,
+                true /*allowGlobs*/,
+                true /*allowAutoVerify*/,
+                outError
+        )) {
+            return null;
+        }
+        return intentInfo;
+    }
+
+    private static boolean parseProviderTags(
+            ParsingPackage parsingPackage,
+            Resources res, XmlResourceParser parser,
+            boolean visibleToEphemeral, ParsedProvider outInfo, String[] outError)
+            throws XmlPullParserException, IOException {
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            if (parser.getName().equals("intent-filter")) {
+                ParsedProviderIntentInfo intent = new ParsedProviderIntentInfo(
+                        parsingPackage.getPackageName(), outInfo.className);
+                if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/,
+                        false /*allowAutoVerify*/,
+                        outError)) {
+                    return false;
+                }
+                if (visibleToEphemeral) {
+                    intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
+                    outInfo.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+                }
+                outInfo.order = Math.max(intent.getOrder(), outInfo.order);
+                outInfo.intents.add(intent);
+
+            } else if (parser.getName().equals("meta-data")) {
+                Bundle metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
+                        outInfo.metaData, outError);
+                if (metaData == null) {
+                    return false;
+                } else {
+                    outInfo.metaData = metaData;
+                }
+
+            } else if (parser.getName().equals("grant-uri-permission")) {
+                TypedArray sa = res.obtainAttributes(parser,
+                        R.styleable.AndroidManifestGrantUriPermission);
+
+                PatternMatcher pa = null;
+
+                String str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestGrantUriPermission_path, 0);
+                if (str != null) {
+                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL);
+                }
+
+                str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0);
+                if (str != null) {
+                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX);
+                }
+
+                str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0);
+                if (str != null) {
+                    pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
+                }
+
+                sa.recycle();
+
+                if (pa != null) {
+                    if (outInfo.uriPermissionPatterns == null) {
+                        outInfo.uriPermissionPatterns = new PatternMatcher[1];
+                        outInfo.uriPermissionPatterns[0] = pa;
+                    } else {
+                        final int N = outInfo.uriPermissionPatterns.length;
+                        PatternMatcher[] newp = new PatternMatcher[N + 1];
+                        System.arraycopy(outInfo.uriPermissionPatterns, 0, newp, 0, N);
+                        newp[N] = pa;
+                        outInfo.uriPermissionPatterns = newp;
+                    }
+                    outInfo.grantUriPermissions = true;
+                } else {
+                    if (!PackageParser.RIGID_PARSER) {
+                        Slog.w(TAG, "Unknown element under <path-permission>: "
+                                + parser.getName() + " at " + parsingPackage.getBaseCodePath()
+                                + " "
+                                + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    } else {
+                        outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
+                        return false;
+                    }
+                }
+                XmlUtils.skipCurrentTag(parser);
+
+            } else if (parser.getName().equals("path-permission")) {
+                TypedArray sa = res.obtainAttributes(parser,
+                        R.styleable.AndroidManifestPathPermission);
+
+                PathPermission pa = null;
+
+                String permission = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestPathPermission_permission, 0);
+                String readPermission = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestPathPermission_readPermission, 0);
+                if (readPermission == null) {
+                    readPermission = permission;
+                }
+                String writePermission = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestPathPermission_writePermission, 0);
+                if (writePermission == null) {
+                    writePermission = permission;
+                }
+
+                boolean havePerm = false;
+                if (readPermission != null) {
+                    readPermission = readPermission.intern();
+                    havePerm = true;
+                }
+                if (writePermission != null) {
+                    writePermission = writePermission.intern();
+                    havePerm = true;
+                }
+
+                if (!havePerm) {
+                    if (!PackageParser.RIGID_PARSER) {
+                        Slog.w(TAG, "No readPermission or writePermssion for <path-permission>: "
+                                + parser.getName() + " at " + parsingPackage.getBaseCodePath()
+                                + " "
+                                + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    } else {
+                        outError[0] = "No readPermission or writePermssion for <path-permission>";
+                        return false;
+                    }
+                }
+
+                String path = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestPathPermission_path, 0);
+                if (path != null) {
+                    pa = new PathPermission(path,
+                            PatternMatcher.PATTERN_LITERAL, readPermission, writePermission);
+                }
+
+                path = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestPathPermission_pathPrefix, 0);
+                if (path != null) {
+                    pa = new PathPermission(path,
+                            PatternMatcher.PATTERN_PREFIX, readPermission, writePermission);
+                }
+
+                path = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestPathPermission_pathPattern, 0);
+                if (path != null) {
+                    pa = new PathPermission(path,
+                            PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission);
+                }
+
+                path = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestPathPermission_pathAdvancedPattern, 0);
+                if (path != null) {
+                    pa = new PathPermission(path,
+                            PatternMatcher.PATTERN_ADVANCED_GLOB, readPermission, writePermission);
+                }
+
+                sa.recycle();
+
+                if (pa != null) {
+                    if (outInfo.pathPermissions == null) {
+                        outInfo.pathPermissions = new PathPermission[1];
+                        outInfo.pathPermissions[0] = pa;
+                    } else {
+                        final int N = outInfo.pathPermissions.length;
+                        PathPermission[] newp = new PathPermission[N + 1];
+                        System.arraycopy(outInfo.pathPermissions, 0, newp, 0, N);
+                        newp[N] = pa;
+                        outInfo.pathPermissions = newp;
+                    }
+                } else {
+                    if (!PackageParser.RIGID_PARSER) {
+                        Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: "
+                                + parser.getName() + " at " + parsingPackage.getBaseCodePath()
+                                + " "
+                                + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
+                    return false;
+                }
+                XmlUtils.skipCurrentTag(parser);
+
+            } else {
+                if (!PackageParser.RIGID_PARSER) {
+                    Slog.w(TAG, "Unknown element under <provider>: "
+                            + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " "
+                            + parser.getPositionDescription());
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+                } else {
+                    outError[0] = "Bad element under <provider>: " + parser.getName();
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    public static ParsedActivity parseActivityAlias(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser,
+            String[] outError)
+            throws XmlPullParserException, IOException {
+        TypedArray sa = res.obtainAttributes(parser,
+                R.styleable.AndroidManifestActivityAlias);
+
+        String targetActivity = sa.getNonConfigurationString(
+                R.styleable.AndroidManifestActivityAlias_targetActivity,
+                Configuration.NATIVE_CONFIG_VERSION);
+        if (targetActivity == null) {
+            outError[0] = "<activity-alias> does not specify android:targetActivity";
+            sa.recycle();
+            return null;
+        }
+
+        String packageName = parsingPackage.getPackageName();
+        targetActivity = ApkParseUtils.buildClassName(packageName, targetActivity);
+        if (targetActivity == null) {
+            outError[0] = "Empty class name in package " + packageName;
+            sa.recycle();
+            return null;
+        }
+
+        ParsedActivity target = null;
+
+        List<ParsedActivity> activities = parsingPackage.getActivities();
+        final int NA = activities.size();
+        for (int i = 0; i < NA; i++) {
+            ParsedActivity t = activities.get(i);
+            if (targetActivity.equals(t.className)) {
+                target = t;
+                break;
+            }
+        }
+
+        if (target == null) {
+            outError[0] = "<activity-alias> target activity " + targetActivity
+                    + " not found in manifest with activities = " + parsingPackage.getActivities()
+                    + ", parsedActivities = " + activities;
+            sa.recycle();
+            return null;
+        }
+
+        ParsedActivity result = new ParsedActivity();
+        result.setPackageNameInternal(target.getPackageName());
+        result.targetActivity = targetActivity;
+        result.configChanges = target.configChanges;
+        result.flags = target.flags;
+        result.privateFlags = target.privateFlags;
+        result.icon = target.icon;
+        result.logo = target.logo;
+        result.banner = target.banner;
+        result.labelRes = target.labelRes;
+        result.nonLocalizedLabel = target.nonLocalizedLabel;
+        result.launchMode = target.launchMode;
+        result.lockTaskLaunchMode = target.lockTaskLaunchMode;
+        result.descriptionRes = target.descriptionRes;
+        result.screenOrientation = target.screenOrientation;
+        result.taskAffinity = target.taskAffinity;
+        result.theme = target.theme;
+        result.softInputMode = target.softInputMode;
+        result.uiOptions = target.uiOptions;
+        result.parentActivityName = target.parentActivityName;
+        result.maxRecents = target.maxRecents;
+        result.windowLayout = target.windowLayout;
+        result.resizeMode = target.resizeMode;
+        result.maxAspectRatio = target.maxAspectRatio;
+        result.hasMaxAspectRatio = target.hasMaxAspectRatio;
+        result.minAspectRatio = target.minAspectRatio;
+        result.hasMinAspectRatio = target.hasMinAspectRatio;
+        result.requestedVrComponent = target.requestedVrComponent;
+        result.directBootAware = target.directBootAware;
+
+        result.setProcessName(parsingPackage.getAppInfoProcessName(), target.getProcessName());
+
+        // Not all attributes from the target ParsedActivity are copied to the alias.
+        // Careful when adding an attribute and determine whether or not it should be copied.
+//        result.enabled = target.enabled;
+//        result.exported = target.exported;
+//        result.permission = target.permission;
+//        result.splitName = target.splitName;
+//        result.documentLaunchMode = target.documentLaunchMode;
+//        result.persistableMode = target.persistableMode;
+//        result.rotationAnimation = target.rotationAnimation;
+//        result.colorMode = target.colorMode;
+//        result.intents.addAll(target.intents);
+//        result.order = target.order;
+//        result.metaData = target.metaData;
+
+        String name = sa.getNonConfigurationString(R.styleable.AndroidManifestActivityAlias_name,
+                0);
+        if (name == null) {
+            outError[0] = "<activity-alias> does not specify android:name";
+            return null;
+        } else {
+            String className = ApkParseUtils.buildClassName(packageName, name);
+            if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+                outError[0] = "<activity-alias> invalid android:name";
+                return null;
+            } else if (className == null) {
+                outError[0] = "Empty class name in package " + packageName;
+                return null;
+            }
+
+            result.className = className;
+        }
+
+        int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+                R.styleable.AndroidManifestActivityAlias_roundIcon, 0) : 0;
+        if (roundIconVal != 0) {
+            result.icon = roundIconVal;
+            result.nonLocalizedLabel = null;
+        } else {
+            int iconVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_icon, 0);
+            if (iconVal != 0) {
+                result.icon = iconVal;
+                result.nonLocalizedLabel = null;
+            }
+        }
+
+        int logoVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_logo, 0);
+        if (logoVal != 0) {
+            result.logo = logoVal;
+        }
+
+        int bannerVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_banner, 0);
+        if (bannerVal != 0) {
+            result.banner = bannerVal;
+        }
+
+        TypedValue v = sa.peekValue(R.styleable.AndroidManifestActivityAlias_label);
+        if (v != null && (result.labelRes = v.resourceId) == 0) {
+            result.nonLocalizedLabel = v.coerceToString();
+        }
+
+        result.setPackageNameInternal(packageName);
+
+        result.descriptionRes = sa.getResourceId(
+                R.styleable.AndroidManifestActivityAlias_description, 0);
+
+        result.enabled = sa.getBoolean(R.styleable.AndroidManifestActivityAlias_enabled, true);
+
+        final boolean setExported = sa.hasValue(
+                R.styleable.AndroidManifestActivityAlias_exported);
+        if (setExported) {
+            result.exported = sa.getBoolean(
+                    R.styleable.AndroidManifestActivityAlias_exported, false);
+        }
+
+        String str;
+        str = sa.getNonConfigurationString(
+                R.styleable.AndroidManifestActivityAlias_permission, 0);
+        if (str != null) {
+            result.setPermission(str);
+        }
+
+        String parentName = sa.getNonConfigurationString(
+                R.styleable.AndroidManifestActivityAlias_parentActivityName,
+                Configuration.NATIVE_CONFIG_VERSION);
+        if (parentName != null) {
+            String parentClassName = ApkParseUtils.buildClassName(result.getPackageName(),
+                    parentName);
+            if (parentClassName == null) {
+                Log.e(TAG, "Activity alias " + result.className +
+                        " specified invalid parentActivityName " + parentName);
+                outError[0] = null;
+            } else {
+                result.parentActivityName = parentClassName;
+            }
+        }
+
+        // TODO add visibleToInstantApps attribute to activity alias
+        final boolean visibleToEphemeral =
+                ((result.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0);
+
+        sa.recycle();
+
+        if (outError[0] != null) {
+            return null;
+        }
+
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+            if (tagName.equals("intent-filter")) {
+                ParsedActivityIntentInfo intent = new ParsedActivityIntentInfo(packageName,
+                        result.className);
+                if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/,
+                        true /*allowAutoVerify*/, outError)) {
+                    return null;
+                }
+                if (intent.countActions() == 0) {
+                    Slog.w(TAG, "No actions in intent filter at "
+                            + parsingPackage.getBaseCodePath() + " "
+                            + parser.getPositionDescription());
+                } else {
+                    result.order = Math.max(intent.getOrder(), result.order);
+                    result.addIntent(intent);
+                }
+                // adjust activity flags when we implicitly expose it via a browsable filter
+                final int visibility = visibleToEphemeral
+                        ? IntentFilter.VISIBILITY_EXPLICIT
+                        : isImplicitlyExposedIntent(intent)
+                                ? IntentFilter.VISIBILITY_IMPLICIT
+                                : IntentFilter.VISIBILITY_NONE;
+                intent.setVisibilityToInstantApp(visibility);
+                if (intent.isVisibleToInstantApp()) {
+                    result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
+                }
+                if (intent.isImplicitlyVisibleToInstantApp()) {
+                    result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
+                }
+            } else if (tagName.equals("meta-data")) {
+                if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
+                        result.metaData,
+                        outError)) == null) {
+                    return null;
+                }
+            } else {
+                if (!PackageParser.RIGID_PARSER) {
+                    Slog.w(TAG, "Unknown element under <activity-alias>: " + tagName
+                            + " at " + parsingPackage.getBaseCodePath() + " "
+                            + parser.getPositionDescription());
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+                } else {
+                    outError[0] = "Bad element under <activity-alias>: " + tagName;
+                    return null;
+                }
+            }
+        }
+
+        if (!setExported) {
+            result.exported = result.intents.size() > 0;
+        }
+
+        return result;
+    }
+
+    public static ParsedPermission parsePermission(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser,
+            String[] outError
+    ) throws IOException, XmlPullParserException {
+        TypedArray sa = null;
+        String packageName = parsingPackage.getPackageName();
+        ParsedPermission result = new ParsedPermission();
+
+        try {
+            sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermission);
+
+            String name = sa.getNonConfigurationString(R.styleable.AndroidManifestPermission_name,
+                    0);
+            if (name == null) {
+                outError[0] = "<permission> does not specify android:name";
+                return null;
+            } else {
+                String className = ApkParseUtils.buildClassName(packageName, name);
+                if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+                    outError[0] = "<permission> invalid android:name";
+                    return null;
+                } else if (className == null) {
+                    outError[0] = "Empty class name in package " + packageName;
+                    return null;
+                }
+
+                result.className = className;
+            }
+
+            int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+                    R.styleable.AndroidManifestPermission_roundIcon, 0) : 0;
+            if (roundIconVal != 0) {
+                result.icon = roundIconVal;
+                result.nonLocalizedLabel = null;
+            } else {
+                int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermission_icon, 0);
+                if (iconVal != 0) {
+                    result.icon = iconVal;
+                    result.nonLocalizedLabel = null;
+                }
+            }
+
+            int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermission_logo, 0);
+            if (logoVal != 0) {
+                result.logo = logoVal;
+            }
+
+            int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermission_banner, 0);
+            if (bannerVal != 0) {
+                result.banner = bannerVal;
+            }
+
+            TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermission_label);
+            if (v != null && (result.labelRes = v.resourceId) == 0) {
+                result.nonLocalizedLabel = v.coerceToString();
+            }
+
+            result.setPackageNameInternal(packageName);
+
+            result.descriptionRes = sa.getResourceId(
+                    R.styleable.AndroidManifestPermission_description, 0);
+
+            if (sa.hasValue(
+                    R.styleable.AndroidManifestPermission_backgroundPermission)) {
+                if ("android".equals(packageName)) {
+                    result.backgroundPermission = sa.getNonResourceString(
+                            R.styleable
+                                    .AndroidManifestPermission_backgroundPermission);
+                } else {
+                    Slog.w(TAG, packageName + " defines a background permission. Only the "
+                            + "'android' package can do that.");
+                }
+            }
+
+            // Note: don't allow this value to be a reference to a resource
+            // that may change.
+            result.setGroup(sa.getNonResourceString(
+                    R.styleable.AndroidManifestPermission_permissionGroup));
+
+            result.requestRes = sa.getResourceId(
+                    R.styleable.AndroidManifestPermission_request, 0);
+
+            result.protectionLevel = sa.getInt(
+                    R.styleable.AndroidManifestPermission_protectionLevel,
+                    PermissionInfo.PROTECTION_NORMAL);
+
+            result.flags = sa.getInt(
+                    R.styleable.AndroidManifestPermission_permissionFlags, 0);
+
+            // For now only platform runtime permissions can be restricted
+            if (!result.isRuntime() || !"android".equals(result.getPackageName())) {
+                result.flags &= ~PermissionInfo.FLAG_HARD_RESTRICTED;
+                result.flags &= ~PermissionInfo.FLAG_SOFT_RESTRICTED;
+            } else {
+                // The platform does not get to specify conflicting permissions
+                if ((result.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0
+                        && (result.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0) {
+                    throw new IllegalStateException("Permission cannot be both soft and hard"
+                            + " restricted: " + result.getName());
+                }
+            }
+
+        } finally {
+            if (sa != null) {
+                sa.recycle();
+            }
+        }
+
+        if (result.protectionLevel == -1) {
+            outError[0] = "<permission> does not specify protectionLevel";
+            return null;
+        }
+
+        result.protectionLevel = PermissionInfo.fixProtectionLevel(result.protectionLevel);
+
+        if (result.getProtectionFlags() != 0) {
+            if ((result.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) == 0
+                    && (result.protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY)
+                    == 0
+                    && (result.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) !=
+                    PermissionInfo.PROTECTION_SIGNATURE) {
+                outError[0] = "<permission>  protectionLevel specifies a non-instant flag but is "
+                        + "not based on signature type";
+                return null;
+            }
+        }
+
+        boolean success = parseAllMetaData(parsingPackage, res, parser,
+                "<permission>", result, outError);
+        if (!success || outError[0] != null) {
+            return null;
+        }
+
+        return result;
+    }
+
+    public static ParsedPermission parsePermissionTree(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser,
+            String[] outError
+    ) throws IOException, XmlPullParserException {
+        TypedArray sa = null;
+        String packageName = parsingPackage.getPackageName();
+        ParsedPermission result = new ParsedPermission();
+
+        try {
+            sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionTree);
+
+            String name = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestPermissionTree_name, 0);
+            if (name == null) {
+                outError[0] = "<permission-tree> does not specify android:name";
+                return null;
+            } else {
+                String className = ApkParseUtils.buildClassName(packageName, name);
+                if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+                    outError[0] = "<permission-tree> invalid android:name";
+                    return null;
+                } else if (className == null) {
+                    outError[0] = "Empty class name in package " + packageName;
+                    return null;
+                }
+
+                result.className = className;
+            }
+
+            int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+                    R.styleable.AndroidManifestPermissionTree_roundIcon, 0) : 0;
+            if (roundIconVal != 0) {
+                result.icon = roundIconVal;
+                result.nonLocalizedLabel = null;
+            } else {
+                int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_icon, 0);
+                if (iconVal != 0) {
+                    result.icon = iconVal;
+                    result.nonLocalizedLabel = null;
+                }
+            }
+
+            int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_logo, 0);
+            if (logoVal != 0) {
+                result.logo = logoVal;
+            }
+
+            int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_banner, 0);
+            if (bannerVal != 0) {
+                result.banner = bannerVal;
+            }
+
+            TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermissionTree_label);
+            if (v != null && (result.labelRes = v.resourceId) == 0) {
+                result.nonLocalizedLabel = v.coerceToString();
+            }
+
+            result.setPackageNameInternal(packageName);
+        } finally {
+            if (sa != null) {
+                sa.recycle();
+            }
+        }
+
+        int index = result.getName().indexOf('.');
+        if (index > 0) {
+            index = result.getName().indexOf('.', index + 1);
+        }
+        if (index < 0) {
+            outError[0] =
+                    "<permission-tree> name has less than three segments: " + result.getName();
+            return null;
+        }
+
+        result.descriptionRes = 0;
+        result.requestRes = 0;
+        result.protectionLevel = PermissionInfo.PROTECTION_NORMAL;
+        result.tree = true;
+
+        boolean success = parseAllMetaData(parsingPackage, res, parser,
+                "<permission-tree>", result, outError);
+        if (!success || outError[0] != null) {
+            return null;
+        }
+
+        return result;
+    }
+
+    public static ParsedPermissionGroup parsePermissionGroup(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser,
+            String[] outError
+    ) throws IOException, XmlPullParserException {
+        TypedArray sa = null;
+        String packageName = parsingPackage.getPackageName();
+        ParsedPermissionGroup result = new ParsedPermissionGroup();
+
+        try {
+            sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionGroup);
+
+            String name = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestPermissionGroup_name, 0);
+            if (name == null) {
+                outError[0] = "<permission> does not specify android:name";
+                return null;
+            } else {
+                String className = ApkParseUtils.buildClassName(packageName, name);
+                if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+                    outError[0] = "<permission> invalid android:name";
+                    return null;
+                } else if (className == null) {
+                    outError[0] = "Empty class name in package " + packageName;
+                    return null;
+                }
+
+                result.className = className;
+            }
+
+            int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+                    R.styleable.AndroidManifestPermissionGroup_roundIcon, 0) : 0;
+            if (roundIconVal != 0) {
+                result.icon = roundIconVal;
+                result.nonLocalizedLabel = null;
+            } else {
+                int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_icon, 0);
+                if (iconVal != 0) {
+                    result.icon = iconVal;
+                    result.nonLocalizedLabel = null;
+                }
+            }
+
+            int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_logo, 0);
+            if (logoVal != 0) {
+                result.logo = logoVal;
+            }
+
+            int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_banner, 0);
+            if (bannerVal != 0) {
+                result.banner = bannerVal;
+            }
+
+            TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermissionGroup_label);
+            if (v != null && (result.labelRes = v.resourceId) == 0) {
+                result.nonLocalizedLabel = v.coerceToString();
+            }
+
+            result.setPackageNameInternal(packageName);
+
+            result.descriptionRes = sa.getResourceId(
+                    R.styleable.AndroidManifestPermissionGroup_description, 0);
+
+            result.requestDetailResourceId = sa.getResourceId(
+                    R.styleable.AndroidManifestPermissionGroup_requestDetail, 0);
+            result.backgroundRequestResourceId = sa.getResourceId(
+                    R.styleable.AndroidManifestPermissionGroup_backgroundRequest,
+                    0);
+            result.backgroundRequestDetailResourceId = sa.getResourceId(
+                    R.styleable
+                            .AndroidManifestPermissionGroup_backgroundRequestDetail, 0);
+
+            result.requestRes = sa.getResourceId(
+                    R.styleable.AndroidManifestPermissionGroup_request, 0);
+            result.flags = sa.getInt(
+                    R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags,
+                    0);
+            result.priority = sa.getInt(
+                    R.styleable.AndroidManifestPermissionGroup_priority, 0);
+
+        } finally {
+            if (sa != null) {
+                sa.recycle();
+            }
+        }
+
+        boolean success = parseAllMetaData(parsingPackage, res, parser,
+                "<permission-group>", result, outError);
+        if (!success || outError[0] != null) {
+            return null;
+        }
+
+        return result;
+    }
+
+    public static ParsedInstrumentation parseInstrumentation(
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser,
+            String[] outError
+    ) throws IOException, XmlPullParserException {
+        TypedArray sa = null;
+        String packageName = parsingPackage.getPackageName();
+        ParsedInstrumentation result = new ParsedInstrumentation();
+
+        try {
+            sa = res.obtainAttributes(parser, R.styleable.AndroidManifestInstrumentation);
+
+            // TODO(b/135203078): Re-share all of the configuration for this. ParseComponentArgs was
+            //  un-used for this, but can be adjusted and re-added to share all the initial result
+            //  parsing for icon/logo/name/etc in all of these parse methods.
+            String name = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestInstrumentation_name, 0);
+            if (name == null) {
+                outError[0] = "<instrumentation> does not specify android:name";
+                return null;
+            } else {
+                String className = ApkParseUtils.buildClassName(packageName, name);
+                if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
+                    outError[0] = "<instrumentation> invalid android:name";
+                    return null;
+                } else if (className == null) {
+                    outError[0] = "Empty class name in package " + packageName;
+                    return null;
+                }
+
+                result.className = className;
+            }
+
+            int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+                    R.styleable.AndroidManifestInstrumentation_roundIcon, 0) : 0;
+            if (roundIconVal != 0) {
+                result.icon = roundIconVal;
+                result.nonLocalizedLabel = null;
+            } else {
+                int iconVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_icon, 0);
+                if (iconVal != 0) {
+                    result.icon = iconVal;
+                    result.nonLocalizedLabel = null;
+                }
+            }
+
+            int logoVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_logo, 0);
+            if (logoVal != 0) {
+                result.logo = logoVal;
+            }
+
+            int bannerVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_banner, 0);
+            if (bannerVal != 0) {
+                result.banner = bannerVal;
+            }
+
+            TypedValue v = sa.peekValue(R.styleable.AndroidManifestInstrumentation_label);
+            if (v != null && (result.labelRes = v.resourceId) == 0) {
+                result.nonLocalizedLabel = v.coerceToString();
+            }
+
+            result.setPackageNameInternal(packageName);
+
+            String str;
+            // Note: don't allow this value to be a reference to a resource
+            // that may change.
+            str = sa.getNonResourceString(R.styleable.AndroidManifestInstrumentation_targetPackage);
+            result.setTargetPackage(str);
+
+            str = sa.getNonResourceString(
+                    R.styleable.AndroidManifestInstrumentation_targetProcesses);
+            result.setTargetProcesses(str);
+            result.handleProfiling = sa.getBoolean(
+                    R.styleable.AndroidManifestInstrumentation_handleProfiling, false);
+            result.functionalTest = sa.getBoolean(
+                    R.styleable.AndroidManifestInstrumentation_functionalTest, false);
+
+        } finally {
+            if (sa != null) {
+                sa.recycle();
+            }
+        }
+
+        boolean success = parseAllMetaData(parsingPackage, res, parser,
+                "<instrumentation>", result, outError);
+        if (!success || outError[0] != null) {
+            return null;
+        }
+
+        return result;
+    }
+
+    public static ActivityInfo.WindowLayout parseLayout(Resources res, AttributeSet attrs) {
+        TypedArray sw = res.obtainAttributes(attrs,
+                R.styleable.AndroidManifestLayout);
+        int width = -1;
+        float widthFraction = -1f;
+        int height = -1;
+        float heightFraction = -1f;
+        final int widthType = sw.getType(
+                R.styleable.AndroidManifestLayout_defaultWidth);
+        if (widthType == TypedValue.TYPE_FRACTION) {
+            widthFraction = sw.getFraction(
+                    R.styleable.AndroidManifestLayout_defaultWidth,
+                    1, 1, -1);
+        } else if (widthType == TypedValue.TYPE_DIMENSION) {
+            width = sw.getDimensionPixelSize(
+                    R.styleable.AndroidManifestLayout_defaultWidth,
+                    -1);
+        }
+        final int heightType = sw.getType(
+                R.styleable.AndroidManifestLayout_defaultHeight);
+        if (heightType == TypedValue.TYPE_FRACTION) {
+            heightFraction = sw.getFraction(
+                    R.styleable.AndroidManifestLayout_defaultHeight,
+                    1, 1, -1);
+        } else if (heightType == TypedValue.TYPE_DIMENSION) {
+            height = sw.getDimensionPixelSize(
+                    R.styleable.AndroidManifestLayout_defaultHeight,
+                    -1);
+        }
+        int gravity = sw.getInt(
+                R.styleable.AndroidManifestLayout_gravity,
+                Gravity.CENTER);
+        int minWidth = sw.getDimensionPixelSize(
+                R.styleable.AndroidManifestLayout_minWidth,
+                -1);
+        int minHeight = sw.getDimensionPixelSize(
+                R.styleable.AndroidManifestLayout_minHeight,
+                -1);
+        sw.recycle();
+        return new ActivityInfo.WindowLayout(width, widthFraction,
+                height, heightFraction, gravity, minWidth, minHeight);
+    }
+
+    public static boolean parseIntentInfo(
+            ParsedIntentInfo intentInfo,
+            ParsingPackage parsingPackage,
+            Resources res, XmlResourceParser parser, boolean allowGlobs,
+            boolean allowAutoVerify, String[] outError
+    ) throws XmlPullParserException, IOException {
+        TypedArray sa = res.obtainAttributes(parser,
+                R.styleable.AndroidManifestIntentFilter);
+
+        int priority = sa.getInt(
+                R.styleable.AndroidManifestIntentFilter_priority, 0);
+        intentInfo.setPriority(priority);
+
+        int order = sa.getInt(
+                R.styleable.AndroidManifestIntentFilter_order, 0);
+        intentInfo.setOrder(order);
+
+        TypedValue v = sa.peekValue(
+                R.styleable.AndroidManifestIntentFilter_label);
+        if (v != null && (intentInfo.labelRes = v.resourceId) == 0) {
+            intentInfo.nonLocalizedLabel = v.coerceToString();
+        }
+
+        int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
+                R.styleable.AndroidManifestIntentFilter_roundIcon, 0) : 0;
+        if (roundIconVal != 0) {
+            intentInfo.icon = roundIconVal;
+        } else {
+            intentInfo.icon = sa.getResourceId(
+                    R.styleable.AndroidManifestIntentFilter_icon, 0);
+        }
+
+        if (allowAutoVerify) {
+            intentInfo.setAutoVerify(sa.getBoolean(
+                    R.styleable.AndroidManifestIntentFilter_autoVerify,
+                    false));
+        }
+
+        sa.recycle();
+
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String nodeName = parser.getName();
+            if (nodeName.equals("action")) {
+                String value = parser.getAttributeValue(
+                        PackageParser.ANDROID_RESOURCES, "name");
+                if (TextUtils.isEmpty(value)) {
+                    outError[0] = "No value supplied for <android:name>";
+                    return false;
+                }
+                XmlUtils.skipCurrentTag(parser);
+
+                intentInfo.addAction(value);
+            } else if (nodeName.equals("category")) {
+                String value = parser.getAttributeValue(
+                        PackageParser.ANDROID_RESOURCES, "name");
+                if (TextUtils.isEmpty(value)) {
+                    outError[0] = "No value supplied for <android:name>";
+                    return false;
+                }
+                XmlUtils.skipCurrentTag(parser);
+
+                intentInfo.addCategory(value);
+
+            } else if (nodeName.equals("data")) {
+                sa = res.obtainAttributes(parser,
+                        R.styleable.AndroidManifestData);
+
+                String str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestData_mimeType, 0);
+                if (str != null) {
+                    try {
+                        intentInfo.addRawDataType(str);
+                    } catch (IntentFilter.MalformedMimeTypeException e) {
+                        outError[0] = e.toString();
+                        sa.recycle();
+                        return false;
+                    }
+                }
+
+                str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestData_scheme, 0);
+                if (str != null) {
+                    intentInfo.addDataScheme(str);
+                }
+
+                str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestData_ssp, 0);
+                if (str != null) {
+                    intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_LITERAL);
+                }
+
+                str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestData_sspPrefix, 0);
+                if (str != null) {
+                    intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_PREFIX);
+                }
+
+                str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestData_sspPattern, 0);
+                if (str != null) {
+                    if (!allowGlobs) {
+                        outError[0] = "sspPattern not allowed here; ssp must be literal";
+                        return false;
+                    }
+                    intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
+                }
+
+                String host = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestData_host, 0);
+                String port = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestData_port, 0);
+                if (host != null) {
+                    intentInfo.addDataAuthority(host, port);
+                }
+
+                str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestData_path, 0);
+                if (str != null) {
+                    intentInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL);
+                }
+
+                str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestData_pathPrefix, 0);
+                if (str != null) {
+                    intentInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX);
+                }
+
+                str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestData_pathPattern, 0);
+                if (str != null) {
+                    if (!allowGlobs) {
+                        outError[0] = "pathPattern not allowed here; path must be literal";
+                        return false;
+                    }
+                    intentInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
+                }
+
+                str = sa.getNonConfigurationString(
+                        R.styleable.AndroidManifestData_pathAdvancedPattern, 0);
+                if (str != null) {
+                    if (!allowGlobs) {
+                        outError[0] = "pathAdvancedPattern not allowed here; path must be literal";
+                        return false;
+                    }
+                    intentInfo.addDataPath(str, PatternMatcher.PATTERN_ADVANCED_GLOB);
+                }
+
+                sa.recycle();
+                XmlUtils.skipCurrentTag(parser);
+            } else if (!PackageParser.RIGID_PARSER) {
+                Slog.w(TAG, "Unknown element under <intent-filter>: "
+                        + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " "
+                        + parser.getPositionDescription());
+                XmlUtils.skipCurrentTag(parser);
+            } else {
+                outError[0] = "Bad element under <intent-filter>: " + parser.getName();
+                return false;
+            }
+        }
+
+        intentInfo.hasDefault = intentInfo.hasCategory(Intent.CATEGORY_DEFAULT);
+
+        if (PackageParser.DEBUG_PARSER) {
+            final StringBuilder cats = new StringBuilder("Intent d=");
+            cats.append(intentInfo.hasDefault);
+            cats.append(", cat=");
+
+            final Iterator<String> it = intentInfo.categoriesIterator();
+            if (it != null) {
+                while (it.hasNext()) {
+                    cats.append(' ');
+                    cats.append(it.next());
+                }
+            }
+            Slog.d(TAG, cats.toString());
+        }
+
+        return true;
+    }
+
+    private static boolean parseAllMetaData(
+            ParsingPackage parsingPackage,
+            Resources res, XmlResourceParser parser, String tag,
+            ParsedComponent outInfo,
+            String[] outError
+    ) throws XmlPullParserException, IOException {
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            if (parser.getName().equals("meta-data")) {
+                if ((outInfo.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
+                        outInfo.metaData, outError)) == null) {
+                    return false;
+                }
+            } else {
+                if (!PackageParser.RIGID_PARSER) {
+                    Slog.w(TAG, "Unknown element under " + tag + ": "
+                            + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " "
+                            + parser.getPositionDescription());
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+                } else {
+                    outError[0] = "Bad element under " + tag + ": " + parser.getName();
+                }
+            }
+        }
+
+        return true;
+    }
+
+    public static boolean isImplicitlyExposedIntent(IntentFilter intent) {
+        return intent.hasCategory(Intent.CATEGORY_BROWSABLE)
+                || intent.hasAction(Intent.ACTION_SEND)
+                || intent.hasAction(Intent.ACTION_SENDTO)
+                || intent.hasAction(Intent.ACTION_SEND_MULTIPLE);
+    }
+}
diff --git a/core/java/android/content/pm/parsing/PackageImpl.java b/core/java/android/content/pm/parsing/PackageImpl.java
new file mode 100644
index 0000000..0e736d5
--- /dev/null
+++ b/core/java/android/content/pm/parsing/PackageImpl.java
@@ -0,0 +1,3254 @@
+/*
+ * 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.content.pm.parsing;
+
+import static android.os.Build.VERSION_CODES.DONUT;
+
+import static java.util.Collections.emptyMap;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.FeatureGroupInfo;
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
+import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
+import android.content.pm.parsing.ComponentParseUtils.ParsedService;
+import android.content.res.TypedArray;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Parcel;
+import android.os.UserHandle;
+import android.os.storage.StorageManager;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.SparseArray;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
+import com.android.server.SystemConfig;
+
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * The backing data for a package that was parsed from disk.
+ *
+ * TODO(b/135203078): Convert Lists used as sets into Sets, to better express intended use case
+ * TODO(b/135203078): Field nullability annotations
+ * TODO(b/135203078): Convert = 1 fields into Booleans
+ * TODO(b/135203078): Make all lists nullable and Collections.unmodifiable immutable when returned.
+ *   Prefer add/set methods if adding is necessary.
+ * TODO(b/135203078): Consider comments to disable auto-format and single-line, single-space all the
+ *   get/set methods to make this class far more compact. Maybe even separate some logic into parent
+ *   classes, assuming there is no overhead.
+ * TODO(b/135203078): Copy documentation from PackageParser#Package for the relevant fields included
+ *   here. Should clarify and clean up any differences. Also consider renames if it helps make
+ *   things clearer.
+ * TODO(b/135203078): Intern all possibl e String values? Initial refactor just mirrored old
+ *   behavior.
+ *
+ * @hide
+ */
+public final class PackageImpl implements ParsingPackage, ParsedPackage, AndroidPackage,
+        AndroidPackageWrite {
+
+    private static final String TAG = "PackageImpl";
+
+    // Resource boolean are -1, so 1 means we don't know the value.
+    private int supportsSmallScreens = 1;
+    private int supportsNormalScreens = 1;
+    private int supportsLargeScreens = 1;
+    private int supportsXLargeScreens = 1;
+    private int resizeable = 1;
+    private int anyDensity = 1;
+
+    private long[] lastPackageUsageTimeInMills =
+            new long[PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT];
+
+    private int versionCode;
+    private int versionCodeMajor;
+    private int baseRevisionCode;
+    private String versionName;
+
+    private boolean coreApp;
+    private int compileSdkVersion;
+    private String compileSdkVersionCodename;
+
+    private String packageName;
+    private String realPackage;
+    private String manifestPackageName;
+    private String baseCodePath;
+
+    private boolean requiredForAllUsers;
+    private String restrictedAccountType;
+    private String requiredAccountType;
+
+    private boolean baseHardwareAccelerated;
+
+    private String overlayTarget;
+    private String overlayTargetName;
+    private String overlayCategory;
+    private int overlayPriority;
+    private boolean overlayIsStatic;
+    private Map<String, String> overlayables = emptyMap();
+
+    private String staticSharedLibName;
+    private long staticSharedLibVersion;
+    private ArrayList<String> libraryNames;
+    private ArrayList<String> usesLibraries;
+    private ArrayList<String> usesOptionalLibraries;
+
+    private ArrayList<String> usesStaticLibraries;
+    private long[] usesStaticLibrariesVersions;
+    private String[][] usesStaticLibrariesCertDigests;
+
+    private String sharedUserId;
+
+    private int sharedUserLabel;
+    private ArrayList<ConfigurationInfo> configPreferences;
+    private ArrayList<FeatureInfo> reqFeatures;
+    private ArrayList<FeatureGroupInfo> featureGroups;
+
+    private byte[] restrictUpdateHash;
+
+    private ArrayList<String> originalPackages;
+    private ArrayList<String> adoptPermissions;
+
+    private ArrayList<String> requestedPermissions;
+    private ArrayList<String> implicitPermissions;
+
+    private ArraySet<String> upgradeKeySets;
+    private Map<String, ArraySet<PublicKey>> keySetMapping;
+
+    private ArrayList<String> protectedBroadcasts;
+
+    @Nullable
+    private ArrayList<ComponentParseUtils.ParsedActivity> activities;
+
+    @Nullable
+    private ArrayList<ComponentParseUtils.ParsedActivity> receivers;
+
+    @Nullable
+    private ArrayList<ComponentParseUtils.ParsedService> services;
+
+    @Nullable
+    private ArrayList<ComponentParseUtils.ParsedProvider> providers;
+
+    @Nullable
+    private ArrayList<ComponentParseUtils.ParsedPermission> permissions;
+
+    @Nullable
+    private ArrayList<ComponentParseUtils.ParsedPermissionGroup> permissionGroups;
+
+    @Nullable
+    private ArrayList<ComponentParseUtils.ParsedInstrumentation> instrumentations;
+
+    private ArrayList<ParsedActivityIntentInfo> preferredActivityFilters;
+
+    private Bundle appMetaData;
+
+    private String volumeUuid;
+    private String applicationVolumeUuid;
+    private PackageParser.SigningDetails signingDetails;
+
+    private String codePath;
+
+    private boolean use32BitAbi;
+    private boolean visibleToInstantApps;
+
+    private String cpuAbiOverride;
+
+    private boolean isStub;
+
+    // TODO(b/135203078): Remove, should be unused
+    private int preferredOrder;
+
+    private boolean forceQueryable;
+
+    @Nullable
+    private ArrayList<Intent> queriesIntents;
+
+    @Nullable
+    private ArrayList<String> queriesPackages;
+
+    private String[] splitClassLoaderNames;
+    private String[] splitCodePaths;
+    private SparseArray<int[]> splitDependencies;
+    private int[] splitFlags;
+    private String[] splitNames;
+    private int[] splitRevisionCodes;
+
+    // TODO(b/135203078): Audit applicationInfo.something usages, which may be different from
+    //  package.something usages. There were differing cases of package.field = versus
+    //  package.appInfo.field =. This class assumes some obvious ones, like packageName,
+    //  were collapsible, but kept the following separate.
+
+    private String applicationInfoBaseResourcePath;
+    private String applicationInfoCodePath;
+    private String applicationInfoResourcePath;
+    private String[] applicationInfoSplitResourcePaths;
+
+    private String appComponentFactory;
+    private String backupAgentName;
+    private int banner;
+    private int category;
+    private String classLoaderName;
+    private String className;
+    private int compatibleWidthLimitDp;
+    private String credentialProtectedDataDir;
+    private String dataDir;
+    private int descriptionRes;
+    private String deviceProtectedDataDir;
+    private boolean enabled;
+    private int flags;
+    private int fullBackupContent;
+    private boolean hiddenUntilInstalled;
+    private int icon;
+    private int iconRes;
+    private int installLocation = PackageParser.PARSE_DEFAULT_INSTALL_LOCATION;
+    private int labelRes;
+    private int largestWidthLimitDp;
+    private int logo;
+    private String manageSpaceActivityName;
+    private float maxAspectRatio;
+    private float minAspectRatio;
+    private int minSdkVersion;
+    private String name;
+    private String nativeLibraryDir;
+    private String nativeLibraryRootDir;
+    private boolean nativeLibraryRootRequiresIsa;
+    private int networkSecurityConfigRes;
+    private CharSequence nonLocalizedLabel;
+    private String permission;
+    private String primaryCpuAbi;
+    private int privateFlags;
+    private String processName;
+    private int requiresSmallestWidthDp;
+    private int roundIconRes;
+    private String secondaryCpuAbi;
+    private String secondaryNativeLibraryDir;
+    private String seInfo;
+    private String seInfoUser;
+    private int targetSandboxVersion;
+    private int targetSdkVersion;
+    private String taskAffinity;
+    private int theme;
+    private int uid = -1;
+    private int uiOptions;
+    private String[] usesLibraryFiles;
+    private List<SharedLibraryInfo> usesLibraryInfos;
+    private String zygotePreloadName;
+
+    @VisibleForTesting
+    public PackageImpl(
+            String packageName,
+            String baseCodePath,
+            TypedArray manifestArray,
+            boolean isCoreApp
+    ) {
+        this.packageName = TextUtils.safeIntern(packageName);
+        this.manifestPackageName = this.packageName;
+        this.baseCodePath = baseCodePath;
+
+        this.versionCode = manifestArray.getInteger(R.styleable.AndroidManifest_versionCode, 0);
+        this.versionCodeMajor = manifestArray.getInteger(
+                R.styleable.AndroidManifest_versionCodeMajor, 0);
+        this.baseRevisionCode = manifestArray.getInteger(R.styleable.AndroidManifest_revisionCode,
+                0);
+        setVersionName(manifestArray.getNonConfigurationString(
+                R.styleable.AndroidManifest_versionName, 0));
+        this.coreApp = isCoreApp;
+
+        this.compileSdkVersion = manifestArray.getInteger(
+                R.styleable.AndroidManifest_compileSdkVersion, 0);
+        setCompileSdkVersionCodename(manifestArray.getNonConfigurationString(
+                R.styleable.AndroidManifest_compileSdkVersionCodename, 0));
+    }
+
+    private PackageImpl(String packageName) {
+        this.packageName = TextUtils.safeIntern(packageName);
+        this.manifestPackageName = this.packageName;
+    }
+
+    @VisibleForTesting
+    public static ParsingPackage forParsing(String packageName) {
+        return new PackageImpl(packageName);
+    }
+
+    @VisibleForTesting
+    public static ParsingPackage forParsing(
+            String packageName,
+            String baseCodePath,
+            TypedArray manifestArray,
+            boolean isCoreApp) {
+        return new PackageImpl(packageName, baseCodePath, manifestArray, isCoreApp);
+    }
+
+    /**
+     * Mock an unavailable {@link AndroidPackage} to use when removing a package from the system.
+     * This can occur if the package was installed on a storage device that has since been removed.
+     * Since the infrastructure uses {@link AndroidPackage}, but for this case only cares about
+     * volumeUuid, just fake it rather than having separate method paths.
+     */
+    public static AndroidPackage buildFakeForDeletion(String packageName, String volumeUuid) {
+        return new PackageImpl(packageName)
+                .setVolumeUuid(volumeUuid)
+                .hideAsParsed()
+                .hideAsFinal();
+    }
+
+    @Override
+    public ParsedPackage hideAsParsed() {
+        return this;
+    }
+
+    @Override
+    public AndroidPackage hideAsFinal() {
+        updateFlags();
+        return this;
+    }
+
+    @Override
+    @Deprecated
+    public AndroidPackageWrite mutate() {
+        return this;
+    }
+
+    private void updateFlags() {
+        if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
+                && targetSdkVersion
+                >= Build.VERSION_CODES.DONUT)) {
+            this.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS;
+        }
+        if (supportsNormalScreens != 0) {
+            this.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS;
+        }
+        if (supportsLargeScreens < 0 || (supportsLargeScreens > 0
+                && targetSdkVersion
+                >= Build.VERSION_CODES.DONUT)) {
+            this.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
+        }
+        if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0
+                && targetSdkVersion
+                >= Build.VERSION_CODES.GINGERBREAD)) {
+            this.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
+        }
+        if (resizeable < 0 || (resizeable > 0
+                && targetSdkVersion
+                >= Build.VERSION_CODES.DONUT)) {
+            this.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS;
+        }
+        if (anyDensity < 0 || (anyDensity > 0
+                && targetSdkVersion
+                >= Build.VERSION_CODES.DONUT)) {
+            this.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
+        }
+    }
+
+    @Override
+    public boolean usesCompatibilityMode() {
+        int flags = 0;
+
+        if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
+                && targetSdkVersion
+                >= Build.VERSION_CODES.DONUT)) {
+            flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS;
+        }
+        if (supportsNormalScreens != 0) {
+            flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS;
+        }
+        if (supportsLargeScreens < 0 || (supportsLargeScreens > 0
+                && targetSdkVersion
+                >= Build.VERSION_CODES.DONUT)) {
+            flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
+        }
+        if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0
+                && targetSdkVersion
+                >= Build.VERSION_CODES.GINGERBREAD)) {
+            flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
+        }
+        if (resizeable < 0 || (resizeable > 0
+                && targetSdkVersion
+                >= Build.VERSION_CODES.DONUT)) {
+            flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS;
+        }
+        if (anyDensity < 0 || (anyDensity > 0
+                && targetSdkVersion
+                >= Build.VERSION_CODES.DONUT)) {
+            flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
+        }
+
+        return targetSdkVersion < DONUT
+                || (flags & (ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS
+                        | ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS
+                        | ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS
+                        | ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS
+                        | ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES
+                        | ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS)) == 0;
+    }
+
+    @Override
+    public String getBaseCodePath() {
+        return baseCodePath;
+    }
+
+    @Override
+    public int getTargetSdkVersion() {
+        return targetSdkVersion;
+    }
+
+    @Override
+    public String getPackageName() {
+        return packageName;
+    }
+
+    @Override
+    public String getProcessName() {
+        return processName;
+    }
+
+    @Override
+    public String getPermission() {
+        return permission;
+    }
+
+    @Override
+    public String getStaticSharedLibName() {
+        return staticSharedLibName;
+    }
+
+    @Override
+    public long getStaticSharedLibVersion() {
+        return staticSharedLibVersion;
+    }
+
+    @Override
+    public String getSharedUserId() {
+        return sharedUserId;
+    }
+
+    @Override
+    public List<String> getRequestedPermissions() {
+        return requestedPermissions == null ? Collections.emptyList() : requestedPermissions;
+    }
+
+    @Nullable
+    @Override
+    public List<ParsedInstrumentation> getInstrumentations() {
+        return instrumentations;
+    }
+
+    @Override
+    public Map<String, ArraySet<PublicKey>> getKeySetMapping() {
+        return keySetMapping == null ? emptyMap() : keySetMapping;
+    }
+
+    @Override
+    public float getMaxAspectRatio() {
+        return maxAspectRatio;
+    }
+
+    @Override
+    public float getMinAspectRatio() {
+        return minAspectRatio;
+    }
+
+    @NonNull
+    @Override
+    public List<String> getLibraryNames() {
+        return libraryNames == null ? Collections.emptyList() : libraryNames;
+    }
+
+    @Override
+    public List<ParsedActivity> getActivities() {
+        return activities == null ? Collections.emptyList()
+                : activities;
+    }
+
+    @Override
+    public Bundle getAppMetaData() {
+        return appMetaData;
+    }
+
+    @Nullable
+    @Override
+    public List<String> getUsesLibraries() {
+        return usesLibraries;
+    }
+
+    @Nullable
+    @Override
+    public List<String> getUsesStaticLibraries() {
+        return usesStaticLibraries;
+    }
+
+    @Override
+    public boolean isBaseHardwareAccelerated() {
+        return baseHardwareAccelerated;
+    }
+
+    @Override
+    public int getUiOptions() {
+        return uiOptions;
+    }
+
+    // TODO(b/135203078): Checking flags directly can be error prone,
+    //  consider separate interface methods?
+    @Override
+    public int getFlags() {
+        return flags;
+    }
+
+    // TODO(b/135203078): Checking flags directly can be error prone,
+    //  consider separate interface methods?
+    @Override
+    public int getPrivateFlags() {
+        return privateFlags;
+    }
+
+    @Override
+    public String getTaskAffinity() {
+        return taskAffinity;
+    }
+
+    @Nullable
+    @Override
+    public List<String> getOriginalPackages() {
+        return originalPackages;
+    }
+
+    @Override
+    public PackageParser.SigningDetails getSigningDetails() {
+        return signingDetails;
+    }
+
+    @Override
+    public String getVolumeUuid() {
+        return volumeUuid;
+    }
+
+    @Nullable
+    @Override
+    public List<ParsedPermissionGroup> getPermissionGroups() {
+        return permissionGroups;
+    }
+
+    @Nullable
+    @Override
+    public List<ParsedPermission> getPermissions() {
+        return permissions;
+    }
+
+    @Override
+    public String getCpuAbiOverride() {
+        return cpuAbiOverride;
+    }
+
+    @Override
+    public String getPrimaryCpuAbi() {
+        return primaryCpuAbi;
+    }
+
+    @Override
+    public String getSecondaryCpuAbi() {
+        return secondaryCpuAbi;
+    }
+
+    @Override
+    public boolean isUse32BitAbi() {
+        return use32BitAbi;
+    }
+
+    @Override
+    public boolean isForceQueryable() {
+        return forceQueryable;
+    }
+
+    @Override
+    public String getCodePath() {
+        return codePath;
+    }
+
+    @Override
+    public String getNativeLibraryDir() {
+        return nativeLibraryDir;
+    }
+
+    @Override
+    public String getNativeLibraryRootDir() {
+        return nativeLibraryRootDir;
+    }
+
+    @Override
+    public boolean isNativeLibraryRootRequiresIsa() {
+        return nativeLibraryRootRequiresIsa;
+    }
+
+    // TODO(b/135203078): Does nothing, remove?
+    @Override
+    public int getPreferredOrder() {
+        return preferredOrder;
+    }
+
+    @Override
+    public long getLongVersionCode() {
+        return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode);
+    }
+
+    @Override
+    public PackageImpl setIsOverlay(boolean isOverlay) {
+        this.privateFlags = isOverlay
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setExternalStorage(boolean externalStorage) {
+        this.flags = externalStorage
+                ? this.flags | ApplicationInfo.FLAG_EXTERNAL_STORAGE
+                : this.flags & ~ApplicationInfo.FLAG_EXTERNAL_STORAGE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setIsolatedSplitLoading(boolean isolatedSplitLoading) {
+        this.privateFlags = isolatedSplitLoading
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING;
+        return this;
+    }
+
+    @Override
+    public PackageImpl sortActivities() {
+        Collections.sort(this.activities, (a1, a2) -> Integer.compare(a2.order, a1.order));
+        return this;
+    }
+
+    @Override
+    public PackageImpl sortReceivers() {
+        Collections.sort(this.receivers, (a1, a2) -> Integer.compare(a2.order, a1.order));
+        return this;
+    }
+
+    @Override
+    public PackageImpl sortServices() {
+        Collections.sort(this.services, (a1, a2) -> Integer.compare(a2.order, a1.order));
+        return this;
+    }
+
+    @Override
+    public PackageImpl setBaseRevisionCode(int baseRevisionCode) {
+        this.baseRevisionCode = baseRevisionCode;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setPreferredOrder(int preferredOrder) {
+        this.preferredOrder = preferredOrder;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setVersionName(String versionName) {
+        this.versionName = TextUtils.safeIntern(versionName);
+        return this;
+    }
+
+    @Override
+    public ParsingPackage setCompileSdkVersion(int compileSdkVersion) {
+        this.compileSdkVersion = compileSdkVersion;
+        return this;
+    }
+
+    @Override
+    public ParsingPackage setCompileSdkVersionCodename(String compileSdkVersionCodename) {
+        this.compileSdkVersionCodename = TextUtils.safeIntern(compileSdkVersionCodename);
+        return this;
+    }
+
+    @Override
+    public PackageImpl setMaxAspectRatio(float maxAspectRatio) {
+        this.maxAspectRatio = maxAspectRatio;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setMinAspectRatio(float minAspectRatio) {
+        this.minAspectRatio = minAspectRatio;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setMinSdkVersion(int minSdkVersion) {
+        this.minSdkVersion = minSdkVersion;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setTargetSdkVersion(int targetSdkVersion) {
+        this.targetSdkVersion = targetSdkVersion;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setRealPackage(String realPackage) {
+        this.realPackage = realPackage;
+        return this;
+    }
+
+    @Override
+    public PackageImpl addConfigPreference(ConfigurationInfo configPreference) {
+        this.configPreferences = ArrayUtils.add(this.configPreferences, configPreference);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addReqFeature(FeatureInfo reqFeature) {
+        this.reqFeatures = ArrayUtils.add(this.reqFeatures, reqFeature);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addFeatureGroup(FeatureGroupInfo featureGroup) {
+        this.featureGroups = ArrayUtils.add(this.featureGroups, featureGroup);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addProtectedBroadcast(String protectedBroadcast) {
+        if (this.protectedBroadcasts == null
+                || !this.protectedBroadcasts.contains(protectedBroadcast)) {
+            this.protectedBroadcasts = ArrayUtils.add(this.protectedBroadcasts,
+                    TextUtils.safeIntern(protectedBroadcast));
+        }
+        return this;
+    }
+
+    @Override
+    public PackageImpl addInstrumentation(ParsedInstrumentation instrumentation) {
+        this.instrumentations = ArrayUtils.add(this.instrumentations, instrumentation);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addOriginalPackage(String originalPackage) {
+        this.originalPackages = ArrayUtils.add(this.originalPackages, originalPackage);
+        return this;
+    }
+
+    @Override
+    public ParsingPackage addOverlayable(String overlayableName, String actorName) {
+        this.overlayables = CollectionUtils.add(this.overlayables,
+                TextUtils.safeIntern(overlayableName), TextUtils.safeIntern(actorName));
+        return this;
+    }
+
+    @Override
+    public PackageImpl addAdoptPermission(String adoptPermission) {
+        this.adoptPermissions = ArrayUtils.add(this.adoptPermissions, adoptPermission);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addPermission(ParsedPermission permission) {
+        this.permissions = ArrayUtils.add(this.permissions, permission);
+        return this;
+    }
+
+    @Override
+    public PackageImpl removePermission(int index) {
+        this.permissions.remove(index);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addPermissionGroup(ParsedPermissionGroup permissionGroup) {
+        this.permissionGroups = ArrayUtils.add(this.permissionGroups, permissionGroup);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addRequestedPermission(String permission) {
+        this.requestedPermissions = ArrayUtils.add(this.requestedPermissions,
+                TextUtils.safeIntern(permission));
+        return this;
+    }
+
+    @Override
+    public PackageImpl addImplicitPermission(String permission) {
+        this.implicitPermissions = ArrayUtils.add(this.implicitPermissions,
+                TextUtils.safeIntern(permission));
+        return this;
+    }
+
+    @Override
+    public PackageImpl addKeySet(String keySetName, PublicKey publicKey) {
+        if (keySetMapping == null) {
+            keySetMapping = new ArrayMap<>();
+        }
+
+        ArraySet<PublicKey> publicKeys = keySetMapping.get(keySetName);
+        if (publicKeys == null) {
+            publicKeys = new ArraySet<>();
+            keySetMapping.put(keySetName, publicKeys);
+        }
+
+        publicKeys.add(publicKey);
+
+        return this;
+    }
+
+    @Override
+    public ParsingPackage addActivity(ParsedActivity parsedActivity) {
+        this.activities = ArrayUtils.add(this.activities, parsedActivity);
+        return this;
+    }
+
+    @Override
+    public ParsingPackage addReceiver(ParsedActivity parsedReceiver) {
+        this.receivers = ArrayUtils.add(this.receivers, parsedReceiver);
+        return this;
+    }
+
+    @Override
+    public ParsingPackage addService(ParsedService parsedService) {
+        this.services = ArrayUtils.add(this.services, parsedService);
+        return this;
+    }
+
+    @Override
+    public ParsingPackage addProvider(ParsedProvider parsedProvider) {
+        this.providers = ArrayUtils.add(this.providers, parsedProvider);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addLibraryName(String libraryName) {
+        this.libraryNames = ArrayUtils.add(this.libraryNames, TextUtils.safeIntern(libraryName));
+        return this;
+    }
+
+    @Override
+    public PackageImpl addUsesLibrary(String libraryName) {
+        this.usesLibraries = ArrayUtils.add(this.usesLibraries, TextUtils.safeIntern(libraryName));
+        return this;
+    }
+
+    @Override
+    public PackageImpl addUsesOptionalLibrary(String libraryName) {
+        this.usesOptionalLibraries = ArrayUtils.add(this.usesOptionalLibraries,
+                TextUtils.safeIntern(libraryName));
+        return this;
+    }
+
+    @Override
+    public PackageImpl removeUsesOptionalLibrary(String libraryName) {
+        this.usesOptionalLibraries = ArrayUtils.remove(this.usesOptionalLibraries, libraryName);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addUsesStaticLibrary(String libraryName) {
+        this.usesStaticLibraries = ArrayUtils.add(this.usesStaticLibraries,
+                TextUtils.safeIntern(libraryName));
+        return this;
+    }
+
+    @Override
+    public PackageImpl addUsesStaticLibraryVersion(long version) {
+        this.usesStaticLibrariesVersions = ArrayUtils.appendLong(this.usesStaticLibrariesVersions,
+                version, true);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addUsesStaticLibraryCertDigests(String[] certSha256Digests) {
+        this.usesStaticLibrariesCertDigests = ArrayUtils.appendElement(String[].class,
+                this.usesStaticLibrariesCertDigests, certSha256Digests, true);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addPreferredActivityFilter(
+            ParsedActivityIntentInfo parsedActivityIntentInfo) {
+        this.preferredActivityFilters = ArrayUtils.add(this.preferredActivityFilters,
+                parsedActivityIntentInfo);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addQueriesIntent(Intent intent) {
+        this.queriesIntents = ArrayUtils.add(this.queriesIntents, intent);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addQueriesPackage(String packageName) {
+        this.queriesPackages = ArrayUtils.add(this.queriesPackages,
+                TextUtils.safeIntern(packageName));
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSupportsSmallScreens(int supportsSmallScreens) {
+        if (supportsSmallScreens == 1) {
+            return this;
+        }
+
+        this.supportsSmallScreens = supportsSmallScreens;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSupportsNormalScreens(int supportsNormalScreens) {
+        if (supportsNormalScreens == 1) {
+            return this;
+        }
+
+        this.supportsNormalScreens = supportsNormalScreens;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSupportsLargeScreens(int supportsLargeScreens) {
+        if (supportsLargeScreens == 1) {
+            return this;
+        }
+
+        this.supportsLargeScreens = supportsLargeScreens;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSupportsXLargeScreens(int supportsXLargeScreens) {
+        if (supportsXLargeScreens == 1) {
+            return this;
+        }
+
+        this.supportsXLargeScreens = supportsXLargeScreens;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setResizeable(int resizeable) {
+        if (resizeable == 1) {
+            return this;
+        }
+
+        this.resizeable = resizeable;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setAnyDensity(int anyDensity) {
+        if (anyDensity == 1) {
+            return this;
+        }
+
+        this.anyDensity = anyDensity;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setRequiresSmallestWidthDp(int requiresSmallestWidthDp) {
+        this.requiresSmallestWidthDp = requiresSmallestWidthDp;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setCompatibleWidthLimitDp(int compatibleWidthLimitDp) {
+        this.compatibleWidthLimitDp = compatibleWidthLimitDp;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setLargestWidthLimitDp(int largestWidthLimitDp) {
+        this.largestWidthLimitDp = largestWidthLimitDp;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setInstallLocation(int installLocation) {
+        this.installLocation = installLocation;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setTargetSandboxVersion(int targetSandboxVersion) {
+        this.targetSandboxVersion = targetSandboxVersion;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setRequiredForAllUsers(boolean requiredForAllUsers) {
+        this.requiredForAllUsers = requiredForAllUsers;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setRestrictedAccountType(String restrictedAccountType) {
+        this.restrictedAccountType = restrictedAccountType;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setRequiredAccountType(String requiredAccountType) {
+        this.requiredAccountType = requiredAccountType;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setBaseHardwareAccelerated(boolean baseHardwareAccelerated) {
+        this.baseHardwareAccelerated = baseHardwareAccelerated;
+
+        this.flags = baseHardwareAccelerated
+                ? this.flags | ApplicationInfo.FLAG_HARDWARE_ACCELERATED
+                : this.flags & ~ApplicationInfo.FLAG_HARDWARE_ACCELERATED;
+
+        return this;
+    }
+
+    @Override
+    public PackageImpl setHasDomainUrls(boolean hasDomainUrls) {
+        this.privateFlags = hasDomainUrls
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setAppMetaData(Bundle appMetaData) {
+        this.appMetaData = appMetaData;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setOverlayTarget(String overlayTarget) {
+        this.overlayTarget = overlayTarget;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setOverlayTargetName(String overlayTargetName) {
+        this.overlayTargetName = overlayTargetName;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setOverlayCategory(String overlayCategory) {
+        this.overlayCategory = overlayCategory;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setOverlayPriority(int overlayPriority) {
+        this.overlayPriority = overlayPriority;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setOverlayIsStatic(boolean overlayIsStatic) {
+        this.overlayIsStatic = overlayIsStatic;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setStaticSharedLibName(String staticSharedLibName) {
+        this.staticSharedLibName = TextUtils.safeIntern(staticSharedLibName);
+        return this;
+    }
+
+    @Override
+    public PackageImpl setStaticSharedLibVersion(long staticSharedLibVersion) {
+        this.staticSharedLibVersion = staticSharedLibVersion;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSharedUserId(String sharedUserId) {
+        this.sharedUserId = TextUtils.safeIntern(sharedUserId);
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSharedUserLabel(int sharedUserLabel) {
+        this.sharedUserLabel = sharedUserLabel;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setRestrictUpdateHash(byte[] restrictUpdateHash) {
+        this.restrictUpdateHash = restrictUpdateHash;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setUpgradeKeySets(ArraySet<String> upgradeKeySets) {
+        this.upgradeKeySets = upgradeKeySets;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setVolumeUuid(String volumeUuid) {
+        this.volumeUuid = volumeUuid;
+        return this;
+    }
+
+    @Deprecated
+    @Override
+    public PackageImpl setApplicationVolumeUuid(String applicationVolumeUuid) {
+        this.applicationVolumeUuid = applicationVolumeUuid;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSigningDetails(PackageParser.SigningDetails signingDetails) {
+        this.signingDetails = signingDetails;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setCodePath(String codePath) {
+        this.codePath = codePath;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setUse32BitAbi(boolean use32BitAbi) {
+        this.use32BitAbi = use32BitAbi;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setCpuAbiOverride(String cpuAbiOverride) {
+        this.cpuAbiOverride = cpuAbiOverride;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setForceQueryable(boolean forceQueryable) {
+        this.forceQueryable = forceQueryable;
+        return this;
+    }
+
+    // TODO(b/135203078): Remove and move PackageManagerService#renameStaticSharedLibraryPackage
+    //  into initial package parsing
+    @Override
+    public PackageImpl setPackageName(String packageName) {
+        this.packageName = packageName.intern();
+
+        if (permissions != null) {
+            for (ParsedPermission permission : permissions) {
+                permission.setPackageName(this.packageName);
+            }
+        }
+
+        if (permissionGroups != null) {
+            for (ParsedPermissionGroup permissionGroup : permissionGroups) {
+                permissionGroup.setPackageName(this.packageName);
+            }
+        }
+
+        if (activities != null) {
+            for (ParsedActivity parsedActivity : activities) {
+                parsedActivity.setPackageName(this.packageName);
+            }
+        }
+
+        if (receivers != null) {
+            for (ParsedActivity receiver : receivers) {
+                receiver.setPackageName(this.packageName);
+            }
+        }
+
+        if (providers != null) {
+            for (ParsedProvider provider : providers) {
+                provider.setPackageName(this.packageName);
+            }
+        }
+
+        if (services != null) {
+            for (ParsedService service : services) {
+                service.setPackageName(this.packageName);
+            }
+        }
+
+        if (instrumentations != null) {
+            for (ParsedInstrumentation instrumentation : instrumentations) {
+                instrumentation.setPackageName(this.packageName);
+            }
+        }
+
+        return this;
+    }
+
+    // Under this is parseBaseApplication
+
+    @Override
+    public PackageImpl setAllowBackup(boolean allowBackup) {
+        this.flags = allowBackup
+                ? this.flags | ApplicationInfo.FLAG_ALLOW_BACKUP
+                : this.flags & ~ApplicationInfo.FLAG_ALLOW_BACKUP;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setKillAfterRestore(boolean killAfterRestore) {
+        this.flags = killAfterRestore
+                ? this.flags | ApplicationInfo.FLAG_KILL_AFTER_RESTORE
+                : this.flags & ~ApplicationInfo.FLAG_KILL_AFTER_RESTORE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setRestoreAnyVersion(boolean restoreAnyVersion) {
+        this.flags = restoreAnyVersion
+                ? this.flags | ApplicationInfo.FLAG_RESTORE_ANY_VERSION
+                : this.flags & ~ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setFullBackupOnly(boolean fullBackupOnly) {
+        this.flags = fullBackupOnly
+                ? this.flags | ApplicationInfo.FLAG_FULL_BACKUP_ONLY
+                : this.flags & ~ApplicationInfo.FLAG_FULL_BACKUP_ONLY;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setPersistent(boolean persistent) {
+        this.flags = persistent
+                ? this.flags | ApplicationInfo.FLAG_PERSISTENT
+                : this.flags & ~ApplicationInfo.FLAG_PERSISTENT;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setDebuggable(boolean debuggable) {
+        this.flags = debuggable
+                ? this.flags | ApplicationInfo.FLAG_DEBUGGABLE
+                : this.flags & ~ApplicationInfo.FLAG_DEBUGGABLE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setProfileableByShell(boolean profileableByShell) {
+        this.privateFlags = profileableByShell
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setVmSafeMode(boolean vmSafeMode) {
+        this.flags = vmSafeMode
+                ? this.flags | ApplicationInfo.FLAG_VM_SAFE_MODE
+                : this.flags & ~ApplicationInfo.FLAG_VM_SAFE_MODE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setHasCode(boolean hasCode) {
+        this.flags = hasCode
+                ? this.flags | ApplicationInfo.FLAG_HAS_CODE
+                : this.flags & ~ApplicationInfo.FLAG_HAS_CODE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setAllowTaskReparenting(boolean allowTaskReparenting) {
+        this.flags = allowTaskReparenting
+                ? this.flags | ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING
+                : this.flags & ~ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setAllowClearUserData(boolean allowClearUserData) {
+        this.flags = allowClearUserData
+                ? this.flags | ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA
+                : this.flags & ~ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setLargeHeap(boolean largeHeap) {
+        this.flags = largeHeap
+                ? this.flags | ApplicationInfo.FLAG_LARGE_HEAP
+                : this.flags & ~ApplicationInfo.FLAG_LARGE_HEAP;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setUsesCleartextTraffic(boolean usesCleartextTraffic) {
+        this.flags = usesCleartextTraffic
+                ? this.flags | ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC
+                : this.flags & ~ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSupportsRtl(boolean supportsRtl) {
+        this.flags = supportsRtl
+                ? this.flags | ApplicationInfo.FLAG_SUPPORTS_RTL
+                : this.flags & ~ApplicationInfo.FLAG_SUPPORTS_RTL;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setTestOnly(boolean testOnly) {
+        this.flags = testOnly
+                ? this.flags | ApplicationInfo.FLAG_TEST_ONLY
+                : this.flags & ~ApplicationInfo.FLAG_TEST_ONLY;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setMultiArch(boolean multiArch) {
+        this.flags = multiArch
+                ? this.flags | ApplicationInfo.FLAG_MULTIARCH
+                : this.flags & ~ApplicationInfo.FLAG_MULTIARCH;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setExtractNativeLibs(boolean extractNativeLibs) {
+        this.flags = extractNativeLibs
+                ? this.flags | ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS
+                : this.flags & ~ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setIsGame(boolean isGame) {
+        this.flags = isGame
+                ? this.flags | ApplicationInfo.FLAG_IS_GAME
+                : this.flags & ~ApplicationInfo.FLAG_IS_GAME;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setBackupInForeground(boolean backupInForeground) {
+        this.privateFlags = backupInForeground
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setUseEmbeddedDex(boolean useEmbeddedDex) {
+        this.privateFlags = useEmbeddedDex
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setDefaultToDeviceProtectedStorage(boolean defaultToDeviceProtectedStorage) {
+        this.privateFlags = defaultToDeviceProtectedStorage
+                ? this.privateFlags | ApplicationInfo
+                        .PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE
+                : this.privateFlags & ~ApplicationInfo
+                        .PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setDirectBootAware(boolean directBootAware) {
+        this.privateFlags = directBootAware
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setPartiallyDirectBootAware(boolean partiallyDirectBootAware) {
+        this.privateFlags = partiallyDirectBootAware
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setActivitiesResizeModeResizeableViaSdkVersion(
+            boolean resizeableViaSdkVersion
+    ) {
+        this.privateFlags = resizeableViaSdkVersion
+                ? this.privateFlags | ApplicationInfo
+                        .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION
+                : this.privateFlags & ~ApplicationInfo
+                        .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setActivitiesResizeModeResizeable(boolean resizeable) {
+        this.privateFlags = resizeable
+                ? this.privateFlags | ApplicationInfo
+                        .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE
+                : this.privateFlags & ~ApplicationInfo
+                        .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE;
+
+        this.privateFlags = !resizeable
+                ? this.privateFlags | ApplicationInfo
+                        .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE
+                : this.privateFlags & ~ApplicationInfo
+                        .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setAllowClearUserDataOnFailedRestore(
+            boolean allowClearUserDataOnFailedRestore
+    ) {
+        this.privateFlags = allowClearUserDataOnFailedRestore
+                ? this.privateFlags | ApplicationInfo
+                        .PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE
+                : this.privateFlags & ~ApplicationInfo
+                        .PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setAllowAudioPlaybackCapture(boolean allowAudioPlaybackCapture) {
+        this.privateFlags = allowAudioPlaybackCapture
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setRequestLegacyExternalStorage(boolean requestLegacyExternalStorage) {
+        this.privateFlags = requestLegacyExternalStorage
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setUsesNonSdkApi(boolean usesNonSdkApi) {
+        this.privateFlags = usesNonSdkApi
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setHasFragileUserData(boolean hasFragileUserData) {
+        this.privateFlags = hasFragileUserData
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setCantSaveState(boolean cantSaveState) {
+        this.privateFlags = cantSaveState
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE;
+        return this;
+    }
+
+    @Override
+    public boolean cantSaveState() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0;
+    }
+
+    @Override
+    public boolean isLibrary() {
+        return staticSharedLibName != null || !ArrayUtils.isEmpty(libraryNames);
+    }
+
+    // TODO(b/135203078): This does nothing until the final stage without applyPolicy being
+    //  part of PackageParser
+    @Override
+    public boolean isSystemApp() {
+        return (flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+    }
+
+    // TODO(b/135203078): This does nothing until the final stage without applyPolicy being
+    //  part of PackageParser
+    @Override
+    public boolean isSystemExt() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0;
+    }
+
+    // TODO(b/135203078): This does nothing until the final stage without applyPolicy being
+    //  part of PackageParser
+    @Override
+    public boolean isUpdatedSystemApp() {
+        return (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
+    }
+
+    @Override
+    public PackageImpl setStaticSharedLibrary(boolean staticSharedLibrary) {
+        this.privateFlags = staticSharedLibrary
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY;
+        return this;
+    }
+
+    @Override
+    public boolean isStaticSharedLibrary() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY) != 0;
+    }
+
+    @Override
+    public PackageImpl setVisibleToInstantApps(boolean visibleToInstantApps) {
+        this.visibleToInstantApps = visibleToInstantApps;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setIconRes(int iconRes) {
+        this.iconRes = iconRes;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setRoundIconRes(int roundIconRes) {
+        this.roundIconRes = roundIconRes;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setClassName(String className) {
+        this.className = className;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setManageSpaceActivityName(String manageSpaceActivityName) {
+        this.manageSpaceActivityName = manageSpaceActivityName;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setBackupAgentName(String backupAgentName) {
+        this.backupAgentName = backupAgentName;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setFullBackupContent(int fullBackupContent) {
+        this.fullBackupContent = fullBackupContent;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setTheme(int theme) {
+        this.theme = theme;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setDescriptionRes(int descriptionRes) {
+        this.descriptionRes = descriptionRes;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setNetworkSecurityConfigRes(int networkSecurityConfigRes) {
+        this.networkSecurityConfigRes = networkSecurityConfigRes;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setCategory(int category) {
+        this.category = category;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setPermission(String permission) {
+        this.permission = permission;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setTaskAffinity(String taskAffinity) {
+        this.taskAffinity = taskAffinity;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setAppComponentFactory(String appComponentFactory) {
+        this.appComponentFactory = appComponentFactory;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setProcessName(String processName) {
+        if (processName == null) {
+            this.processName = packageName;
+        } else {
+            this.processName = processName;
+        }
+        return this;
+    }
+
+    @Override
+    public PackageImpl setEnabled(boolean enabled) {
+        this.enabled = enabled;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setUiOptions(int uiOptions) {
+        this.uiOptions = uiOptions;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setClassLoaderName(String classLoaderName) {
+        this.classLoaderName = classLoaderName;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setZygotePreloadName(String zygotePreloadName) {
+        this.zygotePreloadName = zygotePreloadName;
+        return this;
+    }
+
+    // parsePackageItemInfo
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public PackageImpl setName(String name) {
+        this.name = name;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setIcon(int icon) {
+        this.icon = icon;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setNonLocalizedLabel(CharSequence nonLocalizedLabel) {
+        this.nonLocalizedLabel = nonLocalizedLabel;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setLogo(int logo) {
+        this.logo = logo;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setBanner(int banner) {
+        this.banner = banner;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setLabelRes(int labelRes) {
+        this.labelRes = labelRes;
+        return this;
+    }
+
+    @Override
+    public PackageImpl asSplit(
+            String[] splitNames,
+            String[] splitCodePaths,
+            int[] splitRevisionCodes,
+            SparseArray<int[]> splitDependencies
+    ) {
+        this.splitNames = splitNames;
+
+        if (this.splitNames != null) {
+            for (int index = 0; index < this.splitNames.length; index++) {
+                splitNames[index] = TextUtils.safeIntern(splitNames[index]);
+            }
+        }
+
+        this.splitCodePaths = splitCodePaths;
+        this.splitRevisionCodes = splitRevisionCodes;
+        this.splitDependencies = splitDependencies;
+
+        int count = splitNames.length;
+        this.splitFlags = new int[count];
+        this.splitClassLoaderNames = new String[count];
+        return this;
+    }
+
+    @Override
+    public String[] getSplitNames() {
+        return splitNames;
+    }
+
+    @Override
+    public String[] getSplitCodePaths() {
+        return splitCodePaths;
+    }
+
+    @Override
+    public PackageImpl setSplitHasCode(int splitIndex, boolean splitHasCode) {
+        this.splitFlags[splitIndex] = splitHasCode
+                ? this.splitFlags[splitIndex] | ApplicationInfo.FLAG_HAS_CODE
+                : this.splitFlags[splitIndex] & ~ApplicationInfo.FLAG_HAS_CODE;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSplitClassLoaderName(int splitIndex, String classLoaderName) {
+        this.splitClassLoaderNames[splitIndex] = classLoaderName;
+        return this;
+    }
+
+    @Override
+    public List<String> makeListAllCodePaths() {
+        ArrayList<String> paths = new ArrayList<>();
+        paths.add(baseCodePath);
+
+        if (!ArrayUtils.isEmpty(splitCodePaths)) {
+            Collections.addAll(paths, splitCodePaths);
+        }
+        return paths;
+    }
+
+    @Override
+    public PackageImpl setBaseCodePath(String baseCodePath) {
+        this.baseCodePath = baseCodePath;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSplitCodePaths(String[] splitCodePaths) {
+        this.splitCodePaths = splitCodePaths;
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        return "Package{"
+                + Integer.toHexString(System.identityHashCode(this))
+                + " " + packageName + "}";
+    }
+
+    @Override
+    public PackageImpl setPrimaryCpuAbi(String primaryCpuAbi) {
+        this.primaryCpuAbi = primaryCpuAbi;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSecondaryCpuAbi(String secondaryCpuAbi) {
+        this.secondaryCpuAbi = secondaryCpuAbi;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setNativeLibraryRootDir(String nativeLibraryRootDir) {
+        this.nativeLibraryRootDir = nativeLibraryRootDir;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setNativeLibraryRootRequiresIsa(boolean nativeLibraryRootRequiresIsa) {
+        this.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setNativeLibraryDir(String nativeLibraryDir) {
+        this.nativeLibraryDir = nativeLibraryDir;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSecondaryNativeLibraryDir(String secondaryNativeLibraryDir) {
+        this.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
+        return this;
+    }
+
+    @Deprecated
+    @Override
+    public PackageImpl setApplicationInfoCodePath(String applicationInfoCodePath) {
+        this.applicationInfoCodePath = applicationInfoCodePath;
+        return this;
+    }
+
+    @Deprecated
+    @Override
+    public PackageImpl setApplicationInfoResourcePath(String applicationInfoResourcePath) {
+        this.applicationInfoResourcePath = applicationInfoResourcePath;
+        return this;
+    }
+
+    @Deprecated
+    @Override
+    public PackageImpl setApplicationInfoBaseResourcePath(
+            String applicationInfoBaseResourcePath) {
+        this.applicationInfoBaseResourcePath = applicationInfoBaseResourcePath;
+        return this;
+    }
+
+    @Deprecated
+    @Override
+    public PackageImpl setApplicationInfoSplitResourcePaths(
+            String[] applicationInfoSplitResourcePaths) {
+        this.applicationInfoSplitResourcePaths = applicationInfoSplitResourcePaths;
+        return this;
+    }
+
+    @Override
+    public boolean isDirectBootAware() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE) != 0;
+    }
+
+    @Override
+    public PackageImpl setAllComponentsDirectBootAware(boolean allComponentsDirectBootAware) {
+        if (activities != null) {
+            for (ParsedActivity parsedActivity : activities) {
+                parsedActivity.directBootAware = allComponentsDirectBootAware;
+            }
+        }
+
+        if (receivers != null) {
+            for (ParsedActivity parsedReceiver : receivers) {
+                parsedReceiver.directBootAware = allComponentsDirectBootAware;
+            }
+        }
+
+        if (providers != null) {
+            for (ParsedProvider parsedProvider : providers) {
+                parsedProvider.directBootAware = allComponentsDirectBootAware;
+            }
+        }
+
+        if (services != null) {
+            for (ParsedService parsedService : services) {
+                parsedService.directBootAware = allComponentsDirectBootAware;
+            }
+        }
+
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSystem(boolean system) {
+        this.flags = system
+                ? this.flags | ApplicationInfo.FLAG_SYSTEM
+                : this.flags & ~ApplicationInfo.FLAG_SYSTEM;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSystemExt(boolean systemExt) {
+        this.privateFlags = systemExt
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setIsStub(boolean isStub) {
+        this.isStub = isStub;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setCoreApp(boolean coreApp) {
+        this.coreApp = coreApp;
+        return this;
+    }
+
+    @Override
+    public ParsedPackage capPermissionPriorities() {
+        if (permissionGroups != null && !permissionGroups.isEmpty()) {
+            for (int i = permissionGroups.size() - 1; i >= 0; --i) {
+                // TODO(b/135203078): Builder/immutability
+                permissionGroups.get(i).priority = 0;
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public ParsedPackage clearProtectedBroadcasts() {
+        if (protectedBroadcasts != null) {
+            protectedBroadcasts.clear();
+        }
+        return this;
+    }
+
+    @Override
+    public ParsedPackage markNotActivitiesAsNotExportedIfSingleUser() {
+        // ignore export request for single user receivers
+        if (receivers != null) {
+            for (ParsedActivity receiver : receivers) {
+                if ((receiver.flags & ActivityInfo.FLAG_SINGLE_USER) != 0) {
+                    receiver.exported = false;
+                }
+            }
+        }
+        // ignore export request for single user services
+        if (services != null) {
+            for (ParsedService service : services) {
+                if ((service.flags & ServiceInfo.FLAG_SINGLE_USER) != 0) {
+                    service.exported = false;
+                }
+            }
+        }
+        // ignore export request for single user providers
+        if (providers != null) {
+            for (ParsedProvider provider : providers) {
+                if ((provider.flags & ProviderInfo.FLAG_SINGLE_USER) != 0) {
+                    provider.exported = false;
+                }
+            }
+        }
+
+        return this;
+    }
+
+    @Override
+    public ParsedPackage setPrivileged(boolean privileged) {
+        this.privateFlags = privileged
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+        return this;
+    }
+
+    @Override
+    public ParsedPackage setOem(boolean oem) {
+        this.privateFlags = oem
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_OEM
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_OEM;
+        return this;
+    }
+
+    @Override
+    public ParsedPackage setVendor(boolean vendor) {
+        this.privateFlags = vendor
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_VENDOR
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_VENDOR;
+        return this;
+    }
+
+    @Override
+    public ParsedPackage setProduct(boolean product) {
+        this.privateFlags = product
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PRODUCT
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PRODUCT;
+        return this;
+    }
+
+    @Override
+    public ParsedPackage setOdm(boolean odm) {
+        this.privateFlags = odm
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_ODM
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_ODM;
+        return this;
+    }
+
+    @Override
+    public ParsedPackage setSignedWithPlatformKey(boolean signedWithPlatformKey) {
+        this.privateFlags = signedWithPlatformKey
+                ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY
+                : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY;
+        return this;
+    }
+
+    @Override
+    public ParsedPackage clearOriginalPackages() {
+        if (originalPackages != null) {
+            originalPackages.clear();
+        }
+        return this;
+    }
+
+    @Override
+    public ParsedPackage clearAdoptPermissions() {
+        if (adoptPermissions != null) {
+            adoptPermissions.clear();
+        }
+        return this;
+    }
+
+    @Override
+    public PackageImpl addUsesLibrary(int index, String libraryName) {
+        this.usesLibraries = ArrayUtils.add(usesLibraries, index, libraryName);
+        return this;
+    }
+
+    @Override
+    public ParsedPackage removeUsesLibrary(String libraryName) {
+        this.usesLibraries = ArrayUtils.remove(this.usesLibraries, libraryName);
+        return this;
+    }
+
+    @Override
+    public PackageImpl addUsesOptionalLibrary(int index, String libraryName) {
+        this.usesOptionalLibraries = ArrayUtils.add(usesOptionalLibraries, index, libraryName);
+        return this;
+    }
+
+    @Nullable
+    @Override
+    public List<String> getUsesOptionalLibraries() {
+        return usesOptionalLibraries;
+    }
+
+    @Override
+    public int getVersionCode() {
+        return versionCode;
+    }
+
+    @Nullable
+    @Override
+    public long[] getUsesStaticLibrariesVersions() {
+        return usesStaticLibrariesVersions;
+    }
+
+    @Override
+    public PackageImpl setPackageSettingCallback(PackageSettingCallback packageSettingCallback) {
+        packageSettingCallback.setAndroidPackage(this);
+        return this;
+    }
+
+    @Override
+    public PackageImpl setUpdatedSystemApp(boolean updatedSystemApp) {
+        this.flags = updatedSystemApp
+                ? this.flags | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP
+                : this.flags & ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+        return this;
+    }
+
+    @Override
+    public boolean isPrivileged() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
+    }
+
+    @Override
+    public PackageImpl setSeInfo(String seInfo) {
+        this.seInfo = seInfo;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setSeInfoUser(String seInfoUser) {
+        this.seInfoUser = seInfoUser;
+        return this;
+    }
+
+    @Override
+    public PackageImpl initForUser(int userId) {
+        // TODO(b/135203078): Move this user state to some other data structure
+        this.uid = UserHandle.getUid(userId, UserHandle.getAppId(this.uid));
+
+        if ("android".equals(packageName)) {
+            dataDir = Environment.getDataSystemDirectory().getAbsolutePath();
+            return this;
+        }
+
+        deviceProtectedDataDir = Environment
+                .getDataUserDePackageDirectory(applicationVolumeUuid, userId, packageName)
+                .getAbsolutePath();
+        credentialProtectedDataDir = Environment
+                .getDataUserCePackageDirectory(applicationVolumeUuid, userId, packageName)
+                .getAbsolutePath();
+
+        if ((privateFlags & ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) != 0
+                && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
+            dataDir = deviceProtectedDataDir;
+        } else {
+            dataDir = credentialProtectedDataDir;
+        }
+        return this;
+    }
+
+    @Override
+    public ParsedPackage setFactoryTest(boolean factoryTest) {
+        this.flags = factoryTest
+                ? this.flags | ApplicationInfo.FLAG_FACTORY_TEST
+                : this.flags & ~ApplicationInfo.FLAG_FACTORY_TEST;
+        return this;
+    }
+
+    @Override
+    public String getManifestPackageName() {
+        return manifestPackageName;
+    }
+
+    @Override
+    public String getRealPackage() {
+        return realPackage;
+    }
+
+    @Override
+    public String getOverlayTarget() {
+        return overlayTarget;
+    }
+
+    @Override
+    public String getOverlayTargetName() {
+        return overlayTargetName;
+    }
+
+    @Override
+    public Map<String, String> getOverlayables() {
+        return overlayables;
+    }
+
+    @Override
+    public boolean isOverlayIsStatic() {
+        return overlayIsStatic;
+    }
+
+    @Override
+    public int[] getSplitFlags() {
+        return splitFlags;
+    }
+
+    @Deprecated
+    @Override
+    public String getApplicationInfoVolumeUuid() {
+        return applicationVolumeUuid;
+    }
+
+    @Nullable
+    @Override
+    public List<String> getProtectedBroadcasts() {
+        return protectedBroadcasts;
+    }
+
+    @Nullable
+    @Override
+    public Set<String> getUpgradeKeySets() {
+        return upgradeKeySets;
+    }
+
+    @Nullable
+    @Override
+    public String[][] getUsesStaticLibrariesCertDigests() {
+        return usesStaticLibrariesCertDigests;
+    }
+
+    @Override
+    public int getOverlayPriority() {
+        return overlayPriority;
+    }
+
+    @Deprecated
+    @Override
+    public String getAppInfoPackageName() {
+        return packageName;
+    }
+
+    @Override
+    public UUID getStorageUuid() {
+        return StorageManager.convert(applicationVolumeUuid);
+    }
+
+    @Override
+    public int getUid() {
+        return uid;
+    }
+
+    @Override
+    public boolean isStub() {
+        return isStub;
+    }
+
+    @Deprecated
+    @Override
+    public String getAppInfoCodePath() {
+        return applicationInfoCodePath;
+    }
+
+    @Override
+    public boolean isSystem() {
+        return (flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+    }
+
+    @Override
+    public boolean isMatch(int flags) {
+        if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
+            return isSystem();
+        }
+        return true;
+    }
+
+    @Override
+    public boolean isVisibleToInstantApps() {
+        return visibleToInstantApps;
+    }
+
+    @Override
+    public PackageImpl setLastPackageUsageTimeInMills(int reason, long time) {
+        lastPackageUsageTimeInMills[reason] = time;
+        return this;
+    }
+
+    @Override
+    public List<SharedLibraryInfo> getUsesLibraryInfos() {
+        return usesLibraryInfos;
+    }
+
+    @NonNull
+    @Override
+    public List<String> getAllCodePaths() {
+        return makeListAllCodePaths();
+    }
+
+    @Nullable
+    @Override
+    public String[] getUsesLibraryFiles() {
+        return usesLibraryFiles;
+    }
+
+    @Override
+    public PackageImpl setUsesLibraryInfos(
+            @Nullable List<SharedLibraryInfo> usesLibraryInfos) {
+        this.usesLibraryInfos = usesLibraryInfos;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setUsesLibraryFiles(@Nullable String[] usesLibraryFiles) {
+        this.usesLibraryFiles = usesLibraryFiles;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setUid(int uid) {
+        this.uid = uid;
+        return this;
+    }
+
+    @Override
+    public List<String> getAdoptPermissions() {
+        return adoptPermissions;
+    }
+
+    @Override
+    public ApplicationInfo toAppInfoWithoutState() {
+        updateFlags();
+
+        ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.packageName = packageName;
+        appInfo.flags = flags;
+        appInfo.privateFlags = privateFlags;
+
+        appInfo.appComponentFactory = appComponentFactory;
+        appInfo.backupAgentName = backupAgentName;
+        appInfo.banner = banner;
+        appInfo.category = category;
+        appInfo.classLoaderName = classLoaderName;
+        appInfo.className = className;
+        appInfo.compatibleWidthLimitDp = compatibleWidthLimitDp;
+        appInfo.compileSdkVersion = compileSdkVersion;
+        appInfo.compileSdkVersionCodename = compileSdkVersionCodename;
+        appInfo.credentialProtectedDataDir = credentialProtectedDataDir;
+        appInfo.dataDir = dataDir;
+        appInfo.descriptionRes = descriptionRes;
+        appInfo.deviceProtectedDataDir = deviceProtectedDataDir;
+        appInfo.enabled = enabled;
+        appInfo.fullBackupContent = fullBackupContent;
+        appInfo.hiddenUntilInstalled = hiddenUntilInstalled;
+        appInfo.icon = icon;
+        appInfo.iconRes = iconRes;
+        appInfo.installLocation = installLocation;
+        appInfo.labelRes = labelRes;
+        appInfo.largestWidthLimitDp = largestWidthLimitDp;
+        appInfo.logo = logo;
+        appInfo.manageSpaceActivityName = manageSpaceActivityName;
+        appInfo.maxAspectRatio = maxAspectRatio;
+        appInfo.metaData = appMetaData;
+        appInfo.minAspectRatio = minAspectRatio;
+        appInfo.minSdkVersion = minSdkVersion;
+        appInfo.name = className;
+        if (appInfo.name != null) {
+            appInfo.name = appInfo.name.trim();
+        }
+        appInfo.nativeLibraryDir = nativeLibraryDir;
+        appInfo.nativeLibraryRootDir = nativeLibraryRootDir;
+        appInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
+        appInfo.networkSecurityConfigRes = networkSecurityConfigRes;
+        appInfo.nonLocalizedLabel = nonLocalizedLabel;
+        if (appInfo.nonLocalizedLabel != null) {
+            appInfo.nonLocalizedLabel = appInfo.nonLocalizedLabel.toString().trim();
+        }
+        appInfo.packageName = packageName;
+        appInfo.permission = permission;
+        appInfo.primaryCpuAbi = primaryCpuAbi;
+        appInfo.processName = getProcessName();
+        appInfo.requiresSmallestWidthDp = requiresSmallestWidthDp;
+        appInfo.roundIconRes = roundIconRes;
+        appInfo.secondaryCpuAbi = secondaryCpuAbi;
+        appInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
+        appInfo.seInfo = seInfo;
+        appInfo.seInfoUser = seInfoUser;
+        appInfo.sharedLibraryFiles = usesLibraryFiles;
+        appInfo.sharedLibraryInfos = ArrayUtils.isEmpty(usesLibraryInfos) ? null : usesLibraryInfos;
+        appInfo.splitClassLoaderNames = splitClassLoaderNames;
+        appInfo.splitDependencies = splitDependencies;
+        appInfo.splitNames = splitNames;
+        appInfo.storageUuid = StorageManager.convert(volumeUuid);
+        appInfo.targetSandboxVersion = targetSandboxVersion;
+        appInfo.targetSdkVersion = targetSdkVersion;
+        appInfo.taskAffinity = taskAffinity;
+        appInfo.theme = theme;
+        appInfo.uid = uid;
+        appInfo.uiOptions = uiOptions;
+        appInfo.volumeUuid = volumeUuid;
+        appInfo.zygotePreloadName = zygotePreloadName;
+
+        appInfo.setBaseCodePath(baseCodePath);
+        appInfo.setBaseResourcePath(baseCodePath);
+        appInfo.setCodePath(codePath);
+        appInfo.setResourcePath(codePath);
+        appInfo.setSplitCodePaths(splitCodePaths);
+        appInfo.setSplitResourcePaths(splitCodePaths);
+        appInfo.setVersionCode(getLongVersionCode());
+
+        // TODO(b/135203078): Can this be removed? Looks only used in ActivityInfo.
+//        appInfo.showUserIcon = pkg.getShowUserIcon();
+        // TODO(b/135203078): Unused?
+//        appInfo.resourceDirs = pkg.getResourceDirs();
+        // TODO(b/135203078): Unused?
+//        appInfo.enabledSetting = pkg.getEnabledSetting();
+        // TODO(b/135203078): See PackageImpl#getHiddenApiEnforcementPolicy
+//        appInfo.mHiddenApiPolicy = pkg.getHiddenApiPolicy();
+
+        return appInfo;
+    }
+
+    @Override
+    public PackageImpl setVersionCode(int versionCode) {
+        this.versionCode = versionCode;
+        return this;
+    }
+
+    @Override
+    public PackageImpl setHiddenUntilInstalled(boolean hidden) {
+        this.hiddenUntilInstalled = hidden;
+        return this;
+    }
+
+    @Override
+    public String getSeInfo() {
+        return seInfo;
+    }
+
+    @Deprecated
+    @Override
+    public String getAppInfoResourcePath() {
+        return applicationInfoResourcePath;
+    }
+
+    @Override
+    public boolean isForwardLocked() {
+        // TODO(b/135203078): Unused? Move to debug flag?
+        return false;
+    }
+
+    @Override
+    public byte[] getRestrictUpdateHash() {
+        return restrictUpdateHash;
+    }
+
+    @Override
+    public boolean hasComponentClassName(String className) {
+        if (activities != null) {
+            for (ParsedActivity parsedActivity : activities) {
+                if (Objects.equals(className, parsedActivity.className)) {
+                    return true;
+                }
+            }
+        }
+
+        if (receivers != null) {
+            for (ParsedActivity receiver : receivers) {
+                if (Objects.equals(className, receiver.className)) {
+                    return true;
+                }
+            }
+        }
+
+        if (providers != null) {
+            for (ParsedProvider provider : providers) {
+                if (Objects.equals(className, provider.className)) {
+                    return true;
+                }
+            }
+        }
+
+        if (services != null) {
+            for (ParsedService service : services) {
+                if (Objects.equals(className, service.className)) {
+                    return true;
+                }
+            }
+        }
+
+        if (instrumentations != null) {
+            for (ParsedInstrumentation instrumentation : instrumentations) {
+                if (Objects.equals(className, instrumentation.className)) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public boolean isDefaultToDeviceProtectedStorage() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE)
+                != 0;
+    }
+
+    @Override
+    public boolean isInternal() {
+        return (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0;
+    }
+
+    @Override
+    public int getBaseRevisionCode() {
+        return baseRevisionCode;
+    }
+
+    @Override
+    public int[] getSplitRevisionCodes() {
+        return splitRevisionCodes;
+    }
+
+    @Override
+    public boolean canHaveOatDir() {
+        // The following app types CANNOT have oat directory
+        // - non-updated system apps
+        return !isSystem() || isUpdatedSystemApp();
+    }
+
+    @Override
+    public long getLatestPackageUseTimeInMills() {
+        long latestUse = 0L;
+        for (long use : lastPackageUsageTimeInMills) {
+            latestUse = Math.max(latestUse, use);
+        }
+        return latestUse;
+    }
+
+    @Override
+    public long getLatestForegroundPackageUseTimeInMills() {
+        int[] foregroundReasons = {
+                PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY,
+                PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE
+        };
+
+        long latestUse = 0L;
+        for (int reason : foregroundReasons) {
+            latestUse = Math.max(latestUse, lastPackageUsageTimeInMills[reason]);
+        }
+        return latestUse;
+    }
+
+    @Override
+    public boolean isCoreApp() {
+        return coreApp;
+    }
+
+    @Override
+    public String getVersionName() {
+        return versionName;
+    }
+
+    @Override
+    public PackageImpl setVersionCodeMajor(int versionCodeMajor) {
+        this.versionCodeMajor = versionCodeMajor;
+        return this;
+    }
+
+    @Override
+    public long[] getLastPackageUsageTimeInMills() {
+        return lastPackageUsageTimeInMills;
+    }
+
+    @Override
+    public String getDataDir() {
+        return dataDir;
+    }
+
+    @Override
+    public boolean isExternal() {
+        return (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
+    }
+
+    @Override
+    public List<String> getImplicitPermissions() {
+        return implicitPermissions == null ? Collections.emptyList() : implicitPermissions;
+    }
+
+    /**
+     * TODO(b/135203078): Remove, ensure b/140256621 is fixed or irrelevant
+     * TODO(b/140256621): Remove after fixing instant app check
+     * @deprecated This method always returns false because there's no paired set method
+     */
+    @Deprecated
+    @Override
+    public boolean isInstantApp() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0;
+    }
+
+    @Override
+    public boolean hasRequestedLegacyExternalStorage() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE) != 0;
+    }
+
+    @Override
+    public boolean isVendor() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
+    }
+
+    @Override
+    public boolean isProduct() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
+    }
+
+    @Override
+    public boolean isOem() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
+    }
+
+    @Override
+    public boolean isEncryptionAware() {
+        boolean isPartiallyDirectBootAware =
+                (privateFlags & ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE) != 0;
+        return isDirectBootAware() || isPartiallyDirectBootAware;
+    }
+
+    @Override
+    public boolean isEmbeddedDexUsed() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX) != 0;
+    }
+
+    @Deprecated
+    @Override
+    public String getAppInfoProcessName() {
+        return processName;
+    }
+
+    @Override
+    public List<String> getAllCodePathsExcludingResourceOnly() {
+        ArrayList<String> paths = new ArrayList<>();
+        if ((flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
+            paths.add(baseCodePath);
+        }
+        if (!ArrayUtils.isEmpty(splitCodePaths)) {
+            for (int i = 0; i < splitCodePaths.length; i++) {
+                if ((splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) {
+                    paths.add(splitCodePaths[i]);
+                }
+            }
+        }
+        return paths;
+    }
+
+    @Deprecated
+    @Override
+    public String getAppInfoName() {
+        return name;
+    }
+
+    private boolean isSignedWithPlatformKey() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY) != 0;
+    }
+
+    private boolean usesNonSdkApi() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API) != 0;
+    }
+
+    private boolean isPackageWhitelistedForHiddenApis() {
+        return SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(packageName);
+    }
+
+    private boolean isAllowedToUseHiddenApis() {
+        if (isSignedWithPlatformKey()) {
+            return true;
+        } else if (isSystemApp() || isUpdatedSystemApp()) {
+            return usesNonSdkApi() || isPackageWhitelistedForHiddenApis();
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public int getHiddenApiEnforcementPolicy() {
+        if (isAllowedToUseHiddenApis()) {
+            return ApplicationInfo.HIDDEN_API_ENFORCEMENT_DISABLED;
+        }
+
+        // TODO(b/135203078): Handle maybeUpdateHiddenApiEnforcementPolicy. Right now it's done
+        //  entirely through ApplicationInfo and shouldn't touch this specific class, but that
+        //  may not always hold true.
+//        if (mHiddenApiPolicy != ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT) {
+//            return mHiddenApiPolicy;
+//        }
+        return ApplicationInfo.HIDDEN_API_ENFORCEMENT_ENABLED;
+    }
+
+    @Nullable
+    @Override
+    public SparseArray<int[]> getSplitDependencies() {
+        return splitDependencies;
+    }
+
+    @Override
+    public boolean requestsIsolatedSplitLoading() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING) != 0;
+    }
+
+    @Deprecated
+    @Override
+    public String getAppInfoClassLoaderName() {
+        return classLoaderName;
+    }
+
+    @Override
+    public String getClassLoaderName() {
+        return classLoaderName;
+    }
+
+    @Override
+    public String[] getSplitClassLoaderNames() {
+        return splitClassLoaderNames;
+    }
+
+    @Override
+    public String getOverlayCategory() {
+        return overlayCategory;
+    }
+
+    @Override
+    public boolean isProfileableByShell() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL) != 0;
+    }
+
+    @Nullable
+    @Override
+    public List<ParsedActivityIntentInfo> getPreferredActivityFilters() {
+        return preferredActivityFilters;
+    }
+
+    @Override
+    public boolean isHiddenUntilInstalled() {
+        return hiddenUntilInstalled;
+    }
+
+    @Override
+    public int getMinSdkVersion() {
+        return minSdkVersion;
+    }
+
+    @Override
+    public String getRestrictedAccountType() {
+        return restrictedAccountType;
+    }
+
+    @Override
+    public String getRequiredAccountType() {
+        return requiredAccountType;
+    }
+
+    @Override
+    public int getInstallLocation() {
+        return installLocation;
+    }
+
+    @Override
+    public List<ParsedActivity> getReceivers() {
+        return receivers;
+    }
+
+    @Override
+    public List<ParsedService> getServices() {
+        return services;
+    }
+
+    @Override
+    public List<ParsedProvider> getProviders() {
+        return providers;
+    }
+
+    @Override
+    public int getSharedUserLabel() {
+        return sharedUserLabel;
+    }
+
+    @Override
+    public int getVersionCodeMajor() {
+        return versionCodeMajor;
+    }
+
+    @Override
+    public boolean isRequiredForAllUsers() {
+        return requiredForAllUsers;
+    }
+
+    @Override
+    public int getCompileSdkVersion() {
+        return compileSdkVersion;
+    }
+
+    @Override
+    public String getCompileSdkVersionCodeName() {
+        return compileSdkVersionCodename;
+    }
+
+    @Nullable
+    @Override
+    public List<ConfigurationInfo> getConfigPreferences() {
+        return configPreferences;
+    }
+
+    @Nullable
+    @Override
+    public List<FeatureInfo> getReqFeatures() {
+        return reqFeatures;
+    }
+
+    @Override
+    public List<FeatureGroupInfo> getFeatureGroups() {
+        return featureGroups;
+    }
+
+    @Override
+    public String getDeviceProtectedDataDir() {
+        return deviceProtectedDataDir;
+    }
+
+    @Override
+    public String getCredentialProtectedDataDir() {
+        return credentialProtectedDataDir;
+    }
+
+    @Override
+    public String getSeInfoUser() {
+        return seInfoUser;
+    }
+
+    @Override
+    public String getClassName() {
+        return className;
+    }
+
+    @Override
+    public int getTheme() {
+        return theme;
+    }
+
+    @Override
+    public int getRequiresSmallestWidthDp() {
+        return requiresSmallestWidthDp;
+    }
+
+    @Override
+    public int getCompatibleWidthLimitDp() {
+        return compatibleWidthLimitDp;
+    }
+
+    @Override
+    public int getLargestWidthLimitDp() {
+        return largestWidthLimitDp;
+    }
+
+    @Override
+    public String getScanSourceDir() {
+        return applicationInfoCodePath;
+    }
+
+    @Override
+    public String getScanPublicSourceDir() {
+        return applicationInfoResourcePath;
+    }
+
+    @Override
+    public String getPublicSourceDir() {
+        return applicationInfoBaseResourcePath;
+    }
+
+    @Override
+    public String[] getSplitPublicSourceDirs() {
+        return applicationInfoSplitResourcePaths;
+    }
+
+    @Override
+    public String getSecondaryNativeLibraryDir() {
+        return secondaryNativeLibraryDir;
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    @Override
+    public String getManageSpaceActivityName() {
+        return manageSpaceActivityName;
+    }
+
+    @Override
+    public int getDescriptionRes() {
+        return descriptionRes;
+    }
+
+    @Override
+    public String getBackupAgentName() {
+        return backupAgentName;
+    }
+
+    @Override
+    public int getFullBackupContent() {
+        return fullBackupContent;
+    }
+
+    @Override
+    public int getNetworkSecurityConfigRes() {
+        return networkSecurityConfigRes;
+    }
+
+    @Override
+    public int getCategory() {
+        return category;
+    }
+
+    @Override
+    public int getTargetSandboxVersion() {
+        return targetSandboxVersion;
+    }
+
+    @Override
+    public String getAppComponentFactory() {
+        return appComponentFactory;
+    }
+
+    @Override
+    public int getIconRes() {
+        return iconRes;
+    }
+
+    @Override
+    public int getRoundIconRes() {
+        return roundIconRes;
+    }
+
+    @Override
+    public String getZygotePreloadName() {
+        return zygotePreloadName;
+    }
+
+    @Override
+    public int getLabelRes() {
+        return labelRes;
+    }
+
+    @Override
+    public CharSequence getNonLocalizedLabel() {
+        return nonLocalizedLabel;
+    }
+
+    @Override
+    public int getIcon() {
+        return icon;
+    }
+
+    @Override
+    public int getBanner() {
+        return banner;
+    }
+
+    @Override
+    public int getLogo() {
+        return logo;
+    }
+
+    @Override
+    public Bundle getMetaData() {
+        return appMetaData;
+    }
+
+    @Override
+    @Nullable
+    public List<Intent> getQueriesIntents() {
+        return queriesIntents;
+    }
+
+    @Override
+    @Nullable
+    public List<String> getQueriesPackages() {
+        return queriesPackages;
+    }
+
+    private static void internStringArrayList(List<String> list) {
+        if (list != null) {
+            final int N = list.size();
+            for (int i = 0; i < N; ++i) {
+                list.set(i, list.get(i).intern());
+            }
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(this.supportsSmallScreens);
+        dest.writeInt(this.supportsNormalScreens);
+        dest.writeInt(this.supportsLargeScreens);
+        dest.writeInt(this.supportsXLargeScreens);
+        dest.writeInt(this.resizeable);
+        dest.writeInt(this.anyDensity);
+        dest.writeLongArray(this.lastPackageUsageTimeInMills);
+        dest.writeInt(this.versionCode);
+        dest.writeInt(this.versionCodeMajor);
+        dest.writeInt(this.baseRevisionCode);
+        dest.writeString(this.versionName);
+        dest.writeBoolean(this.coreApp);
+        dest.writeInt(this.compileSdkVersion);
+        dest.writeString(this.compileSdkVersionCodename);
+        dest.writeString(this.packageName);
+        dest.writeString(this.realPackage);
+        dest.writeString(this.manifestPackageName);
+        dest.writeString(this.baseCodePath);
+        dest.writeBoolean(this.requiredForAllUsers);
+        dest.writeString(this.restrictedAccountType);
+        dest.writeString(this.requiredAccountType);
+        dest.writeBoolean(this.baseHardwareAccelerated);
+        dest.writeString(this.overlayTarget);
+        dest.writeString(this.overlayTargetName);
+        dest.writeString(this.overlayCategory);
+        dest.writeInt(this.overlayPriority);
+        dest.writeBoolean(this.overlayIsStatic);
+        dest.writeMap(this.overlayables);
+        dest.writeString(this.staticSharedLibName);
+        dest.writeLong(this.staticSharedLibVersion);
+        dest.writeStringList(this.libraryNames);
+        dest.writeStringList(this.usesLibraries);
+        dest.writeStringList(this.usesOptionalLibraries);
+        dest.writeStringList(this.usesStaticLibraries);
+        dest.writeLongArray(this.usesStaticLibrariesVersions);
+
+        if (this.usesStaticLibrariesCertDigests == null) {
+            dest.writeInt(-1);
+        } else {
+            dest.writeInt(this.usesStaticLibrariesCertDigests.length);
+            for (int index = 0; index < this.usesStaticLibrariesCertDigests.length; index++) {
+                dest.writeStringArray(this.usesStaticLibrariesCertDigests[index]);
+            }
+        }
+
+        dest.writeString(this.sharedUserId);
+        dest.writeInt(this.sharedUserLabel);
+        dest.writeTypedList(this.configPreferences);
+        dest.writeTypedList(this.reqFeatures);
+        dest.writeTypedList(this.featureGroups);
+        dest.writeByteArray(this.restrictUpdateHash);
+        dest.writeStringList(this.originalPackages);
+        dest.writeStringList(this.adoptPermissions);
+        dest.writeStringList(this.requestedPermissions);
+        dest.writeStringList(this.implicitPermissions);
+        dest.writeArraySet(this.upgradeKeySets);
+        dest.writeMap(this.keySetMapping);
+        dest.writeStringList(this.protectedBroadcasts);
+        dest.writeTypedList(this.activities);
+        dest.writeTypedList(this.receivers);
+        dest.writeTypedList(this.services);
+        dest.writeTypedList(this.providers);
+        dest.writeTypedList(this.permissions);
+        dest.writeTypedList(this.permissionGroups);
+        dest.writeTypedList(this.instrumentations);
+        ParsedIntentInfo.writeIntentsList(this.preferredActivityFilters, dest, flags);
+        dest.writeBundle(this.appMetaData);
+        dest.writeString(this.volumeUuid);
+        dest.writeString(this.applicationVolumeUuid);
+        dest.writeParcelable(this.signingDetails, flags);
+        dest.writeString(this.codePath);
+        dest.writeBoolean(this.use32BitAbi);
+        dest.writeBoolean(this.visibleToInstantApps);
+        dest.writeString(this.cpuAbiOverride);
+        dest.writeBoolean(this.isStub);
+        dest.writeInt(this.preferredOrder);
+        dest.writeBoolean(this.forceQueryable);
+        dest.writeParcelableList(this.queriesIntents, flags);
+        dest.writeStringList(this.queriesPackages);
+        dest.writeString(this.applicationInfoBaseResourcePath);
+        dest.writeString(this.applicationInfoCodePath);
+        dest.writeString(this.applicationInfoResourcePath);
+        dest.writeStringArray(this.applicationInfoSplitResourcePaths);
+        dest.writeString(this.appComponentFactory);
+        dest.writeString(this.backupAgentName);
+        dest.writeInt(this.banner);
+        dest.writeInt(this.category);
+        dest.writeString(this.classLoaderName);
+        dest.writeString(this.className);
+        dest.writeInt(this.compatibleWidthLimitDp);
+        dest.writeString(this.credentialProtectedDataDir);
+        dest.writeString(this.dataDir);
+        dest.writeInt(this.descriptionRes);
+        dest.writeString(this.deviceProtectedDataDir);
+        dest.writeBoolean(this.enabled);
+        dest.writeInt(this.flags);
+        dest.writeInt(this.fullBackupContent);
+        dest.writeBoolean(this.hiddenUntilInstalled);
+        dest.writeInt(this.icon);
+        dest.writeInt(this.iconRes);
+        dest.writeInt(this.installLocation);
+        dest.writeInt(this.labelRes);
+        dest.writeInt(this.largestWidthLimitDp);
+        dest.writeInt(this.logo);
+        dest.writeString(this.manageSpaceActivityName);
+        dest.writeFloat(this.maxAspectRatio);
+        dest.writeFloat(this.minAspectRatio);
+        dest.writeInt(this.minSdkVersion);
+        dest.writeString(this.name);
+        dest.writeString(this.nativeLibraryDir);
+        dest.writeString(this.nativeLibraryRootDir);
+        dest.writeBoolean(this.nativeLibraryRootRequiresIsa);
+        dest.writeInt(this.networkSecurityConfigRes);
+        dest.writeCharSequence(this.nonLocalizedLabel);
+        dest.writeString(this.permission);
+        dest.writeString(this.primaryCpuAbi);
+        dest.writeInt(this.privateFlags);
+        dest.writeString(this.processName);
+        dest.writeInt(this.requiresSmallestWidthDp);
+        dest.writeInt(this.roundIconRes);
+        dest.writeString(this.secondaryCpuAbi);
+        dest.writeString(this.secondaryNativeLibraryDir);
+        dest.writeString(this.seInfo);
+        dest.writeString(this.seInfoUser);
+        dest.writeInt(this.targetSandboxVersion);
+        dest.writeInt(this.targetSdkVersion);
+        dest.writeString(this.taskAffinity);
+        dest.writeInt(this.theme);
+        dest.writeInt(this.uid);
+        dest.writeInt(this.uiOptions);
+        dest.writeStringArray(this.usesLibraryFiles);
+        dest.writeTypedList(this.usesLibraryInfos);
+        dest.writeString(this.zygotePreloadName);
+        dest.writeStringArray(this.splitClassLoaderNames);
+        dest.writeStringArray(this.splitCodePaths);
+        dest.writeSparseArray(this.splitDependencies);
+        dest.writeIntArray(this.splitFlags);
+        dest.writeStringArray(this.splitNames);
+        dest.writeIntArray(this.splitRevisionCodes);
+    }
+
+    public PackageImpl(Parcel in) {
+        // We use the boot classloader for all classes that we load.
+        final ClassLoader boot = Object.class.getClassLoader();
+        this.supportsSmallScreens = in.readInt();
+        this.supportsNormalScreens = in.readInt();
+        this.supportsLargeScreens = in.readInt();
+        this.supportsXLargeScreens = in.readInt();
+        this.resizeable = in.readInt();
+        this.anyDensity = in.readInt();
+        this.lastPackageUsageTimeInMills = in.createLongArray();
+        this.versionCode = in.readInt();
+        this.versionCodeMajor = in.readInt();
+        this.baseRevisionCode = in.readInt();
+        this.versionName = TextUtils.safeIntern(in.readString());
+        this.coreApp = in.readBoolean();
+        this.compileSdkVersion = in.readInt();
+        this.compileSdkVersionCodename = TextUtils.safeIntern(in.readString());
+        this.packageName = TextUtils.safeIntern(in.readString());
+        this.realPackage = in.readString();
+        this.manifestPackageName = in.readString();
+        this.baseCodePath = in.readString();
+        this.requiredForAllUsers = in.readBoolean();
+        this.restrictedAccountType = in.readString();
+        this.requiredAccountType = in.readString();
+        this.baseHardwareAccelerated = in.readBoolean();
+        this.overlayTarget = in.readString();
+        this.overlayTargetName = in.readString();
+        this.overlayCategory = in.readString();
+        this.overlayPriority = in.readInt();
+        this.overlayIsStatic = in.readBoolean();
+        this.overlayables = new HashMap<>();
+        in.readMap(overlayables, boot);
+        this.staticSharedLibName = TextUtils.safeIntern(in.readString());
+        this.staticSharedLibVersion = in.readLong();
+        this.libraryNames = in.createStringArrayList();
+        internStringArrayList(this.libraryNames);
+        this.usesLibraries = in.createStringArrayList();
+        internStringArrayList(this.usesLibraries);
+        this.usesOptionalLibraries = in.createStringArrayList();
+        internStringArrayList(this.usesOptionalLibraries);
+        this.usesStaticLibraries = in.createStringArrayList();
+        internStringArrayList(usesStaticLibraries);
+        this.usesStaticLibrariesVersions = in.createLongArray();
+
+        int digestsSize = in.readInt();
+        if (digestsSize >= 0) {
+            this.usesStaticLibrariesCertDigests = new String[digestsSize][];
+            for (int index = 0; index < digestsSize; index++) {
+                this.usesStaticLibrariesCertDigests[index] = in.readStringArray();
+            }
+        }
+
+        this.sharedUserId = TextUtils.safeIntern(in.readString());
+        this.sharedUserLabel = in.readInt();
+        this.configPreferences = in.createTypedArrayList(ConfigurationInfo.CREATOR);
+        this.reqFeatures = in.createTypedArrayList(FeatureInfo.CREATOR);
+        this.featureGroups = in.createTypedArrayList(FeatureGroupInfo.CREATOR);
+        this.restrictUpdateHash = in.createByteArray();
+        this.originalPackages = in.createStringArrayList();
+        this.adoptPermissions = in.createStringArrayList();
+        this.requestedPermissions = in.createStringArrayList();
+        internStringArrayList(this.requestedPermissions);
+        this.implicitPermissions = in.createStringArrayList();
+        internStringArrayList(this.implicitPermissions);
+        this.upgradeKeySets = (ArraySet<String>) in.readArraySet(boot);
+        this.keySetMapping = in.readHashMap(boot);
+        this.protectedBroadcasts = in.createStringArrayList();
+        internStringArrayList(this.protectedBroadcasts);
+        this.activities = in.createTypedArrayList(ParsedActivity.CREATOR);
+        this.receivers = in.createTypedArrayList(ParsedActivity.CREATOR);
+        this.services = in.createTypedArrayList(ParsedService.CREATOR);
+        this.providers = in.createTypedArrayList(ParsedProvider.CREATOR);
+        this.permissions = in.createTypedArrayList(ParsedPermission.CREATOR);
+        this.permissionGroups = in.createTypedArrayList(ParsedPermissionGroup.CREATOR);
+        this.instrumentations = in.createTypedArrayList(ParsedInstrumentation.CREATOR);
+        this.preferredActivityFilters = ParsedIntentInfo.createIntentsList(in);
+        this.appMetaData = in.readBundle(boot);
+        this.volumeUuid = in.readString();
+        this.applicationVolumeUuid = in.readString();
+        this.signingDetails = in.readParcelable(boot);
+        this.codePath = in.readString();
+        this.use32BitAbi = in.readBoolean();
+        this.visibleToInstantApps = in.readBoolean();
+        this.cpuAbiOverride = in.readString();
+        this.isStub = in.readBoolean();
+        this.preferredOrder = in.readInt();
+        this.forceQueryable = in.readBoolean();
+        this.queriesIntents = in.createTypedArrayList(Intent.CREATOR);
+        this.queriesPackages = in.createStringArrayList();
+        internStringArrayList(this.queriesPackages);
+        this.applicationInfoBaseResourcePath = in.readString();
+        this.applicationInfoCodePath = in.readString();
+        this.applicationInfoResourcePath = in.readString();
+        this.applicationInfoSplitResourcePaths = in.createStringArray();
+        this.appComponentFactory = in.readString();
+        this.backupAgentName = in.readString();
+        this.banner = in.readInt();
+        this.category = in.readInt();
+        this.classLoaderName = in.readString();
+        this.className = in.readString();
+        this.compatibleWidthLimitDp = in.readInt();
+        this.credentialProtectedDataDir = in.readString();
+        this.dataDir = in.readString();
+        this.descriptionRes = in.readInt();
+        this.deviceProtectedDataDir = in.readString();
+        this.enabled = in.readBoolean();
+        this.flags = in.readInt();
+        this.fullBackupContent = in.readInt();
+        this.hiddenUntilInstalled = in.readBoolean();
+        this.icon = in.readInt();
+        this.iconRes = in.readInt();
+        this.installLocation = in.readInt();
+        this.labelRes = in.readInt();
+        this.largestWidthLimitDp = in.readInt();
+        this.logo = in.readInt();
+        this.manageSpaceActivityName = in.readString();
+        this.maxAspectRatio = in.readFloat();
+        this.minAspectRatio = in.readFloat();
+        this.minSdkVersion = in.readInt();
+        this.name = in.readString();
+        this.nativeLibraryDir = in.readString();
+        this.nativeLibraryRootDir = in.readString();
+        this.nativeLibraryRootRequiresIsa = in.readBoolean();
+        this.networkSecurityConfigRes = in.readInt();
+        this.nonLocalizedLabel = in.readCharSequence();
+        this.permission = TextUtils.safeIntern(in.readString());
+        this.primaryCpuAbi = in.readString();
+        this.privateFlags = in.readInt();
+        this.processName = in.readString();
+        this.requiresSmallestWidthDp = in.readInt();
+        this.roundIconRes = in.readInt();
+        this.secondaryCpuAbi = in.readString();
+        this.secondaryNativeLibraryDir = in.readString();
+        this.seInfo = in.readString();
+        this.seInfoUser = in.readString();
+        this.targetSandboxVersion = in.readInt();
+        this.targetSdkVersion = in.readInt();
+        this.taskAffinity = in.readString();
+        this.theme = in.readInt();
+        this.uid = in.readInt();
+        this.uiOptions = in.readInt();
+        this.usesLibraryFiles = in.createStringArray();
+        this.usesLibraryInfos = in.createTypedArrayList(SharedLibraryInfo.CREATOR);
+        this.zygotePreloadName = in.readString();
+        this.splitClassLoaderNames = in.createStringArray();
+        this.splitCodePaths = in.createStringArray();
+        this.splitDependencies = in.readSparseArray(boot);
+        this.splitFlags = in.createIntArray();
+        this.splitNames = in.createStringArray();
+        this.splitRevisionCodes = in.createIntArray();
+    }
+
+    public static final Creator<PackageImpl> CREATOR = new Creator<PackageImpl>() {
+        @Override
+        public PackageImpl createFromParcel(Parcel source) {
+            return new PackageImpl(source);
+        }
+
+        @Override
+        public PackageImpl[] newArray(int size) {
+            return new PackageImpl[size];
+        }
+    };
+}
diff --git a/core/java/android/content/pm/parsing/PackageInfoUtils.java b/core/java/android/content/pm/parsing/PackageInfoUtils.java
new file mode 100644
index 0000000..28f0bc4
--- /dev/null
+++ b/core/java/android/content/pm/parsing/PackageInfoUtils.java
@@ -0,0 +1,572 @@
+/*
+ * 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.content.pm.parsing;
+
+import android.annotation.Nullable;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.FallbackCategoryProvider;
+import android.content.pm.FeatureGroupInfo;
+import android.content.pm.FeatureInfo;
+import android.content.pm.InstrumentationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageUserState;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.SELinuxUtil;
+import android.content.pm.ServiceInfo;
+import android.content.pm.Signature;
+import android.content.pm.SigningInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
+
+import com.android.internal.util.ArrayUtils;
+
+import java.util.Set;
+
+/** @hide */
+public class PackageInfoUtils {
+
+    private static final String TAG = ApkParseUtils.TAG;
+
+    /**
+     * Returns true if the package is installed and not hidden, or if the caller
+     * explicitly wanted all uninstalled and hidden packages as well.
+     */
+    private static boolean checkUseInstalledOrHidden(AndroidPackage pkg, PackageUserState state,
+            @PackageManager.PackageInfoFlags int flags) {
+        // Returns false if the package is hidden system app until installed.
+        if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0
+                && !state.installed
+                && pkg.isHiddenUntilInstalled()) {
+            return false;
+        }
+
+        // If available for the target user, or trying to match uninstalled packages and it's
+        // a system app.
+        return state.isAvailable(flags)
+                || (pkg.isSystemApp()
+                && ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0
+                || (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0));
+    }
+
+    public static PackageInfo generate(AndroidPackage pkg, int[] gids,
+            @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
+            Set<String> grantedPermissions, PackageUserState state, int userId) {
+        if (!checkUseInstalledOrHidden(pkg, state, flags) || !pkg.isMatch(flags)) {
+            return null;
+        }
+        ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+
+        PackageInfo pi = new PackageInfo();
+        pi.packageName = pkg.getPackageName();
+        pi.splitNames = pkg.getSplitNames();
+        pi.versionCode = pkg.getVersionCode();
+        pi.versionCodeMajor = pkg.getVersionCodeMajor();
+        pi.baseRevisionCode = pkg.getBaseRevisionCode();
+        pi.splitRevisionCodes = pkg.getSplitRevisionCodes();
+        pi.versionName = pkg.getVersionName();
+        pi.sharedUserId = pkg.getSharedUserId();
+        pi.sharedUserLabel = pkg.getSharedUserLabel();
+        pi.applicationInfo = applicationInfo;
+        pi.installLocation = pkg.getInstallLocation();
+        pi.isStub = pkg.isStub();
+        pi.coreApp = pkg.isCoreApp();
+        if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
+                || (pi.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
+            pi.requiredForAllUsers = pkg.isRequiredForAllUsers();
+        }
+        pi.restrictedAccountType = pkg.getRestrictedAccountType();
+        pi.requiredAccountType = pkg.getRequiredAccountType();
+        pi.overlayTarget = pkg.getOverlayTarget();
+        pi.targetOverlayableName = pkg.getOverlayTargetName();
+        pi.overlayCategory = pkg.getOverlayCategory();
+        pi.overlayPriority = pkg.getOverlayPriority();
+        pi.mOverlayIsStatic = pkg.isOverlayIsStatic();
+        pi.compileSdkVersion = pkg.getCompileSdkVersion();
+        pi.compileSdkVersionCodename = pkg.getCompileSdkVersionCodeName();
+        pi.firstInstallTime = firstInstallTime;
+        pi.lastUpdateTime = lastUpdateTime;
+        if ((flags & PackageManager.GET_GIDS) != 0) {
+            pi.gids = gids;
+        }
+        if ((flags & PackageManager.GET_CONFIGURATIONS) != 0) {
+            int size = pkg.getConfigPreferences() != null ? pkg.getConfigPreferences().size() : 0;
+            if (size > 0) {
+                pi.configPreferences = new ConfigurationInfo[size];
+                pkg.getConfigPreferences().toArray(pi.configPreferences);
+            }
+            size = pkg.getReqFeatures() != null ? pkg.getReqFeatures().size() : 0;
+            if (size > 0) {
+                pi.reqFeatures = new FeatureInfo[size];
+                pkg.getReqFeatures().toArray(pi.reqFeatures);
+            }
+            size = pkg.getFeatureGroups() != null ? pkg.getFeatureGroups().size() : 0;
+            if (size > 0) {
+                pi.featureGroups = new FeatureGroupInfo[size];
+                pkg.getFeatureGroups().toArray(pi.featureGroups);
+            }
+        }
+        if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
+            if (pkg.getActivities() != null) {
+                final int N = pkg.getActivities().size();
+                if (N > 0) {
+                    int num = 0;
+                    final ActivityInfo[] res = new ActivityInfo[N];
+                    for (int i = 0; i < N; i++) {
+                        final ParsedActivity a = pkg.getActivities().get(i);
+                        if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), a, flags)) {
+                            if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(
+                                    a.className)) {
+                                continue;
+                            }
+                            res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo,
+                                    userId);
+                        }
+                    }
+                    pi.activities = ArrayUtils.trimToSize(res, num);
+                }
+            }
+        }
+        if ((flags & PackageManager.GET_RECEIVERS) != 0) {
+            if (pkg.getReceivers() != null) {
+                final int size = pkg.getReceivers().size();
+                if (size > 0) {
+                    int num = 0;
+                    final ActivityInfo[] res = new ActivityInfo[size];
+                    for (int i = 0; i < size; i++) {
+                        final ParsedActivity a = pkg.getReceivers().get(i);
+                        if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), a, flags)) {
+                            res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo,
+                                    userId);
+                        }
+                    }
+                    pi.receivers = ArrayUtils.trimToSize(res, num);
+                }
+            }
+        }
+        if ((flags & PackageManager.GET_SERVICES) != 0) {
+            if (pkg.getServices() != null) {
+                final int size = pkg.getServices().size();
+                if (size > 0) {
+                    int num = 0;
+                    final ServiceInfo[] res = new ServiceInfo[size];
+                    for (int i = 0; i < size; i++) {
+                        final ComponentParseUtils.ParsedService s = pkg.getServices().get(i);
+                        if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), s, flags)) {
+                            res[num++] = generateServiceInfo(pkg, s, flags, state, applicationInfo,
+                                    userId);
+                        }
+                    }
+                    pi.services = ArrayUtils.trimToSize(res, num);
+                }
+            }
+        }
+        if ((flags & PackageManager.GET_PROVIDERS) != 0) {
+            if (pkg.getProviders() != null) {
+                final int size = pkg.getProviders().size();
+                if (size > 0) {
+                    int num = 0;
+                    final ProviderInfo[] res = new ProviderInfo[size];
+                    for (int i = 0; i < size; i++) {
+                        final ComponentParseUtils.ParsedProvider pr = pkg.getProviders()
+                                .get(i);
+                        if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), pr, flags)) {
+                            res[num++] = generateProviderInfo(pkg, pr, flags, state,
+                                    applicationInfo, userId);
+                        }
+                    }
+                    pi.providers = ArrayUtils.trimToSize(res, num);
+                }
+            }
+        }
+        if ((flags & PackageManager.GET_INSTRUMENTATION) != 0) {
+            if (pkg.getInstrumentations() != null) {
+                int N = pkg.getInstrumentations().size();
+                if (N > 0) {
+                    pi.instrumentation = new InstrumentationInfo[N];
+                    for (int i = 0; i < N; i++) {
+                        pi.instrumentation[i] = generateInstrumentationInfo(
+                                pkg.getInstrumentations().get(i), pkg, flags);
+                    }
+                }
+            }
+        }
+        if ((flags & PackageManager.GET_PERMISSIONS) != 0) {
+            if (pkg.getPermissions() != null) {
+                int N = ArrayUtils.size(pkg.getPermissions());
+                if (N > 0) {
+                    pi.permissions = new PermissionInfo[N];
+                    for (int i = 0; i < N; i++) {
+                        pi.permissions[i] = generatePermissionInfo(
+                                pkg.getPermissions().get(i),
+                                flags
+                        );
+                    }
+                }
+            }
+            if (pkg.getRequestedPermissions() != null) {
+                int N = pkg.getRequestedPermissions().size();
+                if (N > 0) {
+                    pi.requestedPermissions = new String[N];
+                    pi.requestedPermissionsFlags = new int[N];
+                    for (int i = 0; i < N; i++) {
+                        final String perm = pkg.getRequestedPermissions().get(i);
+                        pi.requestedPermissions[i] = perm;
+                        // The notion of required permissions is deprecated but for compatibility.
+                        pi.requestedPermissionsFlags[i] |=
+                                PackageInfo.REQUESTED_PERMISSION_REQUIRED;
+                        if (grantedPermissions != null && grantedPermissions.contains(perm)) {
+                            pi.requestedPermissionsFlags[i] |=
+                                    PackageInfo.REQUESTED_PERMISSION_GRANTED;
+                        }
+                    }
+                }
+            }
+        }
+
+        PackageParser.SigningDetails signingDetails = pkg.getSigningDetails();
+        // deprecated method of getting signing certificates
+        if ((flags & PackageManager.GET_SIGNATURES) != 0) {
+            if (signingDetails.hasPastSigningCertificates()) {
+                // Package has included signing certificate rotation information.  Return the oldest
+                // cert so that programmatic checks keep working even if unaware of key rotation.
+                pi.signatures = new Signature[1];
+                pi.signatures[0] = signingDetails.pastSigningCertificates[0];
+            } else if (signingDetails.hasSignatures()) {
+                // otherwise keep old behavior
+                int numberOfSigs = signingDetails.signatures.length;
+                pi.signatures = new Signature[numberOfSigs];
+                System.arraycopy(signingDetails.signatures, 0, pi.signatures, 0,
+                        numberOfSigs);
+            }
+        }
+
+        // replacement for GET_SIGNATURES
+        if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) {
+            if (signingDetails != PackageParser.SigningDetails.UNKNOWN) {
+                // only return a valid SigningInfo if there is signing information to report
+                pi.signingInfo = new SigningInfo(signingDetails);
+            } else {
+                pi.signingInfo = null;
+            }
+        }
+
+        return pi;
+    }
+
+    @Nullable
+    public static ApplicationInfo generateApplicationInfo(AndroidPackage pkg,
+            @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId) {
+
+        if (pkg == null) return null;
+        if (!checkUseInstalledOrHidden(pkg, state, flags) || !pkg.isMatch(flags)) {
+            return null;
+        }
+
+        // Make shallow copy so we can store the metadata/libraries safely
+        ApplicationInfo ai = pkg.toAppInfoWithoutState();
+        ai.initForUser(userId);
+        if ((flags & PackageManager.GET_META_DATA) == 0) {
+            ai.metaData = null;
+        }
+        if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) == 0) {
+            ai.sharedLibraryFiles = null;
+            ai.sharedLibraryInfos = null;
+        }
+        if (state.stopped) {
+            ai.flags |= ApplicationInfo.FLAG_STOPPED;
+        } else {
+            ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
+        }
+        updateApplicationInfo(ai, flags, state);
+
+        return ai;
+    }
+
+    private static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,
+            @PackageManager.ComponentInfoFlags int flags, PackageUserState state,
+            @Nullable ApplicationInfo applicationInfo, int userId) {
+        if (a == null) return null;
+        if (!checkUseInstalledOrHidden(pkg, state, flags)) {
+            return null;
+        }
+        if (applicationInfo == null) {
+            applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+        }
+        // Make shallow copies so we can store the metadata safely
+        ActivityInfo ai = new ActivityInfo();
+        assignSharedFieldsForComponentInfo(ai, a);
+        ai.targetActivity = a.targetActivity;
+        ai.processName = a.getProcessName();
+        ai.exported = a.exported;
+        ai.theme = a.theme;
+        ai.uiOptions = a.uiOptions;
+        ai.parentActivityName = a.parentActivityName;
+        ai.permission = a.getPermission();
+        ai.taskAffinity = a.taskAffinity;
+        ai.flags = a.flags;
+        ai.privateFlags = a.privateFlags;
+        ai.launchMode = a.launchMode;
+        ai.documentLaunchMode = a.documentLaunchMode;
+        ai.maxRecents = a.maxRecents;
+        ai.configChanges = a.configChanges;
+        ai.softInputMode = a.softInputMode;
+        ai.persistableMode = a.persistableMode;
+        ai.lockTaskLaunchMode = a.lockTaskLaunchMode;
+        ai.screenOrientation = a.screenOrientation;
+        ai.resizeMode = a.resizeMode;
+        ai.maxAspectRatio = a.maxAspectRatio;
+        ai.minAspectRatio = a.minAspectRatio;
+        ai.requestedVrComponent = a.requestedVrComponent;
+        ai.rotationAnimation = a.rotationAnimation;
+        ai.colorMode = a.colorMode;
+        ai.windowLayout = a.windowLayout;
+        ai.metaData = a.metaData;
+        ai.applicationInfo = applicationInfo;
+        return ai;
+    }
+
+    public static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,
+            @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
+        return generateActivityInfo(pkg, a, flags, state, null, userId);
+    }
+
+    private static ServiceInfo generateServiceInfo(AndroidPackage pkg,
+            ComponentParseUtils.ParsedService s, @PackageManager.ComponentInfoFlags int flags,
+            PackageUserState state, @Nullable ApplicationInfo applicationInfo, int userId) {
+        if (s == null) return null;
+        if (!checkUseInstalledOrHidden(pkg, state, flags)) {
+            return null;
+        }
+        if (applicationInfo == null) {
+            applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+        }
+        // Make shallow copies so we can store the metadata safely
+        ServiceInfo si = new ServiceInfo();
+        assignSharedFieldsForComponentInfo(si, s);
+        si.exported = s.exported;
+        si.flags = s.flags;
+        si.metaData = s.metaData;
+        si.permission = s.getPermission();
+        si.processName = s.getProcessName();
+        si.mForegroundServiceType = s.foregroundServiceType;
+        si.metaData = s.metaData;
+        si.applicationInfo = applicationInfo;
+        return si;
+    }
+
+    public static ServiceInfo generateServiceInfo(AndroidPackage pkg,
+            ComponentParseUtils.ParsedService s, @PackageManager.ComponentInfoFlags int flags,
+            PackageUserState state, int userId) {
+        return generateServiceInfo(pkg, s, flags, state, null, userId);
+    }
+
+    private static ProviderInfo generateProviderInfo(AndroidPackage pkg,
+            ComponentParseUtils.ParsedProvider p, @PackageManager.ComponentInfoFlags int flags,
+            PackageUserState state, @Nullable ApplicationInfo applicationInfo, int userId) {
+        if (p == null) return null;
+        if (!checkUseInstalledOrHidden(pkg, state, flags)) {
+            return null;
+        }
+        if (applicationInfo == null) {
+            applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+        }
+        // Make shallow copies so we can store the metadata safely
+        ProviderInfo pi = new ProviderInfo();
+        assignSharedFieldsForComponentInfo(pi, p);
+        pi.exported = p.exported;
+        pi.flags = p.flags;
+        pi.processName = p.getProcessName();
+        pi.authority = p.getAuthority();
+        pi.isSyncable = p.isSyncable;
+        pi.readPermission = p.getReadPermission();
+        pi.writePermission = p.getWritePermission();
+        pi.grantUriPermissions = p.grantUriPermissions;
+        pi.forceUriPermissions = p.forceUriPermissions;
+        pi.multiprocess = p.multiProcess;
+        pi.initOrder = p.initOrder;
+        pi.uriPermissionPatterns = p.uriPermissionPatterns;
+        pi.pathPermissions = p.pathPermissions;
+        pi.metaData = p.metaData;
+        if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
+            pi.uriPermissionPatterns = null;
+        }
+        pi.applicationInfo = applicationInfo;
+        return pi;
+    }
+
+    public static ProviderInfo generateProviderInfo(AndroidPackage pkg,
+            ComponentParseUtils.ParsedProvider p, @PackageManager.ComponentInfoFlags int flags,
+            PackageUserState state, int userId) {
+        return generateProviderInfo(pkg, p, flags, state, null, userId);
+    }
+
+    public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i,
+            AndroidPackage pkg, @PackageManager.ComponentInfoFlags int flags) {
+        if (i == null) return null;
+
+        InstrumentationInfo ii = new InstrumentationInfo();
+        assignSharedFieldsForPackageItemInfo(ii, i);
+        ii.targetPackage = i.getTargetPackage();
+        ii.targetProcesses = i.getTargetProcesses();
+        ii.handleProfiling = i.handleProfiling;
+        ii.functionalTest = i.functionalTest;
+
+        ii.sourceDir = pkg.getBaseCodePath();
+        ii.publicSourceDir = pkg.getCodePath();
+        ii.splitNames = pkg.getSplitNames();
+        ii.splitSourceDirs = pkg.getSplitCodePaths();
+        ii.splitPublicSourceDirs = pkg.getSplitCodePaths();
+        ii.splitDependencies = pkg.getSplitDependencies();
+        ii.dataDir = pkg.getDataDir();
+        ii.deviceProtectedDataDir = pkg.getDeviceProtectedDataDir();
+        ii.credentialProtectedDataDir = pkg.getCredentialProtectedDataDir();
+        ii.primaryCpuAbi = pkg.getPrimaryCpuAbi();
+        ii.secondaryCpuAbi = pkg.getSecondaryCpuAbi();
+        ii.nativeLibraryDir = pkg.getNativeLibraryDir();
+        ii.secondaryNativeLibraryDir = pkg.getSecondaryNativeLibraryDir();
+
+        if ((flags & PackageManager.GET_META_DATA) == 0) {
+            return ii;
+        }
+        ii.metaData = i.metaData;
+        return ii;
+    }
+
+    public static PermissionInfo generatePermissionInfo(ParsedPermission p,
+            @PackageManager.ComponentInfoFlags int flags) {
+        if (p == null) return null;
+
+        PermissionInfo pi = new PermissionInfo(p.backgroundPermission);
+        assignSharedFieldsForPackageItemInfo(pi, p);
+        pi.group = p.getGroup();
+        pi.requestRes = p.requestRes;
+        pi.protectionLevel = p.protectionLevel;
+        pi.descriptionRes = p.descriptionRes;
+        pi.flags = p.flags;
+
+        if ((flags & PackageManager.GET_META_DATA) == 0) {
+            return pi;
+        }
+        pi.metaData = p.metaData;
+        return pi;
+    }
+
+    public static PermissionGroupInfo generatePermissionGroupInfo(ParsedPermissionGroup pg,
+            @PackageManager.ComponentInfoFlags int flags) {
+        if (pg == null) return null;
+
+        PermissionGroupInfo pgi = new PermissionGroupInfo(
+                pg.requestDetailResourceId,
+                pg.backgroundRequestResourceId,
+                pg.backgroundRequestDetailResourceId
+        );
+        assignSharedFieldsForPackageItemInfo(pgi, pg);
+        pgi.priority = pg.priority;
+        pgi.requestRes = pg.requestRes;
+        pgi.flags = pg.flags;
+
+        if ((flags & PackageManager.GET_META_DATA) == 0) {
+            return pgi;
+        }
+        pgi.metaData = pg.metaData;
+        return pgi;
+    }
+
+    private static void updateApplicationInfo(ApplicationInfo ai,
+            @PackageManager.ApplicationInfoFlags int flags,
+            PackageUserState state) {
+        // CompatibilityMode is global state.
+        if (!PackageParser.sCompatibilityModeEnabled) {
+            ai.disableCompatibilityMode();
+        }
+        if (state.installed) {
+            ai.flags |= ApplicationInfo.FLAG_INSTALLED;
+        } else {
+            ai.flags &= ~ApplicationInfo.FLAG_INSTALLED;
+        }
+        if (state.suspended) {
+            ai.flags |= ApplicationInfo.FLAG_SUSPENDED;
+        } else {
+            ai.flags &= ~ApplicationInfo.FLAG_SUSPENDED;
+        }
+        if (state.instantApp) {
+            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_INSTANT;
+        } else {
+            ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_INSTANT;
+        }
+        if (state.virtualPreload) {
+            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD;
+        } else {
+            ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD;
+        }
+        if (state.hidden) {
+            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
+        } else {
+            ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN;
+        }
+        if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+            ai.enabled = true;
+        } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
+            ai.enabled = (flags & PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0;
+        } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+                || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
+            ai.enabled = false;
+        }
+        ai.enabledSetting = state.enabled;
+        if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
+            ai.category = state.categoryHint;
+        }
+        if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
+            ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
+        }
+        ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state);
+        ai.resourceDirs = state.overlayPaths;
+        ai.icon = (PackageParser.sUseRoundIcon && ai.roundIconRes != 0)
+                ? ai.roundIconRes : ai.iconRes;
+    }
+
+    private static void assignSharedFieldsForPackageItemInfo(PackageItemInfo packageItemInfo,
+            ComponentParseUtils.ParsedComponent parsedComponent) {
+        packageItemInfo.banner = parsedComponent.banner;
+        packageItemInfo.icon = parsedComponent.icon;
+        packageItemInfo.labelRes = parsedComponent.labelRes;
+        packageItemInfo.logo = parsedComponent.logo;
+        packageItemInfo.name = parsedComponent.className;
+        packageItemInfo.nonLocalizedLabel = parsedComponent.nonLocalizedLabel;
+        packageItemInfo.packageName = parsedComponent.getPackageName();
+    }
+
+    private static void assignSharedFieldsForComponentInfo(ComponentInfo componentInfo,
+            ComponentParseUtils.ParsedComponent parsedComponent) {
+        assignSharedFieldsForPackageItemInfo(componentInfo, parsedComponent);
+        componentInfo.descriptionRes = parsedComponent.descriptionRes;
+        componentInfo.directBootAware = parsedComponent.directBootAware;
+        componentInfo.enabled = parsedComponent.enabled;
+        componentInfo.splitName = parsedComponent.getSplitName();
+    }
+
+}
diff --git a/core/java/android/content/pm/parsing/ParsedPackage.java b/core/java/android/content/pm/parsing/ParsedPackage.java
new file mode 100644
index 0000000..05cf586
--- /dev/null
+++ b/core/java/android/content/pm/parsing/ParsedPackage.java
@@ -0,0 +1,155 @@
+/*
+ * 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.content.pm.parsing;
+
+import android.content.pm.PackageParser;
+
+/**
+ * Methods used for mutation after direct package parsing, mostly done inside
+ * {@link com.android.server.pm.PackageManagerService}.
+ *
+ * Java disallows defining this as an inner interface, so this must be a separate file.
+ *
+ * @hide
+ */
+public interface ParsedPackage extends AndroidPackage {
+
+    AndroidPackage hideAsFinal();
+
+    ParsedPackage addUsesLibrary(int index, String libraryName);
+
+    ParsedPackage addUsesOptionalLibrary(int index, String libraryName);
+
+    ParsedPackage capPermissionPriorities();
+
+    ParsedPackage clearAdoptPermissions();
+
+    ParsedPackage clearOriginalPackages();
+
+    ParsedPackage clearProtectedBroadcasts();
+
+    /**
+     * TODO(b/135203078): Use non-AppInfo method
+     * @deprecated use {@link #setCodePath(String)}
+     */
+    @Deprecated
+    ParsedPackage setApplicationInfoCodePath(String applicationInfoCodePath);
+
+    /**
+     * TODO(b/135203078): Use non-AppInfo method
+     * @deprecated use {@link #setCodePath(String)}
+     */
+    @Deprecated
+    ParsedPackage setApplicationInfoResourcePath(String applicationInfoResourcePath);
+
+    ParsedPackage setBaseCodePath(String baseCodePath);
+
+    ParsedPackage setCodePath(String codePath);
+
+    ParsedPackage setCpuAbiOverride(String cpuAbiOverride);
+
+    ParsedPackage setNativeLibraryDir(String nativeLibraryDir);
+
+    ParsedPackage setNativeLibraryRootDir(String nativeLibraryRootDir);
+
+    ParsedPackage setPackageName(String packageName);
+
+    ParsedPackage setPrimaryCpuAbi(String primaryCpuAbi);
+
+    ParsedPackage setProcessName(String processName);
+
+    ParsedPackage setRealPackage(String realPackage);
+
+    ParsedPackage setSecondaryCpuAbi(String secondaryCpuAbi);
+
+    ParsedPackage setSigningDetails(PackageParser.SigningDetails signingDetails);
+
+    ParsedPackage setSplitCodePaths(String[] splitCodePaths);
+
+    ParsedPackage initForUser(int userId);
+
+    ParsedPackage setNativeLibraryRootRequiresIsa(boolean nativeLibraryRootRequiresIsa);
+
+    ParsedPackage setAllComponentsDirectBootAware(boolean allComponentsDirectBootAware);
+
+    ParsedPackage setFactoryTest(boolean factoryTest);
+
+    ParsedPackage markNotActivitiesAsNotExportedIfSingleUser();
+
+    ParsedPackage setOdm(boolean odm);
+
+    ParsedPackage setOem(boolean oem);
+
+    ParsedPackage setPrivileged(boolean privileged);
+
+    ParsedPackage setProduct(boolean product);
+
+    ParsedPackage setSignedWithPlatformKey(boolean signedWithPlatformKey);
+
+    ParsedPackage setSystem(boolean system);
+
+    ParsedPackage setSystemExt(boolean systemExt);
+
+    ParsedPackage setUpdatedSystemApp(boolean updatedSystemApp);
+
+    ParsedPackage setVendor(boolean vendor);
+
+    ParsedPackage removePermission(int index);
+
+    ParsedPackage removeUsesLibrary(String libraryName);
+
+    ParsedPackage removeUsesOptionalLibrary(String libraryName);
+
+    ParsedPackage setApplicationInfoBaseResourcePath(String applicationInfoBaseResourcePath);
+
+    ParsedPackage setApplicationInfoSplitResourcePaths(
+            String[] applicationInfoSplitResourcePaths);
+
+    ParsedPackage setApplicationVolumeUuid(String applicationVolumeUuid);
+
+    ParsedPackage setCoreApp(boolean coreApp);
+
+    ParsedPackage setIsStub(boolean isStub);
+
+    // TODO(b/135203078): Remove entirely
+    ParsedPackage setPackageSettingCallback(PackageSettingCallback packageSettingCallback);
+
+    ParsedPackage setRestrictUpdateHash(byte[] restrictUpdateHash);
+
+    ParsedPackage setSeInfo(String seInfo);
+
+    ParsedPackage setSeInfoUser(String seInfoUser);
+
+    ParsedPackage setSecondaryNativeLibraryDir(String secondaryNativeLibraryDir);
+
+    ParsedPackage setUid(int uid);
+
+    ParsedPackage setVersionCode(int versionCode);
+
+    ParsedPackage setVersionCodeMajor(int versionCodeMajor);
+
+    // TODO(b/135203078): Move logic earlier in parse chain so nothing needs to be reverted
+    ParsedPackage setDefaultToDeviceProtectedStorage(boolean defaultToDeviceProtectedStorage);
+
+    ParsedPackage setDirectBootAware(boolean directBootAware);
+
+    ParsedPackage setPersistent(boolean persistent);
+
+    interface PackageSettingCallback {
+        default void setAndroidPackage(AndroidPackage pkg){}
+    }
+}
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
new file mode 100644
index 0000000..aff1b2e
--- /dev/null
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -0,0 +1,329 @@
+/*
+ * 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.content.pm.parsing;
+
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.FeatureGroupInfo;
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageParser;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
+import android.content.pm.parsing.ComponentParseUtils.ParsedService;
+import android.os.Bundle;
+import android.util.ArraySet;
+import android.util.SparseArray;
+
+import java.security.PublicKey;
+
+/**
+ * Methods used for mutation during direct package parsing.
+ *
+ * Java disallows defining this as an inner interface, so this must be a separate file.
+ *
+ * @hide
+ */
+public interface ParsingPackage extends AndroidPackage {
+
+    ParsingPackage addActivity(ParsedActivity parsedActivity);
+
+    ParsingPackage addAdoptPermission(String adoptPermission);
+
+    ParsingPackage addConfigPreference(ConfigurationInfo configPreference);
+
+    ParsingPackage addFeatureGroup(FeatureGroupInfo featureGroup);
+
+    ParsingPackage addImplicitPermission(String permission);
+
+    ParsingPackage addInstrumentation(ParsedInstrumentation instrumentation);
+
+    ParsingPackage addKeySet(String keySetName, PublicKey publicKey);
+
+    ParsingPackage addLibraryName(String libraryName);
+
+    ParsingPackage addOriginalPackage(String originalPackage);
+
+    ParsingPackage addOverlayable(String overlayableName, String actorName);
+
+    ParsingPackage addPermission(ParsedPermission permission);
+
+    ParsingPackage addPermissionGroup(ParsedPermissionGroup permissionGroup);
+
+    ParsingPackage addPreferredActivityFilter(ParsedActivityIntentInfo activityIntentInfo);
+
+    ParsingPackage addProtectedBroadcast(String protectedBroadcast);
+
+    ParsingPackage addProvider(ParsedProvider parsedProvider);
+
+    ParsingPackage addReceiver(ParsedActivity parsedReceiver);
+
+    ParsingPackage addReqFeature(FeatureInfo reqFeature);
+
+    ParsingPackage addRequestedPermission(String permission);
+
+    ParsingPackage addService(ParsedService parsedService);
+
+    ParsingPackage addUsesLibrary(String libraryName);
+
+    ParsingPackage addUsesOptionalLibrary(String libraryName);
+
+    ParsingPackage addUsesStaticLibrary(String libraryName);
+
+    ParsingPackage addUsesStaticLibraryCertDigests(String[] certSha256Digests);
+
+    ParsingPackage addUsesStaticLibraryVersion(long version);
+
+    ParsingPackage addQueriesIntent(Intent intent);
+
+    ParsingPackage addQueriesPackage(String packageName);
+
+    ParsingPackage asSplit(
+            String[] splitNames,
+            String[] splitCodePaths,
+            int[] splitRevisionCodes,
+            @Nullable SparseArray<int[]> splitDependencies
+    );
+
+    ParsingPackage setAppMetaData(Bundle appMetaData);
+
+    ParsingPackage setForceQueryable(boolean forceQueryable);
+
+    ParsingPackage setMaxAspectRatio(float maxAspectRatio);
+
+    ParsingPackage setMinAspectRatio(float minAspectRatio);
+
+    ParsingPackage setName(String name);
+
+    ParsingPackage setPermission(String permission);
+
+    ParsingPackage setProcessName(String processName);
+
+    ParsingPackage setSharedUserId(String sharedUserId);
+
+    ParsingPackage setStaticSharedLibName(String staticSharedLibName);
+
+    ParsingPackage setTaskAffinity(String taskAffinity);
+
+    ParsingPackage setTargetSdkVersion(int targetSdkVersion);
+
+    ParsingPackage setUiOptions(int uiOptions);
+
+    ParsingPackage setBaseHardwareAccelerated(boolean baseHardwareAccelerated);
+
+    ParsingPackage setActivitiesResizeModeResizeable(boolean resizeable);
+
+    ParsingPackage setActivitiesResizeModeResizeableViaSdkVersion(boolean resizeableViaSdkVersion);
+
+    ParsingPackage setAllowAudioPlaybackCapture(boolean allowAudioPlaybackCapture);
+
+    ParsingPackage setAllowBackup(boolean allowBackup);
+
+    ParsingPackage setAllowClearUserData(boolean allowClearUserData);
+
+    ParsingPackage setAllowClearUserDataOnFailedRestore(boolean allowClearUserDataOnFailedRestore);
+
+    ParsingPackage setAllowTaskReparenting(boolean allowTaskReparenting);
+
+    ParsingPackage setIsOverlay(boolean isOverlay);
+
+    ParsingPackage setBackupInForeground(boolean backupInForeground);
+
+    ParsingPackage setCantSaveState(boolean cantSaveState);
+
+    ParsingPackage setDebuggable(boolean debuggable);
+
+    ParsingPackage setDefaultToDeviceProtectedStorage(boolean defaultToDeviceProtectedStorage);
+
+    ParsingPackage setDirectBootAware(boolean directBootAware);
+
+    ParsingPackage setExternalStorage(boolean externalStorage);
+
+    ParsingPackage setExtractNativeLibs(boolean extractNativeLibs);
+
+    ParsingPackage setFullBackupOnly(boolean fullBackupOnly);
+
+    ParsingPackage setHasCode(boolean hasCode);
+
+    ParsingPackage setHasFragileUserData(boolean hasFragileUserData);
+
+    ParsingPackage setIsGame(boolean isGame);
+
+    ParsingPackage setIsolatedSplitLoading(boolean isolatedSplitLoading);
+
+    ParsingPackage setKillAfterRestore(boolean killAfterRestore);
+
+    ParsingPackage setLargeHeap(boolean largeHeap);
+
+    ParsingPackage setMultiArch(boolean multiArch);
+
+    ParsingPackage setPartiallyDirectBootAware(boolean partiallyDirectBootAware);
+
+    ParsingPackage setPersistent(boolean persistent);
+
+    ParsingPackage setProfileableByShell(boolean profileableByShell);
+
+    ParsingPackage setRequestLegacyExternalStorage(boolean requestLegacyExternalStorage);
+
+    ParsingPackage setRestoreAnyVersion(boolean restoreAnyVersion);
+
+    ParsingPackage setSplitHasCode(int splitIndex, boolean splitHasCode);
+
+    ParsingPackage setStaticSharedLibrary(boolean staticSharedLibrary);
+
+    ParsingPackage setSupportsRtl(boolean supportsRtl);
+
+    ParsingPackage setTestOnly(boolean testOnly);
+
+    ParsingPackage setUseEmbeddedDex(boolean useEmbeddedDex);
+
+    ParsingPackage setUsesCleartextTraffic(boolean usesCleartextTraffic);
+
+    ParsingPackage setUsesNonSdkApi(boolean usesNonSdkApi);
+
+    ParsingPackage setVisibleToInstantApps(boolean visibleToInstantApps);
+
+    ParsingPackage setVmSafeMode(boolean vmSafeMode);
+
+    ParsingPackage removeUsesOptionalLibrary(String libraryName);
+
+    ParsingPackage setAnyDensity(int anyDensity);
+
+    ParsingPackage setAppComponentFactory(String appComponentFactory);
+
+    ParsingPackage setApplicationVolumeUuid(String applicationVolumeUuid);
+
+    ParsingPackage setBackupAgentName(String backupAgentName);
+
+    ParsingPackage setBanner(int banner);
+
+    ParsingPackage setCategory(int category);
+
+    ParsingPackage setClassLoaderName(String classLoaderName);
+
+    ParsingPackage setClassName(String className);
+
+    ParsingPackage setCodePath(String codePath);
+
+    ParsingPackage setCompatibleWidthLimitDp(int compatibleWidthLimitDp);
+
+    ParsingPackage setDescriptionRes(int descriptionRes);
+
+    ParsingPackage setEnabled(boolean enabled);
+
+    ParsingPackage setFullBackupContent(int fullBackupContent);
+
+    ParsingPackage setHasDomainUrls(boolean hasDomainUrls);
+
+    ParsingPackage setIcon(int icon);
+
+    ParsingPackage setIconRes(int iconRes);
+
+    ParsingPackage setInstallLocation(int installLocation);
+
+    ParsingPackage setLabelRes(int labelRes);
+
+    ParsingPackage setLargestWidthLimitDp(int largestWidthLimitDp);
+
+    ParsingPackage setLogo(int logo);
+
+    ParsingPackage setManageSpaceActivityName(String manageSpaceActivityName);
+
+    ParsingPackage setMinSdkVersion(int minSdkVersion);
+
+    ParsingPackage setNetworkSecurityConfigRes(int networkSecurityConfigRes);
+
+    ParsingPackage setNonLocalizedLabel(CharSequence nonLocalizedLabel);
+
+    ParsingPackage setOverlayCategory(String overlayCategory);
+
+    ParsingPackage setOverlayIsStatic(boolean overlayIsStatic);
+
+    ParsingPackage setOverlayPriority(int overlayPriority);
+
+    ParsingPackage setOverlayTarget(String overlayTarget);
+
+    ParsingPackage setOverlayTargetName(String overlayTargetName);
+
+    ParsingPackage setRealPackage(String realPackage);
+
+    ParsingPackage setRequiredAccountType(String requiredAccountType);
+
+    ParsingPackage setRequiredForAllUsers(boolean requiredForAllUsers);
+
+    ParsingPackage setRequiresSmallestWidthDp(int requiresSmallestWidthDp);
+
+    ParsingPackage setResizeable(int resizeable);
+
+    ParsingPackage setRestrictUpdateHash(byte[] restrictUpdateHash);
+
+    ParsingPackage setRestrictedAccountType(String restrictedAccountType);
+
+    ParsingPackage setRoundIconRes(int roundIconRes);
+
+    ParsingPackage setSharedUserLabel(int sharedUserLabel);
+
+    ParsingPackage setSigningDetails(PackageParser.SigningDetails signingDetails);
+
+    ParsingPackage setSplitClassLoaderName(int splitIndex, String classLoaderName);
+
+    ParsingPackage setStaticSharedLibVersion(long staticSharedLibVersion);
+
+    ParsingPackage setSupportsLargeScreens(int supportsLargeScreens);
+
+    ParsingPackage setSupportsNormalScreens(int supportsNormalScreens);
+
+    ParsingPackage setSupportsSmallScreens(int supportsSmallScreens);
+
+    ParsingPackage setSupportsXLargeScreens(int supportsXLargeScreens);
+
+    ParsingPackage setTargetSandboxVersion(int targetSandboxVersion);
+
+    ParsingPackage setTheme(int theme);
+
+    ParsingPackage setUpgradeKeySets(ArraySet<String> upgradeKeySets);
+
+    ParsingPackage setUse32BitAbi(boolean use32BitAbi);
+
+    ParsingPackage setVolumeUuid(String volumeUuid);
+
+    ParsingPackage setZygotePreloadName(String zygotePreloadName);
+
+    ParsingPackage sortActivities();
+
+    ParsingPackage sortReceivers();
+
+    ParsingPackage sortServices();
+
+    ParsedPackage hideAsParsed();
+
+    ParsingPackage setBaseRevisionCode(int baseRevisionCode);
+
+    ParsingPackage setPreferredOrder(int preferredOrder);
+
+    ParsingPackage setVersionName(String versionName);
+
+    ParsingPackage setCompileSdkVersion(int compileSdkVersion);
+
+    ParsingPackage setCompileSdkVersionCodename(String compileSdkVersionCodename);
+
+    boolean usesCompatibilityMode();
+}
diff --git a/core/java/android/content/pm/parsing/library/AndroidHidlUpdater.java b/core/java/android/content/pm/parsing/library/AndroidHidlUpdater.java
new file mode 100644
index 0000000..81b4bc5
--- /dev/null
+++ b/core/java/android/content/pm/parsing/library/AndroidHidlUpdater.java
@@ -0,0 +1,50 @@
+/*
+ * 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.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_BASE;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_MANAGER;
+
+import android.content.pm.parsing.ParsedPackage;
+import android.os.Build;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Updates a package to ensure that if it targets <= P that the android.hidl.base-V1.0-java
+ * and android.hidl.manager-V1.0-java libraries are included by default.
+ *
+ * @hide
+ */
+@VisibleForTesting
+public class AndroidHidlUpdater extends PackageSharedLibraryUpdater {
+
+    @Override
+    public void updatePackage(ParsedPackage parsedPackage) {
+        // This was the default <= P and is maintained for backwards compatibility.
+        boolean isLegacy = parsedPackage.getTargetSdkVersion() <= Build.VERSION_CODES.P;
+        // Only system apps use these libraries
+        boolean isSystem = parsedPackage.isSystemApp() || parsedPackage.isUpdatedSystemApp();
+
+        if (isLegacy && isSystem) {
+            prefixRequiredLibrary(parsedPackage, ANDROID_HIDL_BASE);
+            prefixRequiredLibrary(parsedPackage, ANDROID_HIDL_MANAGER);
+        } else {
+            removeLibrary(parsedPackage, ANDROID_HIDL_BASE);
+            removeLibrary(parsedPackage, ANDROID_HIDL_MANAGER);
+        }
+    }
+}
diff --git a/core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java b/core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java
new file mode 100644
index 0000000..5fbe5b9
--- /dev/null
+++ b/core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java
@@ -0,0 +1,89 @@
+/*
+ * 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.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
+
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
+import android.content.Context;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ParsedPackage;
+import android.os.Build;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.compat.IPlatformCompat;
+
+/**
+ * Updates a package to ensure that if it targets <= Q that the android.test.base library is
+ * included by default.
+ *
+ * <p>This is separated out so that it can be conditionally included at build time depending on
+ * whether android.test.base is on the bootclasspath or not. In order to include this at
+ * build time, and remove android.test.base from the bootclasspath pass
+ * REMOVE_ATB_FROM_BCP=true on the build command line, otherwise this class will not be included
+ * and the
+ *
+ * @hide
+ */
+@VisibleForTesting
+public class AndroidTestBaseUpdater extends PackageSharedLibraryUpdater {
+    private static final String TAG = "AndroidTestBaseUpdater";
+
+    /**
+     * Remove android.test.base library for apps that target SDK R or more and do not depend on
+     * android.test.runner (as it depends on classes from the android.test.base library).
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
+    private static final long REMOVE_ANDROID_TEST_BASE = 133396946L;
+
+    private static boolean isChangeEnabled(AndroidPackage pkg) {
+        // Do not ask platform compat for system apps to prevent a boot time regression in tests.
+        // b/142558883.
+        if (!pkg.isSystem()) {
+            IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
+                    ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+            try {
+                return platformCompat.isChangeEnabled(REMOVE_ANDROID_TEST_BASE,
+                        pkg.toAppInfoWithoutState());
+            } catch (RemoteException | NullPointerException e) {
+                Log.e(TAG, "Failed to get a response from PLATFORM_COMPAT_SERVICE", e);
+            }
+        }
+        // Fall back to previous behaviour.
+        return pkg.getTargetSdkVersion() > Build.VERSION_CODES.Q;
+    }
+
+    @Override
+    public void updatePackage(ParsedPackage pkg) {
+        // Packages targeted at <= Q expect the classes in the android.test.base library
+        // to be accessible so this maintains backward compatibility by adding the
+        // android.test.base library to those packages.
+        if (!isChangeEnabled(pkg)) {
+            prefixRequiredLibrary(pkg, ANDROID_TEST_BASE);
+        } else {
+            // If a package already depends on android.test.runner then add a dependency on
+            // android.test.base because android.test.runner depends on classes from the
+            // android.test.base library.
+            prefixImplicitDependency(pkg, ANDROID_TEST_RUNNER, ANDROID_TEST_BASE);
+        }
+    }
+}
diff --git a/core/java/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdater.java b/core/java/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdater.java
new file mode 100644
index 0000000..613a06b
--- /dev/null
+++ b/core/java/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdater.java
@@ -0,0 +1,48 @@
+/*
+ * 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.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
+
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ParsedPackage;
+import android.os.Build;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Updates a package to ensure that if it targets < P that the org.apache.http.legacy library is
+ * included by default.
+ *
+ * @hide
+ */
+@VisibleForTesting
+public class OrgApacheHttpLegacyUpdater extends PackageSharedLibraryUpdater {
+
+    private static boolean apkTargetsApiLevelLessThanOrEqualToOMR1(AndroidPackage pkg) {
+        return pkg.getTargetSdkVersion() < Build.VERSION_CODES.P;
+    }
+
+    @Override
+    public void updatePackage(ParsedPackage parsedPackage) {
+        // Packages targeted at <= O_MR1 expect the classes in the org.apache.http.legacy library
+        // to be accessible so this maintains backward compatibility by adding the
+        // org.apache.http.legacy library to those packages.
+        if (apkTargetsApiLevelLessThanOrEqualToOMR1(parsedPackage)) {
+            prefixRequiredLibrary(parsedPackage, ORG_APACHE_HTTP_LEGACY);
+        }
+    }
+}
diff --git a/core/java/android/content/pm/parsing/library/PackageBackwardCompatibility.java b/core/java/android/content/pm/parsing/library/PackageBackwardCompatibility.java
new file mode 100644
index 0000000..1220fc4
--- /dev/null
+++ b/core/java/android/content/pm/parsing/library/PackageBackwardCompatibility.java
@@ -0,0 +1,199 @@
+/*
+ * 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.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
+import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
+
+import android.content.pm.parsing.ParsedPackage;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Supplier;
+
+/**
+ * Modifies {@link ParsedPackage} in order to maintain backwards compatibility.
+ *
+ * @hide
+ */
+@VisibleForTesting
+public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater {
+
+    private static final String TAG = PackageBackwardCompatibility.class.getSimpleName();
+
+    private static final PackageBackwardCompatibility INSTANCE;
+
+    static {
+        final List<PackageSharedLibraryUpdater> packageUpdaters = new ArrayList<>();
+
+        // Automatically add the org.apache.http.legacy library to the app classpath if the app
+        // targets < P.
+        packageUpdaters.add(new OrgApacheHttpLegacyUpdater());
+
+        packageUpdaters.add(new AndroidHidlUpdater());
+
+        // Add this before adding AndroidTestBaseUpdater so that android.test.base comes before
+        // android.test.mock.
+        packageUpdaters.add(new AndroidTestRunnerSplitUpdater());
+
+        // Attempt to load and add the optional updater that will only be available when
+        // REMOVE_ATB_FROM_BCP=true. If that could not be found then add the default updater that
+        // will remove any references to org.apache.http.library from the package so that it does
+        // not try and load the library when it is on the bootclasspath.
+        boolean bootClassPathContainsATB = !addOptionalUpdater(packageUpdaters,
+                "android.content.pm.parsing.library.AndroidTestBaseUpdater",
+                RemoveUnnecessaryAndroidTestBaseLibrary::new);
+
+        PackageSharedLibraryUpdater[] updaterArray = packageUpdaters
+                .toArray(new PackageSharedLibraryUpdater[0]);
+        INSTANCE = new PackageBackwardCompatibility(
+                bootClassPathContainsATB, updaterArray);
+    }
+
+    /**
+     * Add an optional {@link PackageSharedLibraryUpdater} instance to the list, if it could not be
+     * found then add a default instance instead.
+     *
+     * @param packageUpdaters the list to update.
+     * @param className the name of the optional class.
+     * @param defaultUpdater the supplier of the default instance.
+     * @return true if the optional updater was added false otherwise.
+     */
+    private static boolean addOptionalUpdater(List<PackageSharedLibraryUpdater> packageUpdaters,
+            String className, Supplier<PackageSharedLibraryUpdater> defaultUpdater) {
+        Class<? extends PackageSharedLibraryUpdater> clazz;
+        try {
+            clazz = (PackageBackwardCompatibility.class.getClassLoader()
+                    .loadClass(className)
+                    .asSubclass(PackageSharedLibraryUpdater.class));
+            Log.i(TAG, "Loaded " + className);
+        } catch (ClassNotFoundException e) {
+            Log.i(TAG, "Could not find " + className + ", ignoring");
+            clazz = null;
+        }
+
+        boolean usedOptional = false;
+        PackageSharedLibraryUpdater updater;
+        if (clazz == null) {
+            updater = defaultUpdater.get();
+        } else {
+            try {
+                updater = clazz.getConstructor().newInstance();
+                usedOptional = true;
+            } catch (ReflectiveOperationException e) {
+                throw new IllegalStateException("Could not create instance of " + className, e);
+            }
+        }
+        packageUpdaters.add(updater);
+        return usedOptional;
+    }
+
+    @VisibleForTesting
+    public static PackageSharedLibraryUpdater getInstance() {
+        return INSTANCE;
+    }
+
+    private final boolean mBootClassPathContainsATB;
+
+    private final PackageSharedLibraryUpdater[] mPackageUpdaters;
+
+    private PackageBackwardCompatibility(
+            boolean bootClassPathContainsATB, PackageSharedLibraryUpdater[] packageUpdaters) {
+        this.mBootClassPathContainsATB = bootClassPathContainsATB;
+        this.mPackageUpdaters = packageUpdaters;
+    }
+
+    /**
+     * Modify the shared libraries in the supplied {@link ParsedPackage} to maintain backwards
+     * compatibility.
+     *
+     * @param parsedPackage the {@link ParsedPackage} to modify.
+     */
+    @VisibleForTesting
+    public static void modifySharedLibraries(ParsedPackage parsedPackage) {
+        INSTANCE.updatePackage(parsedPackage);
+    }
+
+    @Override
+    public void updatePackage(ParsedPackage parsedPackage) {
+        for (PackageSharedLibraryUpdater packageUpdater : mPackageUpdaters) {
+            packageUpdater.updatePackage(parsedPackage);
+        }
+    }
+
+    /**
+     * True if the android.test.base is on the bootclasspath, false otherwise.
+     */
+    @VisibleForTesting
+    public static boolean bootClassPathContainsATB() {
+        return INSTANCE.mBootClassPathContainsATB;
+    }
+
+    /**
+     * Add android.test.mock dependency for any APK that depends on android.test.runner.
+     *
+     * <p>This is needed to maintain backwards compatibility as in previous versions of Android the
+     * android.test.runner library included the classes from android.test.mock which have since
+     * been split out into a separate library.
+     *
+     * @hide
+     */
+    @VisibleForTesting
+    public static class AndroidTestRunnerSplitUpdater extends PackageSharedLibraryUpdater {
+
+        @Override
+        public void updatePackage(ParsedPackage parsedPackage) {
+            // android.test.runner has a dependency on android.test.mock so if android.test.runner
+            // is present but android.test.mock is not then add android.test.mock.
+            prefixImplicitDependency(parsedPackage, ANDROID_TEST_RUNNER, ANDROID_TEST_MOCK);
+        }
+    }
+
+    /**
+     * Remove any usages of org.apache.http.legacy from the shared library as the library is on the
+     * bootclasspath.
+     */
+    @VisibleForTesting
+    public static class RemoveUnnecessaryOrgApacheHttpLegacyLibrary
+            extends PackageSharedLibraryUpdater {
+
+        @Override
+        public void updatePackage(ParsedPackage parsedPackage) {
+            removeLibrary(parsedPackage, ORG_APACHE_HTTP_LEGACY);
+        }
+
+    }
+
+    /**
+     * Remove any usages of android.test.base from the shared library as the library is on the
+     * bootclasspath.
+     */
+    @VisibleForTesting
+    public static class RemoveUnnecessaryAndroidTestBaseLibrary
+            extends PackageSharedLibraryUpdater {
+
+        @Override
+        public void updatePackage(ParsedPackage parsedPackage) {
+            removeLibrary(parsedPackage, ANDROID_TEST_BASE);
+        }
+    }
+}
diff --git a/core/java/android/content/pm/parsing/library/PackageSharedLibraryUpdater.java b/core/java/android/content/pm/parsing/library/PackageSharedLibraryUpdater.java
new file mode 100644
index 0000000..8b27d14
--- /dev/null
+++ b/core/java/android/content/pm/parsing/library/PackageSharedLibraryUpdater.java
@@ -0,0 +1,97 @@
+/*
+ * 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.content.pm.parsing.library;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.parsing.ParsedPackage;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Base for classes that update a {@link ParsedPackage}'s shared libraries.
+ *
+ * @hide
+ */
+@VisibleForTesting
+public abstract class PackageSharedLibraryUpdater {
+
+    /**
+     * Update the package's shared libraries.
+     *
+     * @param parsedPackage the package to update.
+     */
+    public abstract void updatePackage(ParsedPackage parsedPackage);
+
+    static void removeLibrary(ParsedPackage parsedPackage, String libraryName) {
+        parsedPackage.removeUsesLibrary(libraryName)
+                .removeUsesOptionalLibrary(libraryName);
+    }
+
+    static @NonNull
+            <T> ArrayList<T> prefix(@Nullable ArrayList<T> cur, T val) {
+        if (cur == null) {
+            cur = new ArrayList<>();
+        }
+        cur.add(0, val);
+        return cur;
+    }
+
+    private static boolean isLibraryPresent(List<String> usesLibraries,
+            List<String> usesOptionalLibraries, String apacheHttpLegacy) {
+        return ArrayUtils.contains(usesLibraries, apacheHttpLegacy)
+                || ArrayUtils.contains(usesOptionalLibraries, apacheHttpLegacy);
+    }
+
+    /**
+     * Add an implicit dependency.
+     *
+     * <p>If the package has an existing dependency on {@code existingLibrary} then prefix it with
+     * the {@code implicitDependency} if it is not already in the list of libraries.
+     *
+     * @param parsedPackage the {@link ParsedPackage} to update.
+     * @param existingLibrary the existing library.
+     * @param implicitDependency the implicit dependency to add
+     */
+    void prefixImplicitDependency(ParsedPackage parsedPackage, String existingLibrary,
+            String implicitDependency) {
+        List<String> usesLibraries = parsedPackage.getUsesLibraries();
+        List<String> usesOptionalLibraries = parsedPackage.getUsesOptionalLibraries();
+
+        if (!isLibraryPresent(usesLibraries, usesOptionalLibraries, implicitDependency)) {
+            if (ArrayUtils.contains(usesLibraries, existingLibrary)) {
+                parsedPackage.addUsesLibrary(0, implicitDependency);
+            } else if (ArrayUtils.contains(usesOptionalLibraries, existingLibrary)) {
+                parsedPackage.addUsesOptionalLibrary(0, implicitDependency);
+            }
+        }
+    }
+
+    void prefixRequiredLibrary(ParsedPackage parsedPackage, String libraryName) {
+        List<String> usesLibraries = parsedPackage.getUsesLibraries();
+        List<String> usesOptionalLibraries = parsedPackage.getUsesOptionalLibraries();
+
+        boolean alreadyPresent = isLibraryPresent(
+                usesLibraries, usesOptionalLibraries, libraryName);
+        if (!alreadyPresent) {
+            parsedPackage.addUsesLibrary(0, libraryName);
+        }
+    }
+}
diff --git a/core/java/android/content/pm/parsing/library/SharedLibraryNames.java b/core/java/android/content/pm/parsing/library/SharedLibraryNames.java
new file mode 100644
index 0000000..7b691c0
--- /dev/null
+++ b/core/java/android/content/pm/parsing/library/SharedLibraryNames.java
@@ -0,0 +1,36 @@
+/*
+ * 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.content.pm.parsing.library;
+
+/**
+ * A set of shared library names
+ *
+ * @hide
+ */
+public class SharedLibraryNames {
+
+    static final String ANDROID_HIDL_BASE = "android.hidl.base-V1.0-java";
+
+    static final String ANDROID_HIDL_MANAGER = "android.hidl.manager-V1.0-java";
+
+    static final String ANDROID_TEST_BASE = "android.test.base";
+
+    static final String ANDROID_TEST_MOCK = "android.test.mock";
+
+    static final String ANDROID_TEST_RUNNER = "android.test.runner";
+
+    public static final String ORG_APACHE_HTTP_LEGACY = "org.apache.http.legacy";
+}
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 5a45d9f..090629f 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1115,7 +1115,7 @@
      * @param critical          If true, reduce amount of data written.
      * @hide
      */
-    public void writeToProto(ProtoOutputStream protoOutputStream, long fieldId, boolean persisted,
+    public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId, boolean persisted,
             boolean critical) {
         final long token = protoOutputStream.start(fieldId);
         if (!critical) {
@@ -1138,7 +1138,7 @@
             protoOutputStream.write(DENSITY_DPI, densityDpi);
             // For persistence, we do not care about window configuration
             if (!persisted && windowConfiguration != null) {
-                windowConfiguration.writeToProto(protoOutputStream, WINDOW_CONFIGURATION);
+                windowConfiguration.dumpDebug(protoOutputStream, WINDOW_CONFIGURATION);
             }
         }
         protoOutputStream.write(ORIENTATION, orientation);
@@ -1155,8 +1155,8 @@
      * @param fieldId           Field Id of the Configuration as defined in the parent message
      * @hide
      */
-    public void writeToProto(ProtoOutputStream protoOutputStream, long fieldId) {
-        writeToProto(protoOutputStream, fieldId, false /* persisted */, false /* critical */);
+    public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId) {
+        dumpDebug(protoOutputStream, fieldId, false /* persisted */, false /* critical */);
     }
 
     /**
@@ -1168,8 +1168,8 @@
      * @param critical          If true, reduce amount of data written.
      * @hide
      */
-    public void writeToProto(ProtoOutputStream protoOutputStream, long fieldId, boolean critical) {
-        writeToProto(protoOutputStream, fieldId, false /* persisted */, critical);
+    public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId, boolean critical) {
+        dumpDebug(protoOutputStream, fieldId, false /* persisted */, critical);
     }
 
     /**
@@ -1338,7 +1338,7 @@
         }
 
         final long token = protoOutputStream.start(fieldId);
-        writeToProto(protoOutputStream, CONFIGURATION);
+        dumpDebug(protoOutputStream, CONFIGURATION);
         protoOutputStream.write(SDK_VERSION, Build.VERSION.RESOURCES_SDK_INT);
         protoOutputStream.write(SCREEN_WIDTH_PX, width);
         protoOutputStream.write(SCREEN_HEIGHT_PX, height);
diff --git a/core/java/android/content/res/loader/ResourceLoaderManager.java b/core/java/android/content/res/loader/ResourceLoaderManager.java
index ddbfa81..592ec09 100644
--- a/core/java/android/content/res/loader/ResourceLoaderManager.java
+++ b/core/java/android/content/res/loader/ResourceLoaderManager.java
@@ -151,6 +151,7 @@
     public void onImplUpdate(ResourcesImpl resourcesImpl) {
         synchronized (mLock) {
             this.mResourcesImpl = resourcesImpl;
+            this.mResourcesImpl.getAssets().setResourceLoaderManager(this);
             updateLoaders();
         }
     }
diff --git a/core/java/android/ddm/DdmHandleAppName.java b/core/java/android/ddm/DdmHandleAppName.java
index 9560787..de7acba 100644
--- a/core/java/android/ddm/DdmHandleAppName.java
+++ b/core/java/android/ddm/DdmHandleAppName.java
@@ -17,10 +17,12 @@
 package android.ddm;
 
 import android.annotation.UnsupportedAppUsage;
+import android.util.Log;
+
 import org.apache.harmony.dalvik.ddmc.Chunk;
 import org.apache.harmony.dalvik.ddmc.ChunkHandler;
 import org.apache.harmony.dalvik.ddmc.DdmServer;
-import android.util.Log;
+
 import java.nio.ByteBuffer;
 
 
@@ -31,7 +33,7 @@
 
     public static final int CHUNK_APNM = type("APNM");
 
-    private volatile static String mAppName = "";
+    private static volatile Names sNames = new Names("", "");
 
     private static DdmHandleAppName mInstance = new DdmHandleAppName();
 
@@ -66,45 +68,81 @@
 
 
     /**
+     * Sets all names to the same name.
+     */
+    @UnsupportedAppUsage
+    public static void setAppName(String name, int userId) {
+        setAppName(name, name, userId);
+    }
+
+    /**
      * Set the application name.  Called when we get named, which may be
      * before or after DDMS connects.  For the latter we need to send up
      * an APNM message.
      */
     @UnsupportedAppUsage
-    public static void setAppName(String name, int userId) {
-        if (name == null || name.length() == 0)
-            return;
+    public static void setAppName(String appName, String pkgName, int userId) {
+        if (appName == null || appName.isEmpty() || pkgName == null || pkgName.isEmpty()) return;
 
-        mAppName = name;
+        sNames = new Names(appName, pkgName);
 
         // if DDMS is already connected, send the app name up
-        sendAPNM(name, userId);
+        sendAPNM(appName, pkgName, userId);
     }
 
     @UnsupportedAppUsage
-    public static String getAppName() {
-        return mAppName;
+    public static Names getNames() {
+        return sNames;
     }
 
-    /*
+    /**
      * Send an APNM (APplication NaMe) chunk.
      */
-    private static void sendAPNM(String appName, int userId) {
+    private static void sendAPNM(String appName, String pkgName, int userId) {
         if (false)
             Log.v("ddm", "Sending app name");
 
         ByteBuffer out = ByteBuffer.allocate(
                             4 /* appName's length */
-                            + appName.length()*2 /* appName */
-                            + 4 /* userId */);
+                            + appName.length() * 2 /* appName */
+                            + 4 /* userId */
+                            + 4 /* pkgName's length */
+                            + pkgName.length() * 2 /* pkgName */);
         out.order(ChunkHandler.CHUNK_ORDER);
         out.putInt(appName.length());
         putString(out, appName);
         out.putInt(userId);
+        out.putInt(pkgName.length());
+        putString(out, pkgName);
 
         Chunk chunk = new Chunk(CHUNK_APNM, out);
         DdmServer.sendChunk(chunk);
     }
 
+    /**
+     * A class that encapsulates the app and package names into a single
+     * instance, effectively synchronizing the two names.
+     */
+    static final class Names {
+
+        private final String mAppName;
+
+        private final String mPkgName;
+
+        private Names(String appName, String pkgName) {
+            mAppName = appName;
+            mPkgName = pkgName;
+        }
+
+        public String getAppName() {
+            return mAppName;
+        }
+
+        public String getPkgName() {
+            return mPkgName;
+        }
+
+    }
+
 }
 
diff --git a/core/java/android/ddm/DdmHandleHello.java b/core/java/android/ddm/DdmHandleHello.java
index 87568e8..60dfc8d 100644
--- a/core/java/android/ddm/DdmHandleHello.java
+++ b/core/java/android/ddm/DdmHandleHello.java
@@ -126,10 +126,9 @@
         String vmVersion = System.getProperty("java.vm.version", "?");
         String vmIdent = vmName + " v" + vmVersion;
 
-        //String appName = android.app.ActivityThread.currentPackageName();
-        //if (appName == null)
-        //    appName = "unknown";
-        String appName = DdmHandleAppName.getAppName();
+        DdmHandleAppName.Names names = DdmHandleAppName.getNames();
+        String appName = names.getAppName();
+        String pkgName = names.getPkgName();
 
         VMRuntime vmRuntime = VMRuntime.getRuntime();
         String instructionSetDescription =
@@ -142,12 +141,13 @@
             + (vmRuntime.isCheckJniEnabled() ? "true" : "false");
         boolean isNativeDebuggable = vmRuntime.isNativeDebuggable();
 
-        ByteBuffer out = ByteBuffer.allocate(28
+        ByteBuffer out = ByteBuffer.allocate(32
                             + vmIdent.length() * 2
                             + appName.length() * 2
                             + instructionSetDescription.length() * 2
                             + vmFlags.length() * 2
-                            + 1);
+                            + 1
+                            + pkgName.length() * 2);
         out.order(ChunkHandler.CHUNK_ORDER);
         out.putInt(CLIENT_PROTOCOL_VERSION);
         out.putInt(android.os.Process.myPid());
@@ -161,6 +161,8 @@
         out.putInt(vmFlags.length());
         putString(out, vmFlags);
         out.put((byte)(isNativeDebuggable ? 1 : 0));
+        out.putInt(pkgName.length());
+        putString(out, pkgName);
 
         Chunk reply = new Chunk(CHUNK_HELO, out);
 
diff --git a/core/java/android/hardware/biometrics/BiometricConstants.java b/core/java/android/hardware/biometrics/BiometricConstants.java
index c8bf570..191516b 100644
--- a/core/java/android/hardware/biometrics/BiometricConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricConstants.java
@@ -86,12 +86,10 @@
     int BIOMETRIC_ERROR_LOCKOUT = 7;
 
     /**
-     * Hardware vendors may extend this list if there are conditions that do not fall under one of
-     * the above categories. Vendors are responsible for providing error strings for these errors.
-     * These messages are typically reserved for internal operations such as enrollment, but may be
-     * used to express vendor errors not otherwise covered. Applications are expected to show the
-     * error message string if they happen, but are advised not to rely on the message id since they
-     * will be device and vendor-specific
+     * OEMs should use this constant if there are conditions that do not fit under any of the other
+     * publicly defined constants, and must provide appropriate strings for these
+     * errors to the {@link BiometricPrompt.AuthenticationCallback#onAuthenticationError(int,
+     * CharSequence)} callback. OEMs should expect that the error message will be shown to users.
      */
     int BIOMETRIC_ERROR_VENDOR = 8;
 
diff --git a/core/java/android/hardware/camera2/legacy/RequestQueue.java b/core/java/android/hardware/camera2/legacy/RequestQueue.java
index 407e5e6..fb44402 100644
--- a/core/java/android/hardware/camera2/legacy/RequestQueue.java
+++ b/core/java/android/hardware/camera2/legacy/RequestQueue.java
@@ -30,7 +30,7 @@
 public class RequestQueue {
     private static final String TAG = "RequestQueue";
 
-    private static final long INVALID_FRAME = -1;
+    public static final long INVALID_FRAME = -1;
 
     private BurstHolder mRepeatingRequest = null;
     private final ArrayDeque<BurstHolder> mRequestQueue = new ArrayDeque<BurstHolder>();
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index 32411fb..f9a5029 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -948,8 +948,13 @@
                             Log.d(TAG, "Stopped repeating request. Last frame number is " +
                                     lastFrameNumber);
                         }
-                        mDeviceState.setRepeatingRequestError(lastFrameNumber,
-                                burstHolder.getRequestId());
+                        if (lastFrameNumber != RequestQueue.INVALID_FRAME) {
+                            mDeviceState.setRepeatingRequestError(lastFrameNumber,
+                                    burstHolder.getRequestId());
+                        } else {
+                            Log.e(TAG, "Repeating request id: " + burstHolder.getRequestId() +
+                                    " already canceled!");
+                        }
                     }
 
                     if (DEBUG) {
diff --git a/core/java/android/hardware/display/DisplayViewport.java b/core/java/android/hardware/display/DisplayViewport.java
index f2c50b5..5adf948 100644
--- a/core/java/android/hardware/display/DisplayViewport.java
+++ b/core/java/android/hardware/display/DisplayViewport.java
@@ -134,7 +134,9 @@
         result += prime * result + deviceWidth;
         result += prime * result + deviceHeight;
         result += prime * result + uniqueId.hashCode();
-        result += prime * result + physicalPort;
+        if (physicalPort != null) {
+            result += prime * result + physicalPort.hashCode();
+        }
         result += prime * result + type;
         return result;
     }
@@ -142,11 +144,12 @@
     // For debugging purposes.
     @Override
     public String toString() {
+        final Integer port = physicalPort == null ? null : Byte.toUnsignedInt(physicalPort);
         return "DisplayViewport{type=" + typeToString(type)
                 + ", valid=" + valid
                 + ", displayId=" + displayId
                 + ", uniqueId='" + uniqueId + "'"
-                + ", physicalPort=" + physicalPort
+                + ", physicalPort=" + port
                 + ", orientation=" + orientation
                 + ", logicalFrame=" + logicalFrame
                 + ", physicalFrame=" + physicalFrame
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 194068c..d95da91 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1006,7 +1006,7 @@
      *
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
+    @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
     @Nullable
     public Network getActiveNetworkForUid(int uid) {
         return getActiveNetworkForUid(uid, false);
@@ -1135,7 +1135,7 @@
      *
      * {@hide}
      */
-    @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
+    @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
     @UnsupportedAppUsage
     public NetworkInfo getActiveNetworkInfoForUid(int uid) {
         return getActiveNetworkInfoForUid(uid, false);
@@ -1370,10 +1370,14 @@
      * The system network validation may be using different strategies to detect captive portals,
      * so this method does not necessarily return a URL used by the system. It only returns a URL
      * that may be relevant for other components trying to detect captive portals.
+     *
      * @hide
+     * @deprecated This API returns URL which is not guaranteed to be one of the URLs used by the
+     *             system.
      */
+    @Deprecated
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.LOCAL_MAC_ADDRESS)
+    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
     public String getCaptivePortalServerUrl() {
         try {
             return mService.getCaptivePortalServerUrl();
@@ -2399,6 +2403,7 @@
      * @return an array of 0 or more {@code String} of tethered dhcp ranges.
      * {@hide}
      */
+    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
     public String[] getTetheredDhcpRanges() {
         try {
             return mService.getTetheredDhcpRanges();
@@ -2978,7 +2983,7 @@
      *        HTTP proxy.  A {@code null} value will clear the global HTTP proxy.
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
+    @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
     public void setGlobalProxy(ProxyInfo p) {
         try {
             mService.setGlobalProxy(p);
@@ -3123,6 +3128,7 @@
      * Get the mobile provisioning url.
      * {@hide}
      */
+    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
     public String getMobileProvisioningUrl() {
         try {
             return mService.getMobileProvisioningUrl();
@@ -3169,6 +3175,7 @@
 
     /** {@hide} - returns the factory serial number */
     @UnsupportedAppUsage
+    @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
     public int registerNetworkFactory(Messenger messenger, String name) {
         try {
             return mService.registerNetworkFactory(messenger, name);
@@ -3179,6 +3186,7 @@
 
     /** {@hide} */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+    @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
     public void unregisterNetworkFactory(Messenger messenger) {
         try {
             mService.unregisterNetworkFactory(messenger);
@@ -3196,6 +3204,7 @@
      * Register a NetworkAgent with ConnectivityService.
      * @return NetID corresponding to NetworkAgent.
      */
+    @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
     public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
             NetworkCapabilities nc, int score, NetworkMisc misc) {
         return registerNetworkAgent(messenger, ni, lp, nc, score, misc,
@@ -3207,6 +3216,7 @@
      * Register a NetworkAgent with ConnectivityService.
      * @return NetID corresponding to NetworkAgent.
      */
+    @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
     public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
             NetworkCapabilities nc, int score, NetworkMisc misc, int factorySerialNumber) {
         try {
@@ -4201,7 +4211,7 @@
      *
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
+    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
     public void startCaptivePortalApp(Network network) {
         try {
             mService.startCaptivePortalApp(network);
@@ -4317,6 +4327,7 @@
      * Resets all connectivity manager settings back to factory defaults.
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
     public void factoryReset() {
         try {
             mService.factoryReset();
diff --git a/core/java/android/net/InterfaceConfiguration.java b/core/java/android/net/InterfaceConfiguration.java
index c9a999c..1ae44e1 100644
--- a/core/java/android/net/InterfaceConfiguration.java
+++ b/core/java/android/net/InterfaceConfiguration.java
@@ -20,8 +20,6 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import com.google.android.collect.Sets;
-
 import java.util.HashSet;
 
 /**
@@ -32,7 +30,7 @@
 public class InterfaceConfiguration implements Parcelable {
     private String mHwAddr;
     private LinkAddress mAddr;
-    private HashSet<String> mFlags = Sets.newHashSet();
+    private HashSet<String> mFlags = new HashSet<>();
 
     // Must be kept in sync with constant in INetd.aidl
     private static final String FLAG_UP = "up";
diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java
index 143467b..dddb64d 100644
--- a/core/java/android/net/IpConfiguration.java
+++ b/core/java/android/net/IpConfiguration.java
@@ -191,18 +191,12 @@
                83 * httpProxy.hashCode();
     }
 
-    /**
-     * Implement the Parcelable interface
-     * @hide
-     */
+    /** Implement the Parcelable interface */
     public int describeContents() {
         return 0;
     }
 
-    /**
-     * Implement the Parcelable interface
-     * @hide
-     */
+    /** Implement the Parcelable interface */
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeString(ipAssignment.name());
         dest.writeString(proxySettings.name());
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 0706e75..8e18341 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -762,10 +762,7 @@
      * Returns the NAT64 prefix in use on this link, if any.
      *
      * @return the NAT64 prefix or {@code null}.
-     * @hide
      */
-    @SystemApi
-    @TestApi
     public @Nullable IpPrefix getNat64Prefix() {
         return mNat64Prefix;
     }
@@ -777,10 +774,7 @@
      * 128-bit IPv6 address) are supported or {@code null} for no prefix.
      *
      * @param prefix the NAT64 prefix.
-     * @hide
      */
-    @SystemApi
-    @TestApi
     public void setNat64Prefix(@Nullable IpPrefix prefix) {
         if (prefix != null && prefix.getPrefixLength() != 96) {
             throw new IllegalArgumentException("Only 96-bit prefixes are supported: " + prefix);
diff --git a/core/java/android/net/MacAddress.aidl b/core/java/android/net/MacAddress.aidl
new file mode 100644
index 0000000..48a18a7
--- /dev/null
+++ b/core/java/android/net/MacAddress.aidl
@@ -0,0 +1,20 @@
+/**
+ *
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+@JavaOnlyStableParcelable parcelable MacAddress;
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index 3f56def..c6c73fe 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -63,7 +63,7 @@
     /**
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public final int netId;
 
     // Objects used to perform per-network operations such as getSocketFactory
@@ -502,7 +502,7 @@
     }
 
     /** @hide */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(NetworkProto.NET_ID, netId);
         proto.end(token);
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 88877e2..db20dbd 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -1602,7 +1602,7 @@
     }
 
     /** @hide */
-    public void writeToProto(@NonNull ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(@NonNull ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
 
         for (int transport : getTransportTypes()) {
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index febc730..c1198aa 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -114,7 +114,7 @@
         return builder.append("}").toString();
     }
 
-    public void writeToProto(ProtoOutputStream proto, long tag) {
+    public void dumpDebug(ProtoOutputStream proto, long tag) {
         final long start = proto.start(tag);
 
         proto.write(NetworkIdentityProto.TYPE, mType);
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 4270740..adc497a 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -485,13 +485,13 @@
     }
 
     /** @hide */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
 
         proto.write(NetworkRequestProto.TYPE, typeToProtoEnum(type));
         proto.write(NetworkRequestProto.REQUEST_ID, requestId);
         proto.write(NetworkRequestProto.LEGACY_TYPE, legacyType);
-        networkCapabilities.writeToProto(proto, NetworkRequestProto.NETWORK_CAPABILITIES);
+        networkCapabilities.dumpDebug(proto, NetworkRequestProto.NETWORK_CAPABILITIES);
 
         proto.end(token);
     }
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index f61260e..d96d2ee 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -684,7 +684,7 @@
         }
     }
 
-    public void writeToProto(ProtoOutputStream proto, long tag) {
+    public void dumpDebug(ProtoOutputStream proto, long tag) {
         final long start = proto.start(tag);
 
         proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS, bucketDuration);
@@ -693,11 +693,11 @@
             final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS);
 
             proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS, bucketStart[i]);
-            writeToProto(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i);
-            writeToProto(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i);
-            writeToProto(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i);
-            writeToProto(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i);
-            writeToProto(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, i);
+            dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i);
+            dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i);
+            dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i);
+            dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i);
+            dumpDebug(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, i);
 
             proto.end(startBucket);
         }
@@ -705,7 +705,7 @@
         proto.end(start);
     }
 
-    private static void writeToProto(ProtoOutputStream proto, long tag, long[] array, int index) {
+    private static void dumpDebug(ProtoOutputStream proto, long tag, long[] array, int index) {
         if (array != null) {
             proto.write(tag, array[index]);
         }
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 1c6a484..bf4884a 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.annotation.NonNull;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
@@ -595,8 +596,15 @@
         return total;
     }
 
-    /** {@hide} */
-    public static long getTxPackets(String iface) {
+    /**
+     * Return the number of packets transmitted on the specified interface since
+     * device boot. Statistics are measured at the network layer, so both TCP and
+     * UDP usage are included.
+     *
+     * @param iface The name of the interface.
+     * @return The number of transmitted packets.
+     */
+    public static long getTxPackets(@NonNull String iface) {
         try {
             return getStatsService().getIfaceStats(iface, TYPE_TX_PACKETS);
         } catch (RemoteException e) {
@@ -604,8 +612,15 @@
         }
     }
 
-    /** {@hide} */
-    public static long getRxPackets(String iface) {
+    /**
+     * Return the number of packets received on the specified interface since
+     * device boot. Statistics are measured at the network layer, so both TCP
+     * and UDP usage are included.
+     *
+     * @param iface The name of the interface.
+     * @return The number of received packets.
+     */
+    public static long getRxPackets(@NonNull String iface) {
         try {
             return getStatsService().getIfaceStats(iface, TYPE_RX_PACKETS);
         } catch (RemoteException e) {
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 95815e4..9fed269 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -27,7 +27,7 @@
 import android.server.ServerProtoEnums;
 import android.service.batterystats.BatteryStatsServiceDumpHistoryProto;
 import android.service.batterystats.BatteryStatsServiceDumpProto;
-import android.telephony.SignalStrength;
+import android.telephony.CellSignalStrength;
 import android.telephony.TelephonyManager;
 import android.text.format.DateFormat;
 import android.util.ArrayMap;
@@ -2529,7 +2529,7 @@
                 new String[] {"in", "out", "em", "off"}),
         new BitDescription(HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_MASK,
                 HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_SHIFT, "phone_signal_strength", "Pss",
-                SignalStrength.SIGNAL_STRENGTH_NAMES,
+                new String[] { "none", "poor", "moderate", "good", "great" },
                 new String[] { "0", "1", "2", "3", "4" }),
         new BitDescription(HistoryItem.STATE_BRIGHTNESS_MASK,
                 HistoryItem.STATE_BRIGHTNESS_SHIFT, "brightness", "Sb",
@@ -3891,14 +3891,14 @@
         dumpLine(pw, 0 /* uid */, category, SCREEN_BRIGHTNESS_DATA, args);
 
         // Dump signal strength stats
-        args = new Object[SignalStrength.NUM_SIGNAL_STRENGTH_BINS];
-        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
+        args = new Object[CellSignalStrength.getNumSignalStrengthLevels()];
+        for (int i = 0; i < CellSignalStrength.getNumSignalStrengthLevels(); i++) {
             args[i] = getPhoneSignalStrengthTime(i, rawRealtime, which) / 1000;
         }
         dumpLine(pw, 0 /* uid */, category, SIGNAL_STRENGTH_TIME_DATA, args);
         dumpLine(pw, 0 /* uid */, category, SIGNAL_SCANNING_TIME_DATA,
                 getPhoneSignalScanningTime(rawRealtime, which) / 1000);
-        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
+        for (int i = 0; i < CellSignalStrength.getNumSignalStrengthLevels(); i++) {
             args[i] = getPhoneSignalStrengthCount(i, which);
         }
         dumpLine(pw, 0 /* uid */, category, SIGNAL_STRENGTH_COUNT_DATA, args);
@@ -4968,7 +4968,7 @@
             "good (-108dBm to -98dBm): ",
             "great (greater than -98dBm): "};
         didOne = false;
-        final int numCellularRxBins = Math.min(SignalStrength.NUM_SIGNAL_STRENGTH_BINS,
+        final int numCellularRxBins = Math.min(CellSignalStrength.getNumSignalStrengthLevels(),
             cellularRxSignalStrengthDescription.length);
         for (int i=0; i<numCellularRxBins; i++) {
             final long time = getPhoneSignalStrengthTime(i, rawRealtime, which);
@@ -8216,7 +8216,7 @@
                 which);
 
         // Phone signal strength (SIGNAL_STRENGTH_TIME_DATA and SIGNAL_STRENGTH_COUNT_DATA)
-        for (int i = 0; i < SignalStrength.NUM_SIGNAL_STRENGTH_BINS; ++i) {
+        for (int i = 0; i < CellSignalStrength.getNumSignalStrengthLevels(); ++i) {
             final long pssToken = proto.start(SystemProto.PHONE_SIGNAL_STRENGTH);
             proto.write(SystemProto.PhoneSignalStrength.NAME, i);
             dumpTimer(proto, SystemProto.PhoneSignalStrength.TOTAL, getPhoneSignalStrengthTimer(i),
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index ec39199..a9c5a91 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -505,6 +505,19 @@
     public static final native void restoreCallingWorkSource(long token);
 
     /**
+     * Mark as being built with VINTF-level stability promise. This API should
+     * only ever be invoked by the build system. It means that the interface
+     * represented by this binder is guaranteed to be kept stable for several
+     * years, and the build system also keeps snapshots of these APIs and
+     * invokes the AIDL compiler to make sure that these snapshots are
+     * backwards compatible. Instead of using this API, use an @VintfStability
+     * interface.
+     *
+     * @hide
+     */
+    public final native void markVintfStability();
+
+    /**
      * Flush any Binder commands pending in the current thread to the kernel
      * driver.  This can be
      * useful to call before performing an operation that may block for a long
@@ -896,8 +909,11 @@
     }
 
     /**
-     * Handle a call to {@link #shellCommand}.  The default implementation simply prints
-     * an error message.  Override and replace with your own.
+     * Handle a call to {@link #shellCommand}.
+     *
+     * <p>The default implementation performs a caller check to make sure the caller UID is of
+     * SHELL or ROOT, and then call {@link #handleShellCommand}.
+     *
      * <p class="caution">Note: no permission checking is done before calling this method; you must
      * apply any security checks as appropriate for the command being executed.
      * Consider using {@link ShellCommand} to help in the implementation.</p>
@@ -908,6 +924,12 @@
             @NonNull String[] args, @Nullable ShellCallback callback,
             @NonNull ResultReceiver resultReceiver) throws RemoteException {
 
+        final int callingUid = Binder.getCallingUid();
+        if (callingUid != Process.ROOT_UID && callingUid != Process.SHELL_UID) {
+            resultReceiver.send(-1, null);
+            throw new SecurityException("Shell commands are only callable by ADB");
+        }
+
         // First, convert in, out and err to @NonNull, by redirecting any that's null to /dev/null.
         try {
             if (in == null) {
@@ -948,19 +970,23 @@
     /**
      * System services can implement this method to implement ADB shell commands.
      *
-     * TODO More Javadoc.
-     * TODO Add a generic way to define subcommands and their permissions.
+     * <p>A system binder service can implement it to handle shell commands on ADB. For example,
+     * the Job Scheduler service implements it to handle <code>adb shell cmd jobscheduler</code>.
      *
-     * @param in standard input.
-     * @param out standard output.
-     * @param err standard error.
+     * <p>Commands are only executable by ADB shell; i.e. only {@link Process#SHELL_UID} and
+     * {@link Process#ROOT_UID} can call them.
+     *
+     * @param in standard input
+     * @param out standard output
+     * @param err standard error
      * @param args arguments passed to the command. Can be empty. The first argument is typically
      *             a subcommand, such as {@code run} for {@code adb shell cmd jobscheduler run}.
+     * @return the status code returned from the <code>cmd</code> command.
      *
      * @hide
      */
-    // @SystemApi TODO Make it a system API.
-    protected int handleShellCommand(@NonNull ParcelFileDescriptor in,
+    @SystemApi
+    public int handleShellCommand(@NonNull ParcelFileDescriptor in,
             @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
             @NonNull String[] args) {
         FileOutputStream ferr = new FileOutputStream(err.getFileDescriptor());
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index c5cbad3..a3c2cd8 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -25,6 +25,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
+import android.app.ActivityManager;
 import android.content.Context;
 import android.util.Log;
 
@@ -191,6 +192,32 @@
         }
     }
 
+    /**
+     * Requests a bugreport.
+     *
+     * <p>This requests the platform/system to take a bugreport and makes the final bugreport
+     * available to the user. The user may choose to share it with another app, but the bugreport
+     * is never given back directly to the app that requested it.
+     *
+     * @param params           {@link BugreportParams} that specify what kind of a bugreport should
+     *                         be taken, please note that not all kinds of bugreport allow for a
+     *                         progress notification
+     * @param shareTitle       title on the final share notification
+     * @param shareDescription description on the final share notification
+     */
+    @RequiresPermission(android.Manifest.permission.DUMP)
+    public void requestBugreport(@NonNull BugreportParams params, @Nullable CharSequence shareTitle,
+            @Nullable CharSequence shareDescription) {
+        try {
+            String title = shareTitle == null ? null : shareTitle.toString();
+            String description = shareDescription == null ? null : shareDescription.toString();
+            ActivityManager.getService().requestBugReportWithDescription(title, description,
+                    params.getMode());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     private final class DumpstateListener extends IDumpstateListener.Stub {
         private final Executor mExecutor;
         private final BugreportCallback mCallback;
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 89ccef6..6eaea99 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1084,7 +1084,7 @@
             return result == 0;
         }
 
-        final String system = SystemProperties.get("ro.build.fingerprint");
+        final String system = SystemProperties.get("ro.system.build.fingerprint");
         final String vendor = SystemProperties.get("ro.vendor.build.fingerprint");
         final String bootimage = SystemProperties.get("ro.bootimage.build.fingerprint");
         final String requiredBootloader = SystemProperties.get("ro.build.expect.bootloader");
@@ -1094,7 +1094,7 @@
                 TelephonyProperties.baseband_version(), "");
 
         if (TextUtils.isEmpty(system)) {
-            Slog.e(TAG, "Required ro.build.fingerprint is empty!");
+            Slog.e(TAG, "Required ro.system.build.fingerprint is empty!");
             return false;
         }
 
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 7e11840..c5b4222 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -1345,7 +1345,7 @@
     }
 
     /** @hide */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
 
         if (mParcelledData != null) {
diff --git a/core/java/android/os/FileObserver.java b/core/java/android/os/FileObserver.java
index 4d9ebc2..5b715c0 100644
--- a/core/java/android/os/FileObserver.java
+++ b/core/java/android/os/FileObserver.java
@@ -32,7 +32,7 @@
 
 /**
  * Monitors files (using <a href="http://en.wikipedia.org/wiki/Inotify">inotify</a>)
- * to fire an event after files are accessed or changed by by any process on
+ * to fire an event after files are accessed or changed by any process on
  * the device (including this one).  FileObserver is an abstract class;
  * subclasses must implement the event handler {@link #onEvent(int, String)}.
  *
diff --git a/core/java/android/os/IPullAtomResultReceiver.aidl b/core/java/android/os/IPullAtomResultReceiver.aidl
deleted file mode 100644
index bfb35ff..0000000
--- a/core/java/android/os/IPullAtomResultReceiver.aidl
+++ /dev/null
@@ -1,32 +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.os;
-
-import android.util.StatsEvent;
-
-/**
-  * Binder interface to pull atoms for the stats service.
-  * {@hide}
-  */
-interface IPullAtomResultReceiver {
-
-    /**
-     * Indicate that a pull request for an atom is complete.
-     */
-     oneway void pullFinished(int atomTag, boolean success, in StatsEvent[] output);
-
-}
diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl
deleted file mode 100644
index 29871b6..0000000
--- a/core/java/android/os/IStatsManager.aidl
+++ /dev/null
@@ -1,242 +0,0 @@
-/**
- * Copyright (c) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os;
-
-import android.os.IStatsPullerCallback;
-import android.os.IPullAtomCallback;
-import android.os.ParcelFileDescriptor;
-
-/**
-  * Binder interface to communicate with the statistics management service.
-  * {@hide}
-  */
-interface IStatsManager {
-    /**
-     * Tell the stats daemon that the android system server is up and running.
-     */
-    oneway void systemRunning();
-
-    /**
-     * Tell the stats daemon that the StatsCompanionService is up and running.
-     * Two-way binder call so that caller knows message received.
-     */
-    void statsCompanionReady();
-
-    /**
-     * Tells statsd that an anomaly may have occurred, so statsd can check whether this is so and
-     * act accordingly.
-     * Two-way binder call so that caller's method (and corresponding wakelocks) will linger.
-     */
-    void informAnomalyAlarmFired();
-
-    /**
-     * Tells statsd that it is time to poll some stats. Statsd will be responsible for determing
-     * what stats to poll and initiating the polling.
-     * Two-way binder call so that caller's method (and corresponding wakelocks) will linger.
-     */
-    void informPollAlarmFired();
-
-    /**
-     * Tells statsd that it is time to handle periodic alarms. Statsd will be responsible for
-     * determing what alarm subscriber to trigger.
-     * Two-way binder call so that caller's method (and corresponding wakelocks) will linger.
-     */
-    void informAlarmForSubscriberTriggeringFired();
-
-    /**
-     * Tells statsd that the device is about to shutdown.
-     */
-    void informDeviceShutdown();
-
-    /**
-     * Inform statsd about a file descriptor for a pipe through which we will pipe version
-     * and package information for each uid.
-     * Versions and package information are supplied via UidData proto where info for each app
-     * is captured in its own element of a repeated ApplicationInfo message.
-     */
-    oneway void informAllUidData(in ParcelFileDescriptor fd);
-
-    /**
-     * Inform statsd what the uid, version, version_string, and installer are for one app that was
-     * updated.
-     */
-    oneway void informOnePackage(in String app, in int uid, in long version,
-        in String version_string, in String installer);
-
-    /**
-     * Inform stats that an app was removed.
-     */
-    oneway void informOnePackageRemoved(in String app, in int uid);
-
-    /**
-     * Fetches data for the specified configuration key. Returns a byte array representing proto
-     * wire-encoded of ConfigMetricsReportList.
-     *
-     * Requires Manifest.permission.DUMP.
-     */
-    byte[] getData(in long key, in String packageName);
-
-    /**
-     * Fetches metadata across statsd. Returns byte array representing wire-encoded proto.
-     *
-     * Requires Manifest.permission.DUMP.
-     */
-    byte[] getMetadata(in String packageName);
-
-    /**
-     * Sets a configuration with the specified config key and subscribes to updates for this
-     * configuration key. Broadcasts will be sent if this configuration needs to be collected.
-     * The configuration must be a wire-encoded StatsdConfig. The receiver for this data is
-     * registered in a separate function.
-     *
-     * Requires Manifest.permission.DUMP.
-     */
-    void addConfiguration(in long configKey, in byte[] config, in String packageName);
-
-    /**
-     * Registers the given pending intent for this config key. This intent is invoked when the
-     * memory consumed by the metrics for this configuration approach the pre-defined limits. There
-     * can be at most one listener per config key.
-     *
-     * Requires Manifest.permission.DUMP.
-     */
-    void setDataFetchOperation(long configKey, in IBinder intentSender, in String packageName);
-
-    /**
-     * Removes the data fetch operation for the specified configuration.
-     *
-     * Requires Manifest.permission.DUMP.
-     */
-    void removeDataFetchOperation(long configKey, in String packageName);
-
-    /**
-     * Registers the given pending intent for this packagename. This intent is invoked when the
-     * active status of any of the configs sent by this package changes and will contain a list of
-     * config ids that are currently active. It also returns the list of configs that are currently
-     * active. There can be at most one active configs changed listener per package.
-     *
-     * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
-     */
-    long[] setActiveConfigsChangedOperation(in IBinder intentSender, in String packageName);
-
-    /**
-     * Removes the active configs changed operation for the specified package name.
-     *
-     * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
-     */
-    void removeActiveConfigsChangedOperation(in String packageName);
-
-    /**
-     * Removes the configuration with the matching config key. No-op if this config key does not
-     * exist.
-     *
-     * Requires Manifest.permission.DUMP.
-     */
-    void removeConfiguration(in long configKey, in String packageName);
-
-    /**
-     * Set the IIntentSender (i.e. PendingIntent) to be used when broadcasting subscriber
-     * information to the given subscriberId within the given config.
-     *
-     * Suppose that the calling uid has added a config with key configKey, and that in this config
-     * it is specified that when a particular anomaly is detected, a broadcast should be sent to
-     * a BroadcastSubscriber with id subscriberId. This function links the given intentSender with
-     * that subscriberId (for that config), so that this intentSender is used to send the broadcast
-     * when the anomaly is detected.
-     *
-     * This function can only be called by the owner (uid) of the config. It must be called each
-     * time statsd starts. Later calls overwrite previous calls; only one intentSender is stored.
-     *
-     * intentSender must be convertible into an IntentSender using IntentSender(IBinder)
-     * and cannot be null.
-     *
-     * Requires Manifest.permission.DUMP.
-     */
-    void setBroadcastSubscriber(long configKey, long subscriberId, in IBinder intentSender,
-                                in String packageName);
-
-    /**
-     * Undoes setBroadcastSubscriber() for the (configKey, subscriberId) pair.
-     * Any broadcasts associated with subscriberId will henceforth not be sent.
-     * No-op if this (configKey, subsriberId) pair was not associated with an IntentSender.
-     *
-     * Requires Manifest.permission.DUMP.
-     */
-    void unsetBroadcastSubscriber(long configKey, long subscriberId, in String packageName);
-
-    /**
-     * Apps can send an atom via this application breadcrumb with the specified label and state for
-     * this label. This allows building custom metrics and predicates.
-     */
-    void sendAppBreadcrumbAtom(int label, int state);
-
-    /**
-     * Registers a puller callback function that, when invoked, pulls the data
-     * for the specified vendor atom tag.
-     *
-     * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS
-     * @deprecated please use registerPullAtomCallback.
-     */
-    oneway void registerPullerCallback(int atomTag, IStatsPullerCallback pullerCallback,
-                                       String packageName);
-
-   /**
-    * 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);
-
-   /**
-    * Unregisters a puller callback function for the given vendor atom.
-    *
-    * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS
-    */
-   oneway void unregisterPullerCallback(int atomTag, String packageName);
-
-    /**
-     * The install requires staging.
-     */
-    const int FLAG_REQUIRE_STAGING = 0x01;
-
-    /**
-     * Rollback is enabled with this install.
-     */
-    const int FLAG_ROLLBACK_ENABLED = 0x02;
-
-    /**
-     * Requires low latency monitoring.
-     */
-    const int FLAG_REQUIRE_LOW_LATENCY_MONITOR = 0x04;
-
-    /**
-     * Logs an event for binary push for module updates.
-     */
-     oneway void sendBinaryPushStateChangedAtom(in String trainName, in long trainVersionCode,
-         in int options, in int state, in long[] experimentId);
-
-    /**
-     * Logs an event for watchdog rollbacks.
-     */
-     oneway void sendWatchdogRollbackOccurredAtom(in int rollbackType, in String packageName,
-         in long packageVersionCode);
-
-    /**
-     * Returns the most recently registered experiment IDs.
-     */
-    long[] getRegisteredExperimentIds();
-}
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 40048d9..e81a505 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -87,6 +87,7 @@
     void setDefaultGuestRestrictions(in Bundle restrictions);
     Bundle getDefaultGuestRestrictions();
     boolean markGuestForDeletion(int userId);
+    UserInfo findCurrentGuestUser();
     boolean isQuietModeEnabled(int userId);
     void setSeedAccountData(int userId, in String accountName,
             in String accountType, in PersistableBundle accountOptions, boolean persist);
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index d468972..df16ffe 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -415,12 +415,12 @@
     }
 
     /** @hide */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long looperToken = proto.start(fieldId);
         proto.write(LooperProto.THREAD_NAME, mThread.getName());
         proto.write(LooperProto.THREAD_ID, mThread.getId());
         if (mQueue != null) {
-            mQueue.writeToProto(proto, LooperProto.QUEUE);
+            mQueue.dumpDebug(proto, LooperProto.QUEUE);
         }
         proto.end(looperToken);
     }
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index 6055bef..9d101e5 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -574,7 +574,7 @@
         return b.toString();
     }
 
-    void writeToProto(ProtoOutputStream proto, long fieldId) {
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long messageToken = proto.start(fieldId);
         proto.write(MessageProto.WHEN, when);
 
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index f98fdc3..b5f4bc6 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -807,11 +807,11 @@
         }
     }
 
-    void writeToProto(ProtoOutputStream proto, long fieldId) {
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long messageQueueToken = proto.start(fieldId);
         synchronized (this) {
             for (Message msg = mMessages; msg != null; msg = msg.next) {
-                msg.writeToProto(proto, MessageQueueProto.MESSAGES);
+                msg.dumpDebug(proto, MessageQueueProto.MESSAGES);
             }
             proto.write(MessageQueueProto.IS_POLLING_LOCKED, isPollingLocked());
             proto.write(MessageQueueProto.IS_QUITTING, mQuitting);
diff --git a/core/java/android/os/PatternMatcher.java b/core/java/android/os/PatternMatcher.java
index ef03e8c..428405b 100644
--- a/core/java/android/os/PatternMatcher.java
+++ b/core/java/android/os/PatternMatcher.java
@@ -133,7 +133,7 @@
     }
 
     /** @hide */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         long token = proto.start(fieldId);
         proto.write(PatternMatcherProto.PATTERN, mPattern);
         proto.write(PatternMatcherProto.TYPE, mType);
diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java
index 6f1bf71..b40283f 100644
--- a/core/java/android/os/PersistableBundle.java
+++ b/core/java/android/os/PersistableBundle.java
@@ -324,7 +324,7 @@
     }
 
     /** @hide */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
 
         if (mParcelledData != null) {
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index f18b4db..725e0fb 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -2315,7 +2315,7 @@
         }
 
         /** @hide */
-        public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        public void dumpDebug(ProtoOutputStream proto, long fieldId) {
             synchronized (mToken) {
                 final long token = proto.start(fieldId);
                 proto.write(PowerManagerProto.WakeLock.TAG, mTag);
@@ -2323,7 +2323,7 @@
                 proto.write(PowerManagerProto.WakeLock.HELD, mHeld);
                 proto.write(PowerManagerProto.WakeLock.INTERNAL_COUNT, mInternalCount);
                 if (mWorkSource != null) {
-                    mWorkSource.writeToProto(proto, PowerManagerProto.WakeLock.WORK_SOURCE);
+                    mWorkSource.dumpDebug(proto, PowerManagerProto.WakeLock.WORK_SOURCE);
                 }
                 proto.end(token);
             }
diff --git a/core/java/android/os/ResultReceiver.aidl b/core/java/android/os/ResultReceiver.aidl
index 28ce6d5..9fd5bc9 100644
--- a/core/java/android/os/ResultReceiver.aidl
+++ b/core/java/android/os/ResultReceiver.aidl
@@ -2,19 +2,19 @@
 **
 ** Copyright 2007, 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 
+** 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 
+**     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 
+** 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.os;
 
-parcelable ResultReceiver;
+@JavaOnlyStableParcelable parcelable ResultReceiver;
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 1456a73..e132c11 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -21,6 +21,7 @@
 
 import com.android.internal.os.Zygote;
 
+import dalvik.annotation.optimization.CriticalNative;
 import dalvik.annotation.optimization.FastNative;
 
 /**
@@ -107,12 +108,15 @@
     private static final int MAX_SECTION_NAME_LEN = 127;
 
     // Must be volatile to avoid word tearing.
+    // This is only kept in case any apps get this by reflection but do not
+    // check the return value for null.
     @UnsupportedAppUsage
     private static volatile long sEnabledTags = TRACE_TAG_NOT_READY;
 
     private static int sZygoteDebugFlags = 0;
 
     @UnsupportedAppUsage
+    @CriticalNative
     private static native long nativeGetEnabledTags();
     private static native void nativeSetAppTracingAllowed(boolean allowed);
     private static native void nativeSetTracingEnabled(boolean allowed);
@@ -128,47 +132,10 @@
     @FastNative
     private static native void nativeAsyncTraceEnd(long tag, String name, int cookie);
 
-    static {
-        // We configure two separate change callbacks, one in Trace.cpp and one here.  The
-        // native callback reads the tags from the system property, and this callback
-        // reads the value that the native code retrieved.  It's essential that the native
-        // callback executes first.
-        //
-        // The system provides ordering through a priority level.  Callbacks made through
-        // SystemProperties.addChangeCallback currently have a negative priority, while
-        // our native code is using a priority of zero.
-        SystemProperties.addChangeCallback(() -> {
-            cacheEnabledTags();
-            if ((sZygoteDebugFlags & Zygote.DEBUG_JAVA_DEBUGGABLE) != 0) {
-                traceCounter(TRACE_TAG_ALWAYS, "java_debuggable", 1);
-            }
-        });
-    }
-
     private Trace() {
     }
 
     /**
-     * Caches a copy of the enabled-tag bits.  The "master" copy is held by the native code,
-     * and comes from the PROPERTY_TRACE_TAG_ENABLEFLAGS property.
-     * <p>
-     * If the native code hasn't yet read the property, we will cause it to do one-time
-     * initialization.  We don't want to do this during class init, because this class is
-     * preloaded, so all apps would be stuck with whatever the zygote saw.  (The zygote
-     * doesn't see the system-property update broadcasts.)
-     * <p>
-     * We want to defer initialization until the first use by an app, post-zygote.
-     * <p>
-     * We're okay if multiple threads call here simultaneously -- the native state is
-     * synchronized, and sEnabledTags is volatile (prevents word tearing).
-     */
-    private static long cacheEnabledTags() {
-        long tags = nativeGetEnabledTags();
-        sEnabledTags = tags;
-        return tags;
-    }
-
-    /**
      * Returns true if a trace tag is enabled.
      *
      * @param traceTag The trace tag to check.
@@ -178,10 +145,7 @@
      */
     @UnsupportedAppUsage
     public static boolean isTagEnabled(long traceTag) {
-        long tags = sEnabledTags;
-        if (tags == TRACE_TAG_NOT_READY) {
-            tags = cacheEnabledTags();
-        }
+        long tags = nativeGetEnabledTags();
         return (tags & traceTag) != 0;
     }
 
@@ -210,10 +174,6 @@
     @UnsupportedAppUsage
     public static void setAppTracingAllowed(boolean allowed) {
         nativeSetAppTracingAllowed(allowed);
-
-        // Setting whether app tracing is allowed may change the tags, so we update the cached
-        // tags here.
-        cacheEnabledTags();
     }
 
     /**
@@ -227,10 +187,6 @@
     public static void setTracingEnabled(boolean enabled, int debugFlags) {
         nativeSetTracingEnabled(enabled);
         sZygoteDebugFlags = debugFlags;
-
-        // Setting whether tracing is enabled may change the tags, so we update the cached tags
-        // here.
-        cacheEnabledTags();
     }
 
     /**
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index ce91c50..137f537 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -24,6 +24,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.StringDef;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
@@ -46,6 +47,7 @@
 import android.graphics.BitmapFactory;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.location.LocationManager;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
 import android.view.WindowManager.LayoutParams;
@@ -486,13 +488,13 @@
      *
      * <p>This user restriction is different from {@link #DISALLOW_SHARE_LOCATION},
      * as the device owner or profile owner can still enable or disable location mode via
-     * {@link DevicePolicyManager#setSecureSetting} when this restriction is on.
+     * {@link DevicePolicyManager#setLocationEnabled} when this restriction is on.
      *
      * <p>The default value is <code>false</code>.
      *
      * <p>Key for user restrictions.
      * <p>Type: Boolean
-     * @see android.location.LocationManager#isProviderEnabled(String)
+     * @see LocationManager#isLocationEnabled()
      * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
      * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
@@ -1111,6 +1113,82 @@
      */
     public static final String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
 
+    /**
+     * List of key values that can be passed into the various user restriction related methods
+     * in {@link UserManager} & {@link DevicePolicyManager}.
+     * Note: This is slightly different from the real set of user restrictions listed in {@link
+     * com.android.server.pm.UserRestrictionsUtils#USER_RESTRICTIONS}. For example
+     * {@link #KEY_RESTRICTIONS_PENDING} is not a real user restriction, but is a a legitimate
+     * value that can be passed into {@link #hasUserRestriction(String)}.
+     * @hide
+     */
+    @StringDef(value = {
+            DISALLOW_MODIFY_ACCOUNTS,
+            DISALLOW_CONFIG_WIFI,
+            DISALLOW_CONFIG_LOCALE,
+            DISALLOW_INSTALL_APPS,
+            DISALLOW_UNINSTALL_APPS,
+            DISALLOW_SHARE_LOCATION,
+            DISALLOW_AIRPLANE_MODE,
+            DISALLOW_CONFIG_BRIGHTNESS,
+            DISALLOW_AMBIENT_DISPLAY,
+            DISALLOW_CONFIG_SCREEN_TIMEOUT,
+            DISALLOW_INSTALL_UNKNOWN_SOURCES,
+            DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY,
+            DISALLOW_CONFIG_BLUETOOTH,
+            DISALLOW_BLUETOOTH,
+            DISALLOW_BLUETOOTH_SHARING,
+            DISALLOW_USB_FILE_TRANSFER,
+            DISALLOW_CONFIG_CREDENTIALS,
+            DISALLOW_REMOVE_USER,
+            DISALLOW_REMOVE_MANAGED_PROFILE,
+            DISALLOW_DEBUGGING_FEATURES,
+            DISALLOW_CONFIG_VPN,
+            DISALLOW_CONFIG_LOCATION,
+            DISALLOW_CONFIG_DATE_TIME,
+            DISALLOW_CONFIG_TETHERING,
+            DISALLOW_NETWORK_RESET,
+            DISALLOW_FACTORY_RESET,
+            DISALLOW_ADD_USER,
+            DISALLOW_ADD_MANAGED_PROFILE,
+            ENSURE_VERIFY_APPS,
+            DISALLOW_CONFIG_CELL_BROADCASTS,
+            DISALLOW_CONFIG_MOBILE_NETWORKS,
+            DISALLOW_APPS_CONTROL,
+            DISALLOW_MOUNT_PHYSICAL_MEDIA,
+            DISALLOW_UNMUTE_MICROPHONE,
+            DISALLOW_ADJUST_VOLUME,
+            DISALLOW_OUTGOING_CALLS,
+            DISALLOW_SMS,
+            DISALLOW_FUN,
+            DISALLOW_CREATE_WINDOWS,
+            DISALLOW_SYSTEM_ERROR_DIALOGS,
+            DISALLOW_CROSS_PROFILE_COPY_PASTE,
+            DISALLOW_OUTGOING_BEAM,
+            DISALLOW_WALLPAPER,
+            DISALLOW_SET_WALLPAPER,
+            DISALLOW_SAFE_BOOT,
+            DISALLOW_RECORD_AUDIO,
+            DISALLOW_RUN_IN_BACKGROUND,
+            DISALLOW_CAMERA,
+            DISALLOW_UNMUTE_DEVICE,
+            DISALLOW_DATA_ROAMING,
+            DISALLOW_SET_USER_ICON,
+            DISALLOW_OEM_UNLOCK,
+            DISALLOW_UNIFIED_PASSWORD,
+            ALLOW_PARENT_PROFILE_APP_LINKING,
+            DISALLOW_AUTOFILL,
+            DISALLOW_CONTENT_CAPTURE,
+            DISALLOW_CONTENT_SUGGESTIONS,
+            DISALLOW_USER_SWITCH,
+            DISALLOW_SHARE_INTO_MANAGED_PROFILE,
+            DISALLOW_PRINTING,
+            DISALLOW_CONFIG_PRIVATE_DNS,
+            KEY_RESTRICTIONS_PENDING,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface UserRestrictionKey {}
+
     private static final String ACTION_CREATE_USER = "android.os.action.CREATE_USER";
 
     /**
@@ -2025,7 +2103,8 @@
     @SystemApi
     @UserRestrictionSource
     @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
-    public int getUserRestrictionSource(String restrictionKey, UserHandle userHandle) {
+    public int getUserRestrictionSource(@UserRestrictionKey String restrictionKey,
+            UserHandle userHandle) {
         try {
             return mService.getUserRestrictionSource(restrictionKey, userHandle.getIdentifier());
         } catch (RemoteException re) {
@@ -2044,7 +2123,7 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
     public List<EnforcingUser> getUserRestrictionSources(
-            String restrictionKey, UserHandle userHandle) {
+            @UserRestrictionKey String restrictionKey, UserHandle userHandle) {
         try {
             return mService.getUserRestrictionSources(restrictionKey, userHandle.getIdentifier());
         } catch (RemoteException re) {
@@ -2090,7 +2169,8 @@
      * @param userHandle the UserHandle of the user for whom to retrieve the restrictions.
      */
     @UnsupportedAppUsage
-    public boolean hasBaseUserRestriction(String restrictionKey, UserHandle userHandle) {
+    public boolean hasBaseUserRestriction(@UserRestrictionKey String restrictionKey,
+            UserHandle userHandle) {
         try {
             return mService.hasBaseUserRestriction(restrictionKey, userHandle.getIdentifier());
         } catch (RemoteException re) {
@@ -2161,7 +2241,7 @@
      * @param restrictionKey The string key representing the restriction.
      * @return {@code true} if the current user has the given restriction, {@code false} otherwise.
      */
-    public boolean hasUserRestriction(String restrictionKey) {
+    public boolean hasUserRestriction(@UserRestrictionKey String restrictionKey) {
         return hasUserRestrictionForUser(restrictionKey, Process.myUserHandle());
     }
 
@@ -2173,7 +2253,8 @@
      * @param userHandle the UserHandle of the user for whom to retrieve the restrictions.
      */
     @UnsupportedAppUsage
-    public boolean hasUserRestriction(String restrictionKey, UserHandle userHandle) {
+    public boolean hasUserRestriction(@UserRestrictionKey String restrictionKey,
+            UserHandle userHandle) {
         return hasUserRestrictionForUser(restrictionKey, userHandle);
     }
 
@@ -2193,7 +2274,7 @@
     @RequiresPermission(anyOf = {
             android.Manifest.permission.MANAGE_USERS,
             android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
-    public boolean hasUserRestrictionForUser(@NonNull String restrictionKey,
+    public boolean hasUserRestrictionForUser(@NonNull @UserRestrictionKey String restrictionKey,
             @NonNull UserHandle userHandle) {
         try {
             return mService.hasUserRestriction(restrictionKey, userHandle.getIdentifier());
@@ -2206,7 +2287,7 @@
      * @hide
      * Returns whether any user on the device has the given user restriction set.
      */
-    public boolean hasUserRestrictionOnAnyUser(String restrictionKey) {
+    public boolean hasUserRestrictionOnAnyUser(@UserRestrictionKey String restrictionKey) {
         try {
             return mService.hasUserRestrictionOnAnyUser(restrictionKey);
         } catch (RemoteException re) {
@@ -2374,6 +2455,20 @@
     }
 
     /**
+     * Gets the existing guest user if it exists.  This does not include guest users that are dying.
+     * @return The existing guest user if it exists. Null otherwise.
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    public UserInfo findCurrentGuestUser() {
+        try {
+            return mService.findCurrentGuestUser();
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Creates a user with the specified name and options as a profile of another user.
      * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      * The type of profile must be specified using the given flags.
@@ -2708,6 +2803,21 @@
     }
 
     /**
+     * Returns information for all users on this device. Requires
+     * {@link android.Manifest.permission#MANAGE_USERS} permission.
+     *
+     * @param excludeDying specify if the list should exclude users being
+     *            removed.
+     * @return the list of users that were created.
+     * @hide
+     */
+    @UnsupportedAppUsage
+    public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
+        return getUsers(/*excludePartial= */ true, excludeDying,
+                /* excludePreCreated= */ true);
+    }
+
+    /**
      * Returns information for all users on this device, based on the filtering parameters.
      *
      * @hide
@@ -2723,6 +2833,24 @@
     }
 
     /**
+     * Returns the user handles for all users on this device, based on the filtering parameters.
+     *
+     * @param excludeDying specify if the list should exclude users being removed.
+     * @return the list of user handles.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    public @NonNull List<UserHandle> getUserHandles(boolean excludeDying) {
+        List<UserInfo> users = getUsers(excludeDying);
+        List<UserHandle> result = new ArrayList<>(users.size());
+        for (UserInfo user : users) {
+            result.add(user.getUserHandle());
+        }
+        return result;
+    }
+
+    /**
      * Returns serial numbers of all users on this device.
      *
      * @param excludeDying specify if the list should exclude users being removed.
@@ -3262,21 +3390,6 @@
     }
 
     /**
-     * Returns information for all users on this device. Requires
-     * {@link android.Manifest.permission#MANAGE_USERS} permission.
-     *
-     * @param excludeDying specify if the list should exclude users being
-     *            removed.
-     * @return the list of users that were created.
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
-        return getUsers(/*excludePartial= */ true, excludeDying,
-                /* excludePreCreated= */ true);
-    }
-
-    /**
      * Removes a user and all associated data.
      * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      * @param userId the integer handle of the user.
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index b5635a4..397c2a9 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -1218,7 +1218,7 @@
     }
 
     /** @hide */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long workSourceToken = proto.start(fieldId);
         for (int i = 0; i < mNum; i++) {
             final long contentProto = proto.start(WorkSourceProto.WORK_SOURCE_CONTENTS);
diff --git a/core/java/android/os/connectivity/CellularBatteryStats.java b/core/java/android/os/connectivity/CellularBatteryStats.java
index caa4068..b8c1802 100644
--- a/core/java/android/os/connectivity/CellularBatteryStats.java
+++ b/core/java/android/os/connectivity/CellularBatteryStats.java
@@ -22,8 +22,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.telephony.Annotation.NetworkType;
+import android.telephony.CellSignalStrength;
 import android.telephony.ModemActivityInfo;
-import android.telephony.SignalStrength;
 
 import java.util.Arrays;
 import java.util.Objects;
@@ -48,7 +48,7 @@
     private long mEnergyConsumedMaMs = 0;
     private long[] mTimeInRatMs = new long[BatteryStats.NUM_DATA_CONNECTION_TYPES];
     private long[] mTimeInRxSignalStrengthLevelMs =
-            new long[SignalStrength.NUM_SIGNAL_STRENGTH_BINS];
+            new long[CellSignalStrength.getNumSignalStrengthLevels()];
     private long[] mTxTimeMs = new long[ModemActivityInfo.TX_POWER_LEVELS];
     private long mMonitoredRailChargeConsumedMaMs = 0;
 
@@ -354,7 +354,7 @@
     /** @hide **/
     public void setTimeInRxSignalStrengthLevelMicros(@NonNull long[] t) {
         mTimeInRxSignalStrengthLevelMs = Arrays.copyOfRange(t, 0,
-            Math.min(t.length, SignalStrength.NUM_SIGNAL_STRENGTH_BINS));
+            Math.min(t.length, CellSignalStrength.getNumSignalStrengthLevels()));
         return;
     }
 
diff --git a/core/java/android/os/connectivity/WifiActivityEnergyInfo.aidl b/core/java/android/os/connectivity/WifiActivityEnergyInfo.aidl
new file mode 100644
index 0000000..ce75c12
--- /dev/null
+++ b/core/java/android/os/connectivity/WifiActivityEnergyInfo.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.os.connectivity;
+
+parcelable WifiActivityEnergyInfo;
diff --git a/core/java/android/os/connectivity/WifiActivityEnergyInfo.java b/core/java/android/os/connectivity/WifiActivityEnergyInfo.java
new file mode 100644
index 0000000..664b6c8
--- /dev/null
+++ b/core/java/android/os/connectivity/WifiActivityEnergyInfo.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.os.connectivity;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.app.ActivityThread;
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.os.PowerProfile;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Record of energy and activity information from controller and
+ * underlying wifi stack state. Timestamp the record with elapsed
+ * real-time.
+ * @hide
+ */
+@SystemApi
+public final class WifiActivityEnergyInfo implements Parcelable {
+    private long mTimeSinceBootMillis;
+    @StackState
+    private int mStackState;
+    private long mControllerTxDurationMillis;
+    private long mControllerRxDurationMillis;
+    private long mControllerScanDurationMillis;
+    private long mControllerIdleDurationMillis;
+    private long mControllerEnergyUsedMicroJoules;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"STACK_STATE_"}, value = {
+            STACK_STATE_INVALID,
+            STACK_STATE_STATE_ACTIVE,
+            STACK_STATE_STATE_SCANNING,
+            STACK_STATE_STATE_IDLE})
+    public @interface StackState {}
+
+    /** Invalid Wifi stack state. */
+    public static final int STACK_STATE_INVALID = 0;
+    /** Wifi stack is active. */
+    public static final int STACK_STATE_STATE_ACTIVE = 1;
+    /** Wifi stack is scanning. */
+    public static final int STACK_STATE_STATE_SCANNING = 2;
+    /** Wifi stack is idle. */
+    public static final int STACK_STATE_STATE_IDLE = 3;
+
+    /**
+     * Constructor.
+     *
+     * @param timeSinceBootMillis the time since boot, in milliseconds.
+     * @param stackState The current state of the Wifi Stack. One of {@link #STACK_STATE_INVALID},
+     *                   {@link #STACK_STATE_STATE_ACTIVE}, {@link #STACK_STATE_STATE_SCANNING},
+     *                   or {@link #STACK_STATE_STATE_IDLE}.
+     * @param txDurationMillis Cumulative milliseconds of active transmission.
+     * @param rxDurationMillis Cumulative milliseconds of active receive.
+     * @param scanDurationMillis Cumulative milliseconds when radio is awake due to scan.
+     * @param idleDurationMillis Cumulative milliseconds when radio is awake but not transmitting or
+     *                       receiving.
+     */
+    public WifiActivityEnergyInfo(
+            long timeSinceBootMillis,
+            @StackState int stackState,
+            long txDurationMillis,
+            long rxDurationMillis,
+            long scanDurationMillis,
+            long idleDurationMillis) {
+        mTimeSinceBootMillis = timeSinceBootMillis;
+        mStackState = stackState;
+        mControllerTxDurationMillis = txDurationMillis;
+        mControllerRxDurationMillis = rxDurationMillis;
+        mControllerScanDurationMillis = scanDurationMillis;
+        mControllerIdleDurationMillis = idleDurationMillis;
+
+        final Context context = ActivityThread.currentActivityThread().getSystemContext();
+        if (context == null) {
+            mControllerEnergyUsedMicroJoules = 0L;
+            return;
+        }
+        // Calculate energy used using PowerProfile.
+        PowerProfile powerProfile = new PowerProfile(context);
+        final double rxIdleCurrent = powerProfile.getAveragePower(
+                PowerProfile.POWER_WIFI_CONTROLLER_IDLE);
+        final double rxCurrent = powerProfile.getAveragePower(
+                PowerProfile.POWER_WIFI_CONTROLLER_RX);
+        final double txCurrent = powerProfile.getAveragePower(
+                PowerProfile.POWER_WIFI_CONTROLLER_TX);
+        final double voltage = powerProfile.getAveragePower(
+                PowerProfile.POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
+        final long energyUsedMicroJoules = (long) ((mControllerTxDurationMillis * txCurrent
+                + mControllerRxDurationMillis * rxCurrent
+                + mControllerIdleDurationMillis * rxIdleCurrent)
+                * voltage);
+        mControllerEnergyUsedMicroJoules = energyUsedMicroJoules;
+    }
+
+    @Override
+    public String toString() {
+        return "WifiActivityEnergyInfo{"
+                + " mTimeSinceBootMillis=" + mTimeSinceBootMillis
+                + " mStackState=" + mStackState
+                + " mControllerTxDurationMillis=" + mControllerTxDurationMillis
+                + " mControllerRxDurationMillis=" + mControllerRxDurationMillis
+                + " mControllerScanDurationMillis=" + mControllerScanDurationMillis
+                + " mControllerIdleDurationMillis=" + mControllerIdleDurationMillis
+                + " mControllerEnergyUsedMicroJoules=" + mControllerEnergyUsedMicroJoules
+                + " }";
+    }
+
+    public static final @NonNull Parcelable.Creator<WifiActivityEnergyInfo> CREATOR =
+            new Parcelable.Creator<WifiActivityEnergyInfo>() {
+        public WifiActivityEnergyInfo createFromParcel(Parcel in) {
+            long timestamp = in.readLong();
+            int stackState = in.readInt();
+            long txTime = in.readLong();
+            long rxTime = in.readLong();
+            long scanTime = in.readLong();
+            long idleTime = in.readLong();
+            return new WifiActivityEnergyInfo(timestamp, stackState,
+                    txTime, rxTime, scanTime, idleTime);
+        }
+        public WifiActivityEnergyInfo[] newArray(int size) {
+            return new WifiActivityEnergyInfo[size];
+        }
+    };
+
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeLong(mTimeSinceBootMillis);
+        out.writeInt(mStackState);
+        out.writeLong(mControllerTxDurationMillis);
+        out.writeLong(mControllerRxDurationMillis);
+        out.writeLong(mControllerScanDurationMillis);
+        out.writeLong(mControllerIdleDurationMillis);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Get the timestamp (milliseconds since boot) of record creation. */
+    public long getTimeSinceBootMillis() {
+        return mTimeSinceBootMillis;
+    }
+
+    /** Set the timestamp (milliseconds since boot) of record creation. */
+    public void setTimeSinceBootMillis(long timeSinceBootMillis) {
+        mTimeSinceBootMillis = timeSinceBootMillis;
+    }
+
+    /**
+     * Get the Wifi stack reported state. One of {@link #STACK_STATE_INVALID},
+     * {@link #STACK_STATE_STATE_ACTIVE}, {@link #STACK_STATE_STATE_SCANNING},
+     * {@link #STACK_STATE_STATE_IDLE}.
+     */
+    @StackState
+    public int getStackState() {
+        return mStackState;
+    }
+
+    /**
+     * Set the Wifi stack reported state. One of {@link #STACK_STATE_INVALID},
+     * {@link #STACK_STATE_STATE_ACTIVE}, {@link #STACK_STATE_STATE_SCANNING},
+     * {@link #STACK_STATE_STATE_IDLE}.
+     */
+    public void setStackState(@StackState int stackState) {
+        mStackState = stackState;
+    }
+
+    /** Get the Wifi transmission duration, in milliseconds. */
+    public long getControllerTxDurationMillis() {
+        return mControllerTxDurationMillis;
+    }
+
+    /** Set the Wifi transmission duration, in milliseconds. */
+    public void setControllerTxDurationMillis(long controllerTxDurationMillis) {
+        mControllerTxDurationMillis = controllerTxDurationMillis;
+    }
+
+    /** Get the Wifi receive duration, in milliseconds. */
+    public long getControllerRxDurationMillis() {
+        return mControllerRxDurationMillis;
+    }
+
+    /** Set the Wifi receive duration, in milliseconds. */
+    public void setControllerRxDurationMillis(long controllerRxDurationMillis) {
+        mControllerRxDurationMillis = controllerRxDurationMillis;
+    }
+
+    /** Get the Wifi scan duration, in milliseconds. */
+    public long getControllerScanDurationMillis() {
+        return mControllerScanDurationMillis;
+    }
+
+    /** Set the Wifi scan duration, in milliseconds. */
+    public void setControllerScanDurationMillis(long controllerScanDurationMillis) {
+        mControllerScanDurationMillis = controllerScanDurationMillis;
+    }
+
+    /** Get the Wifi idle duration, in milliseconds. */
+    public long getControllerIdleDurationMillis() {
+        return mControllerIdleDurationMillis;
+    }
+
+    /** Set the Wifi idle duration, in milliseconds. */
+    public void setControllerIdleDurationMillis(long controllerIdleDurationMillis) {
+        mControllerIdleDurationMillis = controllerIdleDurationMillis;
+    }
+
+    /** Get the energy consumed by Wifi, in microjoules. */
+    public long getControllerEnergyUsedMicroJoules() {
+        return mControllerEnergyUsedMicroJoules;
+    }
+
+    /** Set the energy consumed by Wifi, in microjoules. */
+    public void setControllerEnergyUsedMicroJoules(long controllerEnergyUsedMicroJoules) {
+        mControllerEnergyUsedMicroJoules = controllerEnergyUsedMicroJoules;
+    }
+
+    /** Returns true if the record is valid, false otherwise. */
+    public boolean isValid() {
+        return mControllerTxDurationMillis >= 0
+                && mControllerRxDurationMillis >= 0
+                && mControllerScanDurationMillis >= 0
+                && mControllerIdleDurationMillis >= 0;
+    }
+}
diff --git a/core/java/android/os/incremental/IIncrementalManager.aidl b/core/java/android/os/incremental/IIncrementalManager.aidl
new file mode 100644
index 0000000..d6446d4
--- /dev/null
+++ b/core/java/android/os/incremental/IIncrementalManager.aidl
@@ -0,0 +1,104 @@
+/*
+ * 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.os.incremental;
+
+import android.os.incremental.IncrementalDataLoaderParamsParcel;
+
+/** @hide */
+interface IIncrementalManager {
+    /**
+     * A set of flags for the |createMode| parameters when creating a new Incremental storage.
+     */
+    const int CREATE_MODE_TEMPORARY_BIND = 1;
+    const int CREATE_MODE_PERMANENT_BIND = 2;
+    const int CREATE_MODE_CREATE = 4;
+    const int CREATE_MODE_OPEN_EXISTING = 8;
+
+    /**
+     * Opens or creates a storage given a target path and data loader params. Returns the storage ID.
+     */
+    int openStorage(in @utf8InCpp String path);
+    int createStorage(in @utf8InCpp String path, in IncrementalDataLoaderParamsParcel params, int createMode);
+    int createLinkedStorage(in @utf8InCpp String path, int otherStorageId, int createMode);
+
+    /**
+     * Bind-mounts a path under a storage to a full path. Can be permanent or temporary.
+     */
+    const int BIND_TEMPORARY = 0;
+    const int BIND_PERMANENT = 1;
+    int makeBindMount(int storageId, in @utf8InCpp String pathUnderStorage, in @utf8InCpp String targetFullPath, int bindType);
+
+    /**
+     * Deletes an existing bind mount on a path under a storage. Returns 0 on success, and -errno on failure.
+     */
+    int deleteBindMount(int storageId, in @utf8InCpp String targetFullPath);
+
+    /**
+     * Creates a directory under a storage. The target directory is specified by its relative path under the storage.
+     */
+    int makeDirectory(int storageId, in @utf8InCpp String pathUnderStorage);
+
+    /**
+     * Recursively creates a directory under a storage. The target directory is specified by its relative path under the storage.
+     * All the parent directories of the target directory will be created if they do not exist already.
+     */
+    int makeDirectories(int storageId, in @utf8InCpp String pathUnderStorage);
+
+    /**
+     * Creates a file under a storage, specifying its name, size and metadata.
+     */
+    int makeFile(int storageId, in @utf8InCpp String pathUnderStorage, long size, in byte[] metadata);
+
+    /**
+     * Creates a file under a storage. Content of the file is from a range inside another file.
+     * Both files are specified by relative paths under storage.
+     */
+    int makeFileFromRange(int storageId, in @utf8InCpp String targetPathUnderStorage, in @utf8InCpp String sourcePathUnderStorage, long start, long end);
+
+    /**
+     * Creates a hard link between two files in two storage instances.
+     * Source and dest specified by parent storage IDs and their relative paths under the storage.
+     * The source and dest storage instances should be in the same fs mount.
+     * Note: destStorageId can be the same as sourceStorageId.
+     */
+    int makeLink(int sourceStorageId, in @utf8InCpp String sourcePathUnderStorage, int destStorageId, in @utf8InCpp String destPathUnderStorage);
+
+    /**
+     * Deletes a hard link in a storage, specified by the relative path of the link target under storage.
+     */
+    int unlink(int storageId, in @utf8InCpp String pathUnderStorage);
+
+    /**
+     * Checks if a file's certain range is loaded. File is specified by relative file path under storage.
+     */
+    boolean isFileRangeLoaded(int storageId, in @utf8InCpp String pathUnderStorage, long start, long end);
+
+    /**
+     * Reads the metadata of a file. File is specified by relative path under storage.
+     */
+    byte[] getFileMetadata(int storageId, in @utf8InCpp String pathUnderStorage);
+
+    /**
+     * Starts loading data for a storage.
+     */
+    boolean startLoading(int storageId);
+
+    /**
+     * Deletes a storage given its ID. Deletes its bind mounts and unmount it. Stop its data loader.
+     */
+    void deleteStorage(int storageId);
+}
diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl
deleted file mode 100644
index 1c832ca..0000000
--- a/core/java/android/os/incremental/IIncrementalService.aidl
+++ /dev/null
@@ -1,96 +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.os.incremental;
-
-import android.os.incremental.IncrementalDataLoaderParamsParcel;
-
-/** @hide */
-interface IIncrementalService {
-    /**
-     * A set of flags for the |createMode| parameters when creating a new Incremental storage.
-     */
-    const int CREATE_MODE_TEMPORARY_BIND = 1;
-    const int CREATE_MODE_PERMANENT_BIND = 2;
-    const int CREATE_MODE_CREATE = 4;
-    const int CREATE_MODE_OPEN_EXISTING = 8;
-
-    /**
-     * Opens or creates a storage given a target path and data loader params. Returns the storage ID.
-     */
-    int openStorage(in @utf8InCpp String path);
-    int createStorage(in @utf8InCpp String path, in IncrementalDataLoaderParamsParcel params, int createMode);
-    int createLinkedStorage(in @utf8InCpp String path, int otherStorageId, int createMode);
-
-    /**
-     * Bind-mounts a path under a storage to a full path. Can be permanent or temporary.
-     */
-    const int BIND_TEMPORARY = 0;
-    const int BIND_PERMANENT = 1;
-    int makeBindMount(int storageId, in @utf8InCpp String pathUnderStorage, in @utf8InCpp String targetFullPath, int bindType);
-
-    /**
-     * Deletes an existing bind mount on a path under a storage. Returns 0 on success, and -errno on failure.
-     */
-    int deleteBindMount(int storageId, in @utf8InCpp String targetFullPath);
-
-    /**
-     * Creates a directory under a storage. The target directory is specified by its relative path under the storage.
-     */
-    int makeDirectory(int storageId, in @utf8InCpp String pathUnderStorage);
-
-    /**
-     * Creates a file under a storage, specifying its name, size and metadata.
-     */
-    int makeFile(int storageId, in @utf8InCpp String pathUnderStorage, long size, in byte[] metadata);
-
-    /**
-     * Creates a file under a storage. Content of the file is from a range inside another file.
-     * Both files are specified by relative paths under storage.
-     */
-    int makeFileFromRange(int storageId, in @utf8InCpp String targetPathUnderStorage, in @utf8InCpp String sourcePathUnderStorage, long start, long end);
-
-    /**
-     * Creates a hard link between two files in a storage.
-     * Both source and destination are specified by relative paths under storage.
-     */
-    int makeLink(int storageId, in @utf8InCpp String sourcePathUnderStorage, in @utf8InCpp String destPathUnderStorage);
-
-    /**
-     * Deletes a hard link in a storage, specified by the relative path of the link target under storage.
-     */
-    int unlink(int storageId, in @utf8InCpp String pathUnderStorage);
-
-    /**
-     * Checks if a file's certain range is loaded. File is specified by relative file path under storage.
-     */
-    boolean isFileRangeLoaded(int storageId, in @utf8InCpp String pathUnderStorage, long start, long end);
-
-    /**
-     * Reads the metadata of a file. File is specified by relative path under storage.
-     */
-    byte[] getFileMetadata(int storageId, in @utf8InCpp String pathUnderStorage);
-
-    /**
-     * Returns the list of file paths under a storage.
-     */
-    @utf8InCpp String[] getFileList(int storageId);
-
-    /**
-     * Starts loading data for a storage.
-     */
-    boolean startLoading(int storageId);
-}
diff --git a/core/java/android/os/incremental/IIncrementalServiceProxy.aidl b/core/java/android/os/incremental/IIncrementalServiceProxy.aidl
index 12740ea..ffff52e 100644
--- a/core/java/android/os/incremental/IIncrementalServiceProxy.aidl
+++ b/core/java/android/os/incremental/IIncrementalServiceProxy.aidl
@@ -18,7 +18,7 @@
 
 import android.os.incremental.IncrementalFileSystemControlParcel;
 import android.os.incremental.IncrementalDataLoaderParamsParcel;
-import android.service.incremental.IIncrementalDataLoaderStatusListener;
+import android.content.pm.IDataLoaderStatusListener;
 
 /**
  * Binder service to receive calls from native Incremental Service and handle Java tasks such as
@@ -29,7 +29,7 @@
     boolean prepareDataLoader(int mountId,
         in IncrementalFileSystemControlParcel control,
         in IncrementalDataLoaderParamsParcel params,
-        in IIncrementalDataLoaderStatusListener listener);
+        in IDataLoaderStatusListener listener);
     boolean startDataLoader(int mountId);
     void showHealthBlockedUI(int mountId);
     void destroyDataLoader(int mountId);
diff --git a/core/java/android/os/incremental/IncrementalDataLoaderParams.java b/core/java/android/os/incremental/IncrementalDataLoaderParams.java
new file mode 100644
index 0000000..701f1cc
--- /dev/null
+++ b/core/java/android/os/incremental/IncrementalDataLoaderParams.java
@@ -0,0 +1,84 @@
+/*
+ * 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.os.incremental;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.ParcelFileDescriptor;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * This class represents the parameters used to configure an Incremental Data Loader.
+ * Hide for now.
+ * @hide
+ */
+public class IncrementalDataLoaderParams {
+    @NonNull private final IncrementalDataLoaderParamsParcel mData;
+
+    public IncrementalDataLoaderParams(@NonNull String url, @NonNull String packageName,
+            @Nullable Map<String, ParcelFileDescriptor> namedFds) {
+        IncrementalDataLoaderParamsParcel data = new IncrementalDataLoaderParamsParcel();
+        data.staticArgs = url;
+        data.packageName = packageName;
+        if (namedFds == null || namedFds.isEmpty()) {
+            data.dynamicArgs = new NamedParcelFileDescriptor[0];
+        } else {
+            data.dynamicArgs = new NamedParcelFileDescriptor[namedFds.size()];
+            int i = 0;
+            for (Map.Entry<String, ParcelFileDescriptor> namedFd : namedFds.entrySet()) {
+                data.dynamicArgs[i] = new NamedParcelFileDescriptor();
+                data.dynamicArgs[i].name = namedFd.getKey();
+                data.dynamicArgs[i].fd = namedFd.getValue();
+                i += 1;
+            }
+        }
+        mData = data;
+    }
+
+    public IncrementalDataLoaderParams(@NonNull IncrementalDataLoaderParamsParcel data) {
+        mData = data;
+    }
+
+    /**
+     * @return static server's URL
+     */
+    public final @NonNull String getStaticArgs() {
+        return mData.staticArgs;
+    }
+
+    /**
+     * @return data loader's package name
+     */
+    public final @NonNull String getPackageName() {
+        return mData.packageName;
+    }
+
+    public final @NonNull IncrementalDataLoaderParamsParcel getData() {
+        return mData;
+    }
+
+    /**
+     * @return data loader's dynamic arguments such as file descriptors
+     */
+    public final @NonNull Map<String, ParcelFileDescriptor> getDynamicArgs() {
+        return Arrays.stream(mData.dynamicArgs).collect(
+            Collectors.toMap(p->p.name, p->p.fd));
+    }
+}
diff --git a/core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl b/core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl
index 50c28f0..cd988dc 100644
--- a/core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl
+++ b/core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl
@@ -23,7 +23,7 @@
  * @hide
  */
 parcelable IncrementalDataLoaderParamsParcel {
-    @utf8InCpp String staticUri;
     @utf8InCpp String packageName;
+    @utf8InCpp String staticArgs;
     NamedParcelFileDescriptor[] dynamicArgs;
 }
diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java
new file mode 100644
index 0000000..5bd0748
--- /dev/null
+++ b/core/java/android/os/incremental/IncrementalFileStorages.java
@@ -0,0 +1,280 @@
+/*
+ * 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.os.incremental;
+
+/**
+ * Set up files and directories used in an installation session.
+ * Currently only used by Incremental Installation.
+ * For Incremental installation, the expected outcome of this function is:
+ * 0) All the files are in defaultStorage
+ * 1) All APK files are in the same directory, bound to mApkStorage, and bound to the
+ * InstallerSession's stage dir. The files are linked from mApkStorage to defaultStorage.
+ * 2) All lib files are in the sub directories as their names suggest, and in the same parent
+ * directory as the APK files. The files are linked from mApkStorage to defaultStorage.
+ * 3) OBB files are in another directory that is different from APK files and lib files, bound
+ * to mObbStorage. The files are linked from mObbStorage to defaultStorage.
+ *
+ * @throws IllegalStateException the session is not an Incremental installation session.
+ */
+
+import static dalvik.system.VMRuntime.getInstructionSet;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.InstallationFile;
+import android.os.IVold;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Random;
+
+/**
+ * This class manages storage instances used during a package installation session.
+ * @hide
+ */
+public final class IncrementalFileStorages {
+    private static final String TAG = "IncrementalFileStorages";
+    private @Nullable IncrementalStorage mDefaultStorage;
+    private @Nullable IncrementalStorage mApkStorage;
+    private @Nullable IncrementalStorage mObbStorage;
+    private @Nullable String mDefaultDir;
+    private @Nullable String mObbDir;
+    private @NonNull IncrementalManager mIncrementalManager;
+    private @Nullable ArraySet<String> mLibDirs;
+    private @NonNull String mPackageName;
+    private @NonNull File mStageDir;
+
+    /**
+     * Set up files and directories used in an installation session.
+     * Currently only used by Incremental Installation.
+     * For Incremental installation, the expected outcome of this function is:
+     * 0) All the files are in defaultStorage
+     * 1) All APK files are in the same directory, bound to mApkStorage, and bound to the
+     * InstallerSession's stage dir. The files are linked from mApkStorage to defaultStorage.
+     * 2) All lib files are in the sub directories as their names suggest, and in the same parent
+     * directory as the APK files. The files are linked from mApkStorage to defaultStorage.
+     * 3) OBB files are in another directory that is different from APK files and lib files, bound
+     * to mObbStorage. The files are linked from mObbStorage to defaultStorage.
+     *
+     * @throws IllegalStateException the session is not an Incremental installation session.
+     */
+    public IncrementalFileStorages(@NonNull String packageName,
+            @NonNull File stageDir,
+            @NonNull IncrementalManager incrementalManager,
+            @NonNull IncrementalDataLoaderParams incrementalDataLoaderParams) {
+        mPackageName = packageName;
+        mStageDir = stageDir;
+        mIncrementalManager = incrementalManager;
+        if (incrementalDataLoaderParams.getPackageName().equals("local")) {
+            final String incrementalPath = incrementalDataLoaderParams.getStaticArgs();
+            mDefaultStorage = mIncrementalManager.openStorage(incrementalPath);
+            mDefaultDir = incrementalPath;
+            return;
+        }
+        mDefaultDir = getTempDir();
+        if (mDefaultDir == null) {
+            return;
+        }
+        mDefaultStorage = mIncrementalManager.createStorage(mDefaultDir,
+                incrementalDataLoaderParams,
+                IncrementalManager.CREATE_MODE_CREATE
+                        | IncrementalManager.CREATE_MODE_TEMPORARY_BIND, false);
+    }
+
+    /**
+     * Adds a file into the installation session. Makes sure it will be placed inside
+     * a proper storage instance, based on its file type.
+     */
+    public void addFile(@NonNull InstallationFile file) throws IOException {
+        if (mDefaultStorage == null) {
+            throw new IOException("Cannot add file because default storage does not exist");
+        }
+        if (file.getFileType() == InstallationFile.FILE_TYPE_APK) {
+            addApkFile(file);
+        } else if (file.getFileType() == InstallationFile.FILE_TYPE_OBB) {
+            addObbFile(file);
+        } else if (file.getFileType() == InstallationFile.FILE_TYPE_LIB) {
+            addLibFile(file);
+        } else {
+            throw new IOException("Unknown file type: " + file.getFileType());
+        }
+    }
+
+    private void addApkFile(@NonNull InstallationFile apk) throws IOException {
+        // Create a storage for APK files and lib files
+        final String stageDirPath = mStageDir.getAbsolutePath();
+        if (mApkStorage == null) {
+            mApkStorage = mIncrementalManager.createStorage(stageDirPath, mDefaultStorage,
+                    IncrementalManager.CREATE_MODE_CREATE
+                            | IncrementalManager.CREATE_MODE_TEMPORARY_BIND);
+            mApkStorage.bind(stageDirPath);
+        }
+
+        if (!new File(mDefaultDir, apk.getName()).exists()) {
+            mDefaultStorage.makeFile(apk.getName(), apk.getSize(),
+                    apk.getMetadata());
+        }
+        // Assuming APK files are already named properly, e.g., "base.apk"
+        mDefaultStorage.makeLink(apk.getName(), mApkStorage, apk.getName());
+    }
+
+    private void addLibFile(@NonNull InstallationFile lib) throws IOException {
+        // TODO(b/136132412): remove this after we have incfs support for lib file mapping
+        if (mApkStorage == null) {
+            throw new IOException("Cannot add lib file without adding an apk file first");
+        }
+        if (mLibDirs == null) {
+            mLibDirs = new ArraySet<>();
+        }
+        String current = "";
+        final Path libDirPath = Paths.get(lib.getName()).getParent();
+        final int numDirComponents = libDirPath.getNameCount();
+        for (int i = 0; i < numDirComponents; i++) {
+            String dirName = libDirPath.getName(i).toString();
+            try {
+                dirName = getInstructionSet(dirName);
+            } catch (IllegalArgumentException ignored) {
+            }
+            current += dirName;
+            if (!mLibDirs.contains(current)) {
+                mDefaultStorage.makeDirectory(current);
+                mApkStorage.makeDirectory(current);
+                mLibDirs.add(current);
+            }
+            current += '/';
+        }
+        String libFilePath = current + Paths.get(lib.getName()).getFileName();
+        mDefaultStorage.makeFile(libFilePath, lib.getSize(), lib.getMetadata());
+        mDefaultStorage.makeLink(libFilePath, mApkStorage, libFilePath);
+    }
+
+    private void addObbFile(@NonNull InstallationFile obb) throws IOException {
+        if (mObbStorage == null) {
+            // Create a storage for OBB files
+            mObbDir = getTempDir();
+            if (mObbDir == null) {
+                throw new IOException("Failed to create obb storage directory.");
+            }
+            mObbStorage = mIncrementalManager.createStorage(
+                    mObbDir, mDefaultStorage,
+                    IncrementalManager.CREATE_MODE_CREATE
+                            | IncrementalManager.CREATE_MODE_TEMPORARY_BIND);
+        }
+        mDefaultStorage.makeFile(obb.getName(), obb.getSize(), obb.getMetadata());
+        mDefaultStorage.makeLink(obb.getName(), mObbStorage, obb.getName());
+    }
+
+    private boolean hasObb() {
+        return (mObbStorage != null && mObbDir != null);
+    }
+
+    /**
+     * Starts loading data for default storage.
+     * TODO(b/136132412): update the implementation with latest API design.
+     */
+    public boolean startLoading() {
+        if (mDefaultStorage == null) {
+            return false;
+        }
+        return mDefaultStorage.startLoading();
+    }
+
+    /**
+     * Sets up obb storage directory and create bindings.
+     */
+    public void finishSetUp() {
+        if (!hasObb()) {
+            return;
+        }
+        final String mainObbDir = String.format("/storage/emulated/0/Android/obb/%s", mPackageName);
+        final String packageObbDirRoot =
+                String.format("/mnt/runtime/%s/emulated/0/Android/obb/", mPackageName);
+        final String[] obbDirs = {
+                packageObbDirRoot + "read",
+                packageObbDirRoot + "write",
+                packageObbDirRoot + "full",
+                packageObbDirRoot + "default",
+                String.format("/data/media/0/Android/obb/%s", mPackageName),
+                mainObbDir,
+        };
+        try {
+            Slog.i(TAG, "Creating obb directory '" + mainObbDir + "'");
+            final IVold vold = IVold.Stub.asInterface(ServiceManager.getServiceOrThrow("vold"));
+            vold.mkdirs(mainObbDir);
+            for (String d : obbDirs) {
+                mObbStorage.bindPermanent(d);
+            }
+        } catch (ServiceManager.ServiceNotFoundException ex) {
+            Slog.e(TAG, "vold service is not found.");
+            cleanUp();
+        } catch (IOException | RemoteException ex) {
+            Slog.e(TAG, "Failed to create obb dir at: " + mainObbDir, ex);
+            cleanUp();
+        }
+    }
+
+    /**
+     * Resets the states and unbinds storage instances for an installation session.
+     * TODO(b/136132412): make sure unnecessary binds are removed but useful storages are kept
+     */
+    public void cleanUp() {
+        if (mDefaultStorage != null && mDefaultDir != null) {
+            try {
+                mDefaultStorage.unBind(mDefaultDir);
+            } catch (IOException ignored) {
+            }
+            mDefaultDir = null;
+            mDefaultStorage = null;
+        }
+        if (mApkStorage != null && mStageDir != null) {
+            try {
+                mApkStorage.unBind(mStageDir.getAbsolutePath());
+            } catch (IOException ignored) {
+            }
+            mApkStorage = null;
+        }
+        if (mObbStorage != null && mObbDir != null) {
+            try {
+                mObbStorage.unBind(mObbDir);
+            } catch (IOException ignored) {
+            }
+            mObbDir = null;
+            mObbStorage = null;
+        }
+    }
+
+    private String getTempDir() {
+        final String tmpDirRoot = "/data/tmp";
+        final Random random = new Random();
+        final Path tmpDir =
+                Paths.get(tmpDirRoot, String.valueOf(random.nextInt(Integer.MAX_VALUE - 1)));
+        try {
+            Files.createDirectories(tmpDir);
+        } catch (Exception ex) {
+            Slog.e(TAG, "Failed to create dir", ex);
+            return null;
+        }
+        return tmpDir.toAbsolutePath().toString();
+    }
+}
diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java
new file mode 100644
index 0000000..5aabf86
--- /dev/null
+++ b/core/java/android/os/incremental/IncrementalManager.java
@@ -0,0 +1,327 @@
+/*
+ * 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.os.incremental;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.RemoteException;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Provides operations to open or create an IncrementalStorage, using IIncrementalManager service.
+ * Example Usage:
+ *
+ * <blockquote><pre>
+ * IncrementalManager manager = (IncrementalManager) getSystemService(Context.INCREMENTAL_MANAGER);
+ * IncrementalStorage storage = manager.openStorage("/path/to/incremental/dir");
+ * </pre></blockquote>
+ *
+ * @hide
+ */
+@SystemService(Context.INCREMENTAL_SERVICE)
+public class IncrementalManager {
+    private static final String TAG = "IncrementalManager";
+    private final IIncrementalManager mService;
+    @GuardedBy("mStorages")
+    private final SparseArray<IncrementalStorage> mStorages = new SparseArray<>();
+
+    public static final int CREATE_MODE_TEMPORARY_BIND =
+            IIncrementalManager.CREATE_MODE_TEMPORARY_BIND;
+    public static final int CREATE_MODE_PERMANENT_BIND =
+            IIncrementalManager.CREATE_MODE_PERMANENT_BIND;
+    public static final int CREATE_MODE_CREATE =
+            IIncrementalManager.CREATE_MODE_CREATE;
+    public static final int CREATE_MODE_OPEN_EXISTING =
+            IIncrementalManager.CREATE_MODE_OPEN_EXISTING;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"CREATE_MODE_"}, value = {
+            CREATE_MODE_TEMPORARY_BIND,
+            CREATE_MODE_PERMANENT_BIND,
+            CREATE_MODE_CREATE,
+            CREATE_MODE_OPEN_EXISTING,
+    })
+    public @interface CreateMode {
+    }
+
+    public IncrementalManager(@NonNull IIncrementalManager is) {
+        mService = is;
+    }
+
+    /**
+     * Returns a storage object given a storage ID.
+     *
+     * @param storageId The storage ID to identify the storage object.
+     * @return IncrementalStorage object corresponding to storage ID.
+     */
+    @Nullable
+    public IncrementalStorage getStorage(int storageId) {
+        synchronized (mStorages) {
+            return mStorages.get(storageId);
+        }
+    }
+
+    /**
+     * Opens or create an Incremental File System mounted directory and returns an
+     * IncrementalStorage object.
+     *
+     * @param path                Absolute path to mount Incremental File System on.
+     * @param params              IncrementalDataLoaderParams object to configure data loading.
+     * @param createMode          Mode for opening an old Incremental File System mount or
+     *                            creating a new mount.
+     * @param autoStartDataLoader Set true to immediately start data loader after creating storage.
+     * @return IncrementalStorage object corresponding to the mounted directory.
+     */
+    @Nullable
+    public IncrementalStorage createStorage(@NonNull String path,
+            @NonNull IncrementalDataLoaderParams params, @CreateMode int createMode,
+            boolean autoStartDataLoader) {
+        try {
+            final int id = mService.createStorage(path, params.getData(), createMode);
+            if (id < 0) {
+                return null;
+            }
+            final IncrementalStorage storage = new IncrementalStorage(mService, id);
+            synchronized (mStorages) {
+                mStorages.put(id, storage);
+            }
+            if (autoStartDataLoader) {
+                storage.startLoading();
+            }
+            return storage;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Opens an existing Incremental File System mounted directory and returns an
+     * IncrementalStorage object.
+     *
+     * @param path Absolute target path that Incremental File System has been mounted on.
+     * @return IncrementalStorage object corresponding to the mounted directory.
+     */
+    @Nullable
+    public IncrementalStorage openStorage(@NonNull String path) {
+        try {
+            final int id = mService.openStorage(path);
+            if (id < 0) {
+                return null;
+            }
+            final IncrementalStorage storage = new IncrementalStorage(mService, id);
+            synchronized (mStorages) {
+                mStorages.put(id, storage);
+            }
+            return storage;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Opens or creates an IncrementalStorage that is linked to another IncrementalStorage.
+     *
+     * @return IncrementalStorage object corresponding to the linked storage.
+     */
+    @Nullable
+    public IncrementalStorage createStorage(@NonNull String path,
+            @NonNull IncrementalStorage linkedStorage, @CreateMode int createMode) {
+        try {
+            final int id = mService.createLinkedStorage(path, linkedStorage.getId(), createMode);
+            if (id < 0) {
+                return null;
+            }
+            final IncrementalStorage storage = new IncrementalStorage(mService, id);
+            synchronized (mStorages) {
+                mStorages.put(id, storage);
+            }
+            return storage;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Iterates through path parents to find the base dir of an Incremental Storage.
+     *
+     * @param file Target file to search storage for.
+     * @return Absolute path which is a bind-mount point of Incremental File System.
+     */
+    private Path getStoragePathForFile(File file) {
+        File currentPath = new File(file.getParent());
+        while (currentPath.getParent() != null) {
+            IncrementalStorage storage = openStorage(currentPath.getAbsolutePath());
+            if (storage != null) {
+                return currentPath.toPath();
+            }
+            currentPath = new File(currentPath.getParent());
+        }
+        return null;
+    }
+
+    /**
+     * Renames an Incremental path to a new path. If source path is a file, make a link from the old
+     * Incremental file to the new one. If source path is a dir, unbind old dir from Incremental
+     * Storage and bind the new one.
+     * <ol>
+     *     <li> For renaming a dir, dest dir will be created if not exists, and does not need to
+     *          be on the same Incremental storage as the source. </li>
+     *     <li> For renaming a file, dest file must be on the same Incremental storage as source.
+     *     </li>
+     * </ol>
+     *
+     * @param sourcePath   Absolute path to the source. Should be the same type as the destPath
+     *                     (file or dir). Expected to already exist and is an Incremental path.
+     * @param destPath     Absolute path to the destination.
+     * @throws IllegalArgumentException when 1) source does not exist,
+     *                     or 2) source and dest type mismatch (one is file and the other is dir),
+     *                     or 3) source path is not on Incremental File System,
+     * @throws IOException when 1) cannot find the root path of the Incremental storage of source,
+     *                     or 2) cannot retrieve the Incremental storage instance of the source,
+     *                     or 3) renaming a file, but dest is not on the same Incremental Storage,
+     *                     or 4) renaming a dir, dest dir does not exist but fails to be created.
+     *
+     * TODO(b/136132412): add unit tests
+     */
+    public void rename(@NonNull String sourcePath, @NonNull String destPath) throws IOException {
+        final File source = new File(sourcePath);
+        final File dest = new File(destPath);
+        if (!source.exists()) {
+            throw new IllegalArgumentException("Path not exist: " + sourcePath);
+        }
+        if (dest.exists()) {
+            throw new IllegalArgumentException("Target path already exists: " + destPath);
+        }
+        if (source.isDirectory() && dest.exists() && dest.isFile()) {
+            throw new IllegalArgumentException(
+                    "Trying to rename a dir but destination is a file: " + destPath);
+        }
+        if (source.isFile() && dest.exists() && dest.isDirectory()) {
+            throw new IllegalArgumentException(
+                    "Trying to rename a file but destination is a dir: " + destPath);
+        }
+        if (!isIncrementalPath(sourcePath)) {
+            throw new IllegalArgumentException("Not an Incremental path: " + sourcePath);
+        }
+
+        Path storagePath = Paths.get(sourcePath);
+        if (source.isFile()) {
+            storagePath = getStoragePathForFile(source);
+        }
+        if (storagePath == null || storagePath.toAbsolutePath() == null) {
+            throw new IOException("Invalid source storage path for: " + sourcePath);
+        }
+        final IncrementalStorage storage = openStorage(storagePath.toAbsolutePath().toString());
+        if (storage == null) {
+            throw new IOException("Failed to retrieve storage from Incremental Service.");
+        }
+        if (source.isFile()) {
+            renameFile(storage, storagePath, source, dest);
+        } else {
+            renameDir(storage, storagePath, source, dest);
+        }
+    }
+
+    private void renameFile(IncrementalStorage storage, Path storagePath,
+            File source, File dest) throws IOException {
+        Path sourcePath = source.toPath();
+        Path destPath = dest.toPath();
+        if (!sourcePath.startsWith(storagePath)) {
+            throw new IOException("Path: " + source.getAbsolutePath() + " is not on storage at: "
+                    + storagePath.toString());
+        }
+        if (!destPath.startsWith(storagePath)) {
+            throw new IOException("Path: " + dest.getAbsolutePath() + " is not on storage at: "
+                    + storagePath.toString());
+        }
+        final Path sourceRelativePath = storagePath.relativize(sourcePath);
+        final Path destRelativePath = storagePath.relativize(destPath);
+        storage.moveFile(sourceRelativePath.toString(), destRelativePath.toString());
+
+    }
+
+    private void renameDir(IncrementalStorage storage, Path storagePath,
+            File source, File dest) throws IOException {
+        Path destPath = dest.toPath();
+        boolean usedMkdir = false;
+        try {
+            Os.mkdir(dest.getAbsolutePath(), 0755);
+            usedMkdir = true;
+        } catch (ErrnoException e) {
+            // Traditional mkdir fails but maybe we can create it on Incremental File System if
+            // the dest path is on the same Incremental storage as the source.
+            if (destPath.startsWith(storagePath)) {
+                storage.makeDirectories(storagePath.relativize(destPath).toString());
+            } else {
+                throw new IOException("Failed to create directory: " + dest.getAbsolutePath(), e);
+            }
+        }
+        try {
+            storage.moveDir(source.getAbsolutePath(), dest.getAbsolutePath());
+        } catch (Exception ex) {
+            if (usedMkdir) {
+                try {
+                    Os.remove(dest.getAbsolutePath());
+                } catch (ErrnoException ignored) {
+                }
+            }
+            throw new IOException(
+                    "Failed to move " + source.getAbsolutePath() + " to " + dest.getAbsolutePath());
+        }
+    }
+
+    /**
+     * Closes a storage specified by the absolute path. If the path is not Incremental, do nothing.
+     * Unbinds the target dir and deletes the corresponding storage instance.
+     */
+    public void closeStorage(@NonNull String path) {
+        try {
+            final int id = mService.openStorage(path);
+            if (id < 0) {
+                return;
+            }
+            mService.deleteStorage(id);
+            synchronized (mStorages) {
+                mStorages.remove(id);
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Checks if path is mounted on Incremental File System.
+     */
+    public static boolean isIncrementalPath(@NonNull String path) {
+        // TODO(b/136132412): implement native method
+        return false;
+    }
+}
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
new file mode 100644
index 0000000..2bf89ed
--- /dev/null
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -0,0 +1,346 @@
+/*
+ * 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.os.incremental;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.RemoteException;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Provides operations on an Incremental File System directory, using IncrementalService. Example
+ * usage:
+ *
+ * <blockquote><pre>
+ * IncrementalManager manager = (IncrementalManager) getSystemService(Context.INCREMENTAL_MANAGER);
+ * IncrementalStorage storage = manager.openStorage("/path/to/incremental/dir");
+ * storage.makeDirectory("subdir");
+ * </pre></blockquote>
+ *
+ * @hide
+ */
+public final class IncrementalStorage {
+    private static final String TAG = "IncrementalStorage";
+    private final int mId;
+    private final IIncrementalManager mService;
+
+
+    public IncrementalStorage(@NonNull IIncrementalManager is, int id) {
+        mService = is;
+        mId = id;
+    }
+
+    public int getId() {
+        return mId;
+    }
+
+    /**
+     * Temporarily bind-mounts the current storage directory to a target directory. The bind-mount
+     * will NOT be preserved between device reboots.
+     *
+     * @param targetPath Absolute path to the target directory.
+     */
+    public void bind(@NonNull String targetPath) throws IOException {
+        bind("", targetPath);
+    }
+
+    /**
+     * Temporarily bind-mounts a subdir under the current storage directory to a target directory.
+     * The bind-mount will NOT be preserved between device reboots.
+     *
+     * @param sourcePathUnderStorage Source path as a relative path under current storage
+     *                               directory.
+     * @param targetPath             Absolute path to the target directory.
+     */
+    public void bind(@NonNull String sourcePathUnderStorage, @NonNull String targetPath)
+            throws IOException {
+        try {
+            int res = mService.makeBindMount(mId, sourcePathUnderStorage, targetPath,
+                    IIncrementalManager.BIND_TEMPORARY);
+            if (res < 0) {
+                throw new IOException("bind() failed with errno " + -res);
+            }
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+
+    /**
+     * Permanently bind-mounts the current storage directory to a target directory. The bind-mount
+     * WILL be preserved between device reboots.
+     *
+     * @param targetPath Absolute path to the target directory.
+     */
+    public void bindPermanent(@NonNull String targetPath) throws IOException {
+        bindPermanent("", targetPath);
+    }
+
+    /**
+     * Permanently bind-mounts a subdir under the current storage directory to a target directory.
+     * The bind-mount WILL be preserved between device reboots.
+     *
+     * @param sourcePathUnderStorage Relative path under the current storage directory.
+     * @param targetPath             Absolute path to the target directory.
+     */
+    public void bindPermanent(@NonNull String sourcePathUnderStorage, @NonNull String targetPath)
+            throws IOException {
+        try {
+            int res = mService.makeBindMount(mId, sourcePathUnderStorage, targetPath,
+                    IIncrementalManager.BIND_PERMANENT);
+            if (res < 0) {
+                throw new IOException("bind() permanent failed with errno " + -res);
+            }
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Unbinds a bind mount.
+     *
+     * @param targetPath Absolute path to the target directory.
+     */
+    public void unBind(@NonNull String targetPath) throws IOException {
+        try {
+            int res = mService.deleteBindMount(mId, targetPath);
+            if (res < 0) {
+                throw new IOException("unbind() failed with errno " + -res);
+            }
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Creates a sub-directory under the current storage directory.
+     *
+     * @param pathUnderStorage Relative path of the sub-directory, e.g., "subdir"
+     */
+    public void makeDirectory(@NonNull String pathUnderStorage) throws IOException {
+        try {
+            int res = mService.makeDirectory(mId, pathUnderStorage);
+            if (res < 0) {
+                throw new IOException("makeDirectory() failed with errno " + -res);
+            }
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Creates a sub-directory under the current storage directory. If its parent dirs do not exist,
+     * create the parent dirs as well.
+     *
+     * @param pathUnderStorage Relative path of the sub-directory, e.g., "subdir/subsubdir"
+     */
+    public void makeDirectories(@NonNull String pathUnderStorage) throws IOException {
+        try {
+            int res = mService.makeDirectories(mId, pathUnderStorage);
+            if (res < 0) {
+                throw new IOException("makeDirectory() failed with errno " + -res);
+            }
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Creates a file under the current storage directory.
+     *
+     * @param pathUnderStorage Relative path of the new file.
+     * @param size             Size of the new file in bytes.
+     * @param metadata         Metadata bytes.
+     */
+    public void makeFile(@NonNull String pathUnderStorage, long size,
+            @Nullable byte[] metadata) throws IOException {
+        try {
+            int res = mService.makeFile(mId, pathUnderStorage, size, metadata);
+            if (res < 0) {
+                throw new IOException("makeFile() failed with errno " + -res);
+            }
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Creates a file in Incremental storage. The content of the file is mapped from a range inside
+     * a source file in the same storage.
+     *
+     * @param destRelativePath   Target relative path under storage.
+     * @param sourceRelativePath Source relative path under storage.
+     * @param rangeStart         Starting offset (in bytes) in the source file.
+     * @param rangeEnd           Ending offset (in bytes) in the source file.
+     */
+    public void makeFileFromRange(@NonNull String destRelativePath,
+            @NonNull String sourceRelativePath, long rangeStart, long rangeEnd) throws IOException {
+        try {
+            int res = mService.makeFileFromRange(mId, destRelativePath, sourceRelativePath,
+                    rangeStart, rangeEnd);
+            if (res < 0) {
+                throw new IOException("makeFileFromRange() failed, errno " + -res);
+            }
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Creates a hard-link between two paths, which can be under different storages but in the same
+     * Incremental File System.
+     *
+     * @param sourcePathUnderStorage The relative path of the source.
+     * @param destStorage            The target storage of the link target.
+     * @param destPathUnderStorage   The relative path of the target.
+     */
+    public void makeLink(@NonNull String sourcePathUnderStorage, IncrementalStorage destStorage,
+            @NonNull String destPathUnderStorage) throws IOException {
+        try {
+            int res = mService.makeLink(mId, sourcePathUnderStorage, destStorage.getId(),
+                    destPathUnderStorage);
+            if (res < 0) {
+                throw new IOException("makeLink() failed with errno " + -res);
+            }
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Deletes a hard-link under the current storage directory.
+     *
+     * @param pathUnderStorage The relative path of the target.
+     */
+    public void unlink(@NonNull String pathUnderStorage) throws IOException {
+        try {
+            int res = mService.unlink(mId, pathUnderStorage);
+            if (res < 0) {
+                throw new IOException("unlink() failed with errno " + -res);
+            }
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Rename an old file name to a new file name under the current storage directory.
+     *
+     * @param sourcePathUnderStorage Old file path as a relative path to the storage directory.
+     * @param destPathUnderStorage   New file path as a relative path to the storage directory.
+     */
+    public void moveFile(@NonNull String sourcePathUnderStorage,
+            @NonNull String destPathUnderStorage) throws IOException {
+        try {
+            int res = mService.makeLink(mId, sourcePathUnderStorage, mId, destPathUnderStorage);
+            if (res < 0) {
+                throw new IOException("moveFile() failed at makeLink(), errno " + -res);
+            }
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+        try {
+            mService.unlink(mId, sourcePathUnderStorage);
+        } catch (RemoteException ignored) {
+        }
+    }
+
+    /**
+     * Move a directory, which is bind-mounted to a given storage, to a new location. The bind mount
+     * will be persistent between reboots.
+     *
+     * @param sourcePath The old path of the directory as an absolute path.
+     * @param destPath   The new path of the directory as an absolute path, expected to already
+     *                   exist.
+     */
+    public void moveDir(@NonNull String sourcePath, @NonNull String destPath) throws IOException {
+        if (!new File(destPath).exists()) {
+            throw new IOException("moveDir() requires that destination dir already exists.");
+        }
+        try {
+            int res = mService.makeBindMount(mId, "", destPath, IIncrementalManager.BIND_PERMANENT);
+            if (res < 0) {
+                throw new IOException("moveDir() failed at making bind mount, errno " + -res);
+            }
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+        try {
+            mService.deleteBindMount(mId, sourcePath);
+        } catch (RemoteException ignored) {
+        }
+    }
+
+    /**
+     * Checks whether a file under the current storage directory is fully loaded.
+     *
+     * @param pathUnderStorage The relative path of the file.
+     * @return True if the file is fully loaded.
+     */
+    public boolean isFileFullyLoaded(@NonNull String pathUnderStorage) {
+        return isFileRangeLoaded(pathUnderStorage, 0, -1);
+    }
+
+    /**
+     * Checks whether a range in a file if loaded.
+     *
+     * @param pathUnderStorage The relative path of the file.
+     * @param start            The starting offset of the range.
+     * @param end              The ending offset of the range.
+     * @return True if the file is fully loaded.
+     */
+    public boolean isFileRangeLoaded(@NonNull String pathUnderStorage, long start, long end) {
+        try {
+            return mService.isFileRangeLoaded(mId, pathUnderStorage, start, end);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+            return false;
+        }
+    }
+
+    /**
+     * Returns the metadata object of an IncFs File.
+     *
+     * @param pathUnderStorage The relative path of the file.
+     * @return Byte array that contains metadata bytes.
+     */
+    @Nullable
+    public byte[] getFileMetadata(@NonNull String pathUnderStorage) {
+        try {
+            return mService.getFileMetadata(mId, pathUnderStorage);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+            return null;
+        }
+    }
+
+    /**
+     * Informs the data loader service associated with the current storage to start data loader
+     *
+     * @return True if data loader is successfully started.
+     */
+    public boolean startLoading() {
+        try {
+            return mService.startLoading(mId);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+            return false;
+        }
+    }
+}
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 6c4ee01..09286fe 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -17,6 +17,7 @@
 package android.permission;
 
 import android.Manifest;
+import android.annotation.CallbackExecutor;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -29,6 +30,8 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.permission.SplitPermissionInfoParcelable;
 import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.util.Slog;
 
 import com.android.internal.annotations.Immutable;
@@ -36,6 +39,8 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 /**
  * System level service for accessing the permission capabilities of the platform.
@@ -59,6 +64,8 @@
 
     private final IPackageManager mPackageManager;
 
+    private final IPermissionManager mPermissionManager;
+
     private List<SplitPermissionInfo> mSplitPermissionInfos;
 
     /**
@@ -67,9 +74,12 @@
      * @param context The current context in which to operate.
      * @hide
      */
-    public PermissionManager(@NonNull Context context, IPackageManager packageManager) {
+    public PermissionManager(@NonNull Context context, IPackageManager packageManager)
+            throws ServiceManager.ServiceNotFoundException {
         mContext = context;
         mPackageManager = packageManager;
+        mPermissionManager = IPermissionManager.Stub.asInterface(
+                ServiceManager.getServiceOrThrow("permissionmgr"));
     }
 
     /**
@@ -145,6 +155,48 @@
         return mSplitPermissionInfos;
     }
 
+    /**
+     * Grant default permissions to currently active LUI app
+     * @param packageName The package name for the LUI app
+     * @param user The user handle
+     * @param callback The callback provided by caller to be notified when grant completes
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS)
+    public void grantDefaultPermissionsToLuiApp(
+            @NonNull String packageName, @NonNull UserHandle user,
+            @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
+        try {
+            mPermissionManager.grantDefaultPermissionsToActiveLuiApp(
+                    packageName, user.getIdentifier());
+            executor.execute(() -> callback.accept(true));
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Revoke default permissions to currently active LUI app
+     * @param packageNames The package names for the LUI apps
+     * @param user The user handle
+     * @param callback The callback provided by caller to be notified when grant completes
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS)
+    public void revokeDefaultPermissionsFromLuiApps(
+            @NonNull String[] packageNames, @NonNull UserHandle user,
+            @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
+        try {
+            mPermissionManager.revokeDefaultPermissionsFromLuiApps(
+                    packageNames, user.getIdentifier());
+            executor.execute(() -> callback.accept(true));
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
     private List<SplitPermissionInfo> splitPermissionInfoListToNonParcelableList(
             List<SplitPermissionInfoParcelable> parcelableList) {
         final int size = parcelableList.size();
diff --git a/core/java/android/provider/BlockedNumberContract.java b/core/java/android/provider/BlockedNumberContract.java
index 7995f22..1eb7664 100644
--- a/core/java/android/provider/BlockedNumberContract.java
+++ b/core/java/android/provider/BlockedNumberContract.java
@@ -16,7 +16,6 @@
 package android.provider;
 
 import android.annotation.IntDef;
-import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.WorkerThread;
 import android.content.Context;
@@ -155,12 +154,7 @@
     /** The authority for the blocked number provider */
     public static final String AUTHORITY = "com.android.blockednumber";
 
-    /**
-     * A content:// style uri to the authority for the blocked number provider
-     * @hide
-     */
-    @NonNull
-    @SystemApi
+    /** A content:// style uri to the authority for the blocked number provider */
     public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
 
     private static final String LOG_TAG = BlockedNumberContract.class.getSimpleName();
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 01f9c73..2fa3386 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -20,12 +20,14 @@
 import android.annotation.CurrentTimeMillisLong;
 import android.annotation.CurrentTimeSecondsLong;
 import android.annotation.DurationMillisLong;
+import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
@@ -61,6 +63,7 @@
 import android.os.storage.StorageManager;
 import android.os.storage.StorageVolume;
 import android.os.storage.VolumeInfo;
+import android.os.storage.VolumeRecord;
 import android.service.media.CameraPrewarmService;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
@@ -78,6 +81,8 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.text.Collator;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -154,6 +159,8 @@
     public static final String SCAN_FILE_CALL = "scan_file";
     /** {@hide} */
     public static final String SCAN_VOLUME_CALL = "scan_volume";
+    /** {@hide} */
+    public static final String SUICIDE_CALL = "suicide";
 
     /**
      * Extra used with {@link #SCAN_FILE_CALL} or {@link #SCAN_VOLUME_CALL} to indicate that
@@ -205,8 +212,10 @@
     public static final String PARAM_DELETE_DATA = "deletedata";
 
     /** {@hide} */
+    @Deprecated
     public static final String PARAM_INCLUDE_PENDING = "includePending";
     /** {@hide} */
+    @Deprecated
     public static final String PARAM_INCLUDE_TRASHED = "includeTrashed";
     /** {@hide} */
     public static final String PARAM_PROGRESS = "progress";
@@ -559,6 +568,101 @@
     public static final String UNKNOWN_STRING = "<unknown>";
 
     /**
+     * Specify a {@link Uri} that is "related" to the current operation being
+     * performed.
+     * <p>
+     * This is typically used to allow an operation that may normally be
+     * rejected, such as making a copy of a pre-existing image located under a
+     * {@link MediaColumns#RELATIVE_PATH} where new images are not allowed.
+     * <p>
+     * It's strongly recommended that when making a copy of pre-existing content
+     * that you define the "original document ID" GUID as defined by the <em>XMP
+     * Media Management</em> standard.
+     * <p>
+     * This key can be placed in a {@link Bundle} of extras and passed to
+     * {@link ContentResolver#insert}.
+     */
+    public static final String QUERY_ARG_RELATED_URI = "android:query-arg-related-uri";
+
+    /**
+     * Specify how {@link MediaColumns#IS_PENDING} items should be filtered when
+     * performing a {@link MediaStore} operation.
+     * <p>
+     * This key can be placed in a {@link Bundle} of extras and passed to
+     * {@link ContentResolver#query}, {@link ContentResolver#update}, or
+     * {@link ContentResolver#delete}.
+     * <p>
+     * By default, pending items are filtered away from operations.
+     */
+    @Match
+    public static final String QUERY_ARG_MATCH_PENDING = "android:query-arg-match-pending";
+
+    /**
+     * Specify how {@link MediaColumns#IS_TRASHED} items should be filtered when
+     * performing a {@link MediaStore} operation.
+     * <p>
+     * This key can be placed in a {@link Bundle} of extras and passed to
+     * {@link ContentResolver#query}, {@link ContentResolver#update}, or
+     * {@link ContentResolver#delete}.
+     * <p>
+     * By default, trashed items are filtered away from operations.
+     */
+    @Match
+    public static final String QUERY_ARG_MATCH_TRASHED = "android:query-arg-match-trashed";
+
+    /**
+     * Specify how {@link MediaColumns#IS_FAVORITE} items should be filtered
+     * when performing a {@link MediaStore} operation.
+     * <p>
+     * This key can be placed in a {@link Bundle} of extras and passed to
+     * {@link ContentResolver#query}, {@link ContentResolver#update}, or
+     * {@link ContentResolver#delete}.
+     * <p>
+     * By default, favorite items are <em>not</em> filtered away from
+     * operations.
+     */
+    @Match
+    public static final String QUERY_ARG_MATCH_FAVORITE = "android:query-arg-match-favorite";
+
+    /** @hide */
+    @IntDef(flag = true, prefix = { "MATCH_" }, value = {
+            MATCH_DEFAULT,
+            MATCH_INCLUDE,
+            MATCH_EXCLUDE,
+            MATCH_ONLY,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Match {}
+
+    /**
+     * Value indicating that the default matching behavior should be used, as
+     * defined by the key documentation.
+     */
+    public static final int MATCH_DEFAULT = 0;
+
+    /**
+     * Value indicating that operations should include items matching the
+     * criteria defined by this key.
+     * <p>
+     * Note that items <em>not</em> matching the criteria <em>may</em> also be
+     * included depending on the default behavior documented by the key. If you
+     * want to operate exclusively on matching items, use {@link #MATCH_ONLY}.
+     */
+    public static final int MATCH_INCLUDE = 1;
+
+    /**
+     * Value indicating that operations should exclude items matching the
+     * criteria defined by this key.
+     */
+    public static final int MATCH_EXCLUDE = 2;
+
+    /**
+     * Value indicating that operations should only operate on items explicitly
+     * matching the criteria defined by this key.
+     */
+    public static final int MATCH_ONLY = 3;
+
+    /**
      * Update the given {@link Uri} to also include any pending media items from
      * calls such as
      * {@link ContentResolver#query(Uri, String[], Bundle, CancellationSignal)}.
@@ -566,12 +670,16 @@
      *
      * @see MediaColumns#IS_PENDING
      * @see MediaStore#getIncludePending(Uri)
+     * @deprecated consider migrating to {@link #QUERY_ARG_MATCH_PENDING} which
+     *             is more expressive.
      */
+    @Deprecated
     public static @NonNull Uri setIncludePending(@NonNull Uri uri) {
         return setIncludePending(uri.buildUpon()).build();
     }
 
     /** @hide */
+    @Deprecated
     public static @NonNull Uri.Builder setIncludePending(@NonNull Uri.Builder uriBuilder) {
         return uriBuilder.appendQueryParameter(PARAM_INCLUDE_PENDING, "1");
     }
@@ -582,7 +690,11 @@
      *
      * @see MediaColumns#IS_PENDING
      * @see MediaStore#setIncludePending(Uri)
+     * @deprecated consider migrating to {@link #QUERY_ARG_MATCH_PENDING} which
+     *             is more expressive.
+     * @removed
      */
+    @Deprecated
     public static boolean getIncludePending(@NonNull Uri uri) {
         return parseBoolean(uri.getQueryParameter(MediaStore.PARAM_INCLUDE_PENDING));
     }
@@ -597,7 +709,11 @@
      * @see MediaStore#setIncludeTrashed(Uri)
      * @see MediaStore#trash(Context, Uri)
      * @see MediaStore#untrash(Context, Uri)
+     * @deprecated consider migrating to {@link #QUERY_ARG_MATCH_TRASHED} which
+     *             is more expressive.
+     * @removed
      */
+    @Deprecated
     public static @NonNull Uri setIncludeTrashed(@NonNull Uri uri) {
         return uri.buildUpon().appendQueryParameter(PARAM_INCLUDE_TRASHED, "1").build();
     }
@@ -1000,7 +1116,7 @@
          * the field to {@code 0}, or until they expire as defined by
          * {@link #DATE_EXPIRES}.
          *
-         * @see MediaStore#setIncludePending(Uri)
+         * @see MediaStore#QUERY_ARG_MATCH_PENDING
          */
         @Column(Cursor.FIELD_TYPE_INTEGER)
         public static final String IS_PENDING = "is_pending";
@@ -1011,8 +1127,7 @@
          * Trashed items are retained until they expire as defined by
          * {@link #DATE_EXPIRES}.
          *
-         * @see MediaColumns#IS_TRASHED
-         * @see MediaStore#setIncludeTrashed(Uri)
+         * @see MediaStore#QUERY_ARG_MATCH_TRASHED
          * @see MediaStore#trash(Context, Uri)
          * @see MediaStore#untrash(Context, Uri)
          */
@@ -1186,6 +1301,8 @@
         /**
          * Flag indicating if the media item has been marked as being a
          * "favorite" by the user.
+         *
+         * @see MediaStore#QUERY_ARG_MATCH_FAVORITE
          */
         @Column(Cursor.FIELD_TYPE_INTEGER)
         public static final String IS_FAVORITE = "is_favorite";
@@ -1477,31 +1594,41 @@
 
             /**
              * Constant for the {@link #MEDIA_TYPE} column indicating that file
-             * is not an audio, image, video or playlist file.
+             * is not an audio, image, video, playlist, or subtitles file.
              */
             public static final int MEDIA_TYPE_NONE = 0;
 
             /**
-             * Constant for the {@link #MEDIA_TYPE} column indicating that file is an image file.
+             * Constant for the {@link #MEDIA_TYPE} column indicating that file
+             * is an image file.
              */
             public static final int MEDIA_TYPE_IMAGE = 1;
 
             /**
-             * Constant for the {@link #MEDIA_TYPE} column indicating that file is an audio file.
+             * Constant for the {@link #MEDIA_TYPE} column indicating that file
+             * is an audio file.
              */
             public static final int MEDIA_TYPE_AUDIO = 2;
 
             /**
-             * Constant for the {@link #MEDIA_TYPE} column indicating that file is a video file.
+             * Constant for the {@link #MEDIA_TYPE} column indicating that file
+             * is a video file.
              */
             public static final int MEDIA_TYPE_VIDEO = 3;
 
             /**
-             * Constant for the {@link #MEDIA_TYPE} column indicating that file is a playlist file.
+             * Constant for the {@link #MEDIA_TYPE} column indicating that file
+             * is a playlist file.
              */
             public static final int MEDIA_TYPE_PLAYLIST = 4;
 
             /**
+             * Constant for the {@link #MEDIA_TYPE} column indicating that file
+             * is a subtitles or lyrics file.
+             */
+            public static final int MEDIA_TYPE_SUBTITLE = 5;
+
+            /**
              * Column indicating if the file is part of Downloads collection.
              * @hide
              */
@@ -3490,6 +3617,43 @@
     }
 
     /**
+     * Return list of all specific volume names that have recently been part of
+     * {@link #VOLUME_EXTERNAL}.
+     * <p>
+     * This includes both currently mounted volumes <em>and</em> recently
+     * mounted (but currently unmounted) volumes. Any indexed metadata for these
+     * volumes is preserved to optimize the speed of remounting at a later time.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE)
+    public static @NonNull Set<String> getRecentExternalVolumeNames(@NonNull Context context) {
+        final StorageManager sm = context.getSystemService(StorageManager.class);
+
+        // We always have primary storage
+        final Set<String> volumeNames = new ArraySet<>();
+        volumeNames.add(VOLUME_EXTERNAL_PRIMARY);
+
+        final long lastWeek = System.currentTimeMillis() - DateUtils.WEEK_IN_MILLIS;
+        for (VolumeRecord rec : sm.getVolumeRecords()) {
+            // Skip volumes without valid UUIDs
+            if (TextUtils.isEmpty(rec.fsUuid)) continue;
+
+            final VolumeInfo vi = sm.findVolumeByUuid(rec.fsUuid);
+            if (vi != null && vi.isVisibleForUser(UserHandle.myUserId())
+                    && vi.isMountedReadable()) {
+                // We're mounted right now
+                volumeNames.add(rec.getNormalizedFsUuid());
+            } else if (rec.lastSeenMillis > 0 && rec.lastSeenMillis < lastWeek) {
+                // We're not mounted right now, but we've been seen recently
+                volumeNames.add(rec.getNormalizedFsUuid());
+            }
+        }
+        return volumeNames;
+    }
+
+    /**
      * Return the volume name that the given {@link Uri} references.
      */
     public static @NonNull String getVolumeName(@NonNull Uri uri) {
@@ -3588,6 +3752,8 @@
      * @hide
      */
     @TestApi
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE)
     public static @NonNull Collection<File> getVolumeScanPaths(@NonNull String volumeName)
             throws FileNotFoundException {
         if (TextUtils.isEmpty(volumeName)) {
@@ -3816,6 +3982,16 @@
     }
 
     /** @hide */
+    public static void suicide(Context context) {
+        final ContentResolver resolver = context.getContentResolver();
+        try (ContentProviderClient client = resolver
+                .acquireUnstableContentProviderClient(AUTHORITY)) {
+            client.call(SUICIDE_CALL, null, null);
+        } catch (Exception ignored) {
+        }
+    }
+
+    /** @hide */
     @TestApi
     public static Uri scanFile(Context context, File file) {
         return scan(context, SCAN_FILE_CALL, file, false);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index cc4ed4b..ad8d553 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -89,7 +89,6 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 
@@ -833,8 +832,7 @@
     /**
      * Activity Action: Show screen for controlling which apps can draw on top of other apps.
      * <p>
-     * In some cases, a matching Activity may not exist, so ensure you
-     * safeguard against this.
+     * In some cases, a matching Activity may not exist, so ensure you safeguard against this.
      * <p>
      * Input: Optionally, in versions of Android prior to 11, the Intent's data URI can specify the
      * application package name to directly invoke the management GUI specific to the package name.
@@ -847,6 +845,31 @@
             "android.settings.action.MANAGE_OVERLAY_PERMISSION";
 
     /**
+     * Activity Action: Show screen for controlling if the app specified in the data URI of the
+     * intent can draw on top of other apps.
+     * <p>
+     * Unlike {@link #ACTION_MANAGE_OVERLAY_PERMISSION}, which in Android 11 can't be used to show
+     * a GUI for a specific package, permission {@code android.permission.INTERNAL_SYSTEM_WINDOW} is
+     * needed to start an activity with this intent.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: The Intent's data URI MUST specify the application package name whose ability of
+     * drawing on top of other apps you want to control.
+     * For example "package:com.my.app".
+     * <p>
+     * Output: Nothing.
+     *
+     * @hide
+     */
+    @TestApi
+    @SystemApi
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_MANAGE_APP_OVERLAY_PERMISSION =
+            "android.settings.MANAGE_APP_OVERLAY_PERMISSION";
+
+    /**
      * Activity Action: Show screen for controlling which apps are allowed to write/modify
      * system settings.
      * <p>
@@ -4953,7 +4976,6 @@
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_P2P_PENDING_FACTORY_RESET);
             MOVED_TO_GLOBAL.add(Settings.Global.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON);
-            MOVED_TO_GLOBAL.add(Settings.Global.PACKAGE_VERIFIER_ENABLE);
             MOVED_TO_GLOBAL.add(Settings.Global.PACKAGE_VERIFIER_TIMEOUT);
             MOVED_TO_GLOBAL.add(Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE);
             MOVED_TO_GLOBAL.add(Settings.Global.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS);
@@ -8168,6 +8190,15 @@
         public static final String NOTIFICATION_BADGING = "notification_badging";
 
         /**
+         * When enabled the system will maintain a rolling history of received notifications. When
+         * disabled the history will be disabled and deleted.
+         *
+         * The value 1 - enable, 0 - disable
+         * @hide
+         */
+        public static final String NOTIFICATION_HISTORY_ENABLED = "notification_history_enabled";
+
+        /**
          * Whether notifications are dismissed by a right-to-left swipe (instead of a left-to-right
          * swipe).
          *
@@ -8751,6 +8782,22 @@
         public static final String BUGREPORT_IN_POWER_MENU = "bugreport_in_power_menu";
 
         /**
+         * The package name for the custom bugreport handler app. This app must be whitelisted.
+         * This is currently used only by Power Menu short press.
+         *
+         * @hide
+         */
+        public static final String CUSTOM_BUGREPORT_HANDLER_APP = "custom_bugreport_handler_app";
+
+        /**
+         * The user id for the custom bugreport handler app. This is currently used only by Power
+         * Menu short press.
+         *
+         * @hide
+         */
+        public static final String CUSTOM_BUGREPORT_HANDLER_USER = "custom_bugreport_handler_user";
+
+        /**
          * Whether ADB is enabled.
          */
         public static final String ADB_ENABLED = "adb_enabled";
@@ -8887,14 +8934,33 @@
          * List of ISO country codes in which eUICC UI is shown. Country codes should be separated
          * by comma.
          *
-         * <p>Used to hide eUICC UI from users who are currently in countries no carriers support
-         * eUICC.
+         * Note: if {@link #EUICC_SUPPORTED_COUNTRIES} is empty, then {@link
+         * #EUICC_UNSUPPORTED_COUNTRIES} is used.
+         *
+         * <p>Used to hide eUICC UI from users who are currently in countries where no carriers
+         * support eUICC.
+         *
          * @hide
          */
-        //TODO(b/77914569) Changes this to System Api.
+        @SystemApi
         public static final String EUICC_SUPPORTED_COUNTRIES = "euicc_supported_countries";
 
         /**
+         * List of ISO country codes in which eUICC UI is not shown. Country codes should be
+         * separated by comma.
+         *
+         * Note: if {@link #EUICC_SUPPORTED_COUNTRIES} is empty, then {@link
+         * #EUICC_UNSUPPORTED_COUNTRIES} is used.
+         *
+         * <p>Used to hide eUICC UI from users who are currently in countries where no carriers
+         * support eUICC.
+         *
+         * @hide
+         */
+        @SystemApi
+        public static final String EUICC_UNSUPPORTED_COUNTRIES = "euicc_unsupported_countries";
+
+        /**
          * Whether any activity can be resized. When this is true, any
          * activity, regardless of manifest values, can be resized for multi-window.
          * (0 = false, 1 = true)
@@ -9275,16 +9341,6 @@
        @SystemApi
        public static final String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update";
 
-       /**
-        * Whether the package manager should send package verification broadcasts for verifiers to
-        * review apps prior to installation.
-        * 1 = request apps to be verified prior to installation, if a verifier exists.
-        * 0 = do not verify apps before installation
-        * @hide
-        */
-       @UnsupportedAppUsage
-       public static final String PACKAGE_VERIFIER_ENABLE = "package_verifier_enable";
-
        /** Timeout for package verification.
         * @hide */
        public static final String PACKAGE_VERIFIER_TIMEOUT = "verifier_timeout";
@@ -10637,6 +10693,7 @@
         /** {@hide} */
         public static final String
                 BLUETOOTH_HEARING_AID_PRIORITY_PREFIX = "bluetooth_hearing_aid_priority_";
+
         /**
          * Enable/disable radio bug detection
          *
@@ -11454,105 +11511,6 @@
                 "adb_allowed_connection_time";
 
         /**
-         * Get the key that retrieves a bluetooth headset's priority.
-         * @hide
-         */
-        public static final String getBluetoothHeadsetPriorityKey(String address) {
-            return BLUETOOTH_HEADSET_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
-        }
-
-        /**
-         * Get the key that retrieves a bluetooth a2dp sink's priority.
-         * @hide
-         */
-        public static final String getBluetoothA2dpSinkPriorityKey(String address) {
-            return BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
-        }
-
-        /**
-         * Get the key that retrieves a bluetooth a2dp src's priority.
-         * @hide
-         */
-        public static final String getBluetoothA2dpSrcPriorityKey(String address) {
-            return BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
-        }
-
-        /**
-         * Get the key that retrieves a bluetooth a2dp device's ability to support optional codecs.
-         * @hide
-         */
-        public static final String getBluetoothA2dpSupportsOptionalCodecsKey(String address) {
-            return BLUETOOTH_A2DP_SUPPORTS_OPTIONAL_CODECS_PREFIX +
-                    address.toUpperCase(Locale.ROOT);
-        }
-
-        /**
-         * Get the key that retrieves whether a bluetooth a2dp device should have optional codecs
-         * enabled.
-         * @hide
-         */
-        public static final String getBluetoothA2dpOptionalCodecsEnabledKey(String address) {
-            return BLUETOOTH_A2DP_OPTIONAL_CODECS_ENABLED_PREFIX +
-                    address.toUpperCase(Locale.ROOT);
-        }
-
-        /**
-         * Get the key that retrieves a bluetooth Input Device's priority.
-         * @hide
-         */
-        public static final String getBluetoothHidHostPriorityKey(String address) {
-            return BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
-        }
-
-        /**
-         * Get the key that retrieves a bluetooth pan client priority.
-         * @hide
-         */
-        public static final String getBluetoothPanPriorityKey(String address) {
-            return BLUETOOTH_PAN_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
-        }
-
-        /**
-         * Get the key that retrieves a bluetooth hearing aid priority.
-         * @hide
-         */
-        public static final String getBluetoothHearingAidPriorityKey(String address) {
-            return BLUETOOTH_HEARING_AID_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
-        }
-
-        /**
-         * Get the key that retrieves a bluetooth map priority.
-         * @hide
-         */
-        public static final String getBluetoothMapPriorityKey(String address) {
-            return BLUETOOTH_MAP_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
-        }
-
-        /**
-         * Get the key that retrieves a bluetooth map client priority.
-         * @hide
-         */
-        public static final String getBluetoothMapClientPriorityKey(String address) {
-            return BLUETOOTH_MAP_CLIENT_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
-        }
-
-        /**
-         * Get the key that retrieves a bluetooth pbap client priority.
-         * @hide
-         */
-        public static final String getBluetoothPbapClientPriorityKey(String address) {
-            return BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
-        }
-
-        /**
-         * Get the key that retrieves a bluetooth sap priority.
-         * @hide
-         */
-        public static final String getBluetoothSapPriorityKey(String address) {
-            return BLUETOOTH_SAP_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
-        }
-
-        /**
          * Scaling factor for normal window animations. Setting to 0 will
          * disable window animations.
          */
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
new file mode 100644
index 0000000..70c8e5d
--- /dev/null
+++ b/core/java/android/provider/Telephony.java
@@ -0,0 +1,4859 @@
+/*
+ * Copyright (C) 2006 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.provider;
+
+import android.Manifest;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.annotation.UnsupportedAppUsage;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.database.sqlite.SqliteWrapper;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Parcel;
+import android.telephony.Rlog;
+import android.telephony.ServiceState;
+import android.telephony.SmsMessage;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Patterns;
+
+import com.android.internal.telephony.SmsApplication;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * The Telephony provider contains data related to phone operation, specifically SMS and MMS
+ * messages, access to the APN list, including the MMSC to use, and the service state.
+ *
+ * <p class="note"><strong>Note:</strong> These APIs are not available on all Android-powered
+ * devices. If your app depends on telephony features such as for managing SMS messages, include
+ * a <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code <uses-feature>}
+ * </a> element in your manifest that declares the {@code "android.hardware.telephony"} hardware
+ * feature. Alternatively, you can check for telephony availability at runtime using either
+ * {@link android.content.pm.PackageManager#hasSystemFeature
+ * hasSystemFeature(PackageManager.FEATURE_TELEPHONY)} or {@link
+ * android.telephony.TelephonyManager#getPhoneType}.</p>
+ *
+ * <h3>Creating an SMS app</h3>
+ *
+ * <p>Only the default SMS app (selected by the user in system settings) is able to write to the
+ * SMS Provider (the tables defined within the {@code Telephony} class) and only the default SMS
+ * app receives the {@link android.provider.Telephony.Sms.Intents#SMS_DELIVER_ACTION} broadcast
+ * when the user receives an SMS or the {@link
+ * android.provider.Telephony.Sms.Intents#WAP_PUSH_DELIVER_ACTION} broadcast when the user
+ * receives an MMS.</p>
+ *
+ * <p>Any app that wants to behave as the user's default SMS app must handle the following intents:
+ * <ul>
+ * <li>In a broadcast receiver, include an intent filter for {@link Sms.Intents#SMS_DELIVER_ACTION}
+ * (<code>"android.provider.Telephony.SMS_DELIVER"</code>). The broadcast receiver must also
+ * require the {@link android.Manifest.permission#BROADCAST_SMS} permission.
+ * <p>This allows your app to directly receive incoming SMS messages.</p></li>
+ * <li>In a broadcast receiver, include an intent filter for {@link
+ * Sms.Intents#WAP_PUSH_DELIVER_ACTION}} ({@code "android.provider.Telephony.WAP_PUSH_DELIVER"})
+ * with the MIME type <code>"application/vnd.wap.mms-message"</code>.
+ * The broadcast receiver must also require the {@link
+ * android.Manifest.permission#BROADCAST_WAP_PUSH} permission.
+ * <p>This allows your app to directly receive incoming MMS messages.</p></li>
+ * <li>In your activity that delivers new messages, include an intent filter for
+ * {@link android.content.Intent#ACTION_SENDTO} (<code>"android.intent.action.SENDTO"
+ * </code>) with schemas, <code>sms:</code>, <code>smsto:</code>, <code>mms:</code>, and
+ * <code>mmsto:</code>.
+ * <p>This allows your app to receive intents from other apps that want to deliver a
+ * message.</p></li>
+ * <li>In a service, include an intent filter for {@link
+ * android.telephony.TelephonyManager#ACTION_RESPOND_VIA_MESSAGE}
+ * (<code>"android.intent.action.RESPOND_VIA_MESSAGE"</code>) with schemas,
+ * <code>sms:</code>, <code>smsto:</code>, <code>mms:</code>, and <code>mmsto:</code>.
+ * This service must also require the {@link
+ * android.Manifest.permission#SEND_RESPOND_VIA_MESSAGE} permission.
+ * <p>This allows users to respond to incoming phone calls with an immediate text message
+ * using your app.</p></li>
+ * </ul>
+ *
+ * <p>Other apps that are not selected as the default SMS app can only <em>read</em> the SMS
+ * Provider, but may also be notified when a new SMS arrives by listening for the {@link
+ * Sms.Intents#SMS_RECEIVED_ACTION}
+ * broadcast, which is a non-abortable broadcast that may be delivered to multiple apps. This
+ * broadcast is intended for apps that&mdash;while not selected as the default SMS app&mdash;need to
+ * read special incoming messages such as to perform phone number verification.</p>
+ *
+ * <p>For more information about building SMS apps, read the blog post, <a
+ * href="http://android-developers.blogspot.com/2013/10/getting-your-sms-apps-ready-for-kitkat.html"
+ * >Getting Your SMS Apps Ready for KitKat</a>.</p>
+ *
+ */
+public final class Telephony {
+    private static final String TAG = "Telephony";
+
+    /**
+     * Not instantiable.
+     * @hide
+     */
+    private Telephony() {
+    }
+
+    /**
+     * Base columns for tables that contain text-based SMSs.
+     */
+    public interface TextBasedSmsColumns {
+
+        /** Message type: all messages. */
+        public static final int MESSAGE_TYPE_ALL    = 0;
+
+        /** Message type: inbox. */
+        public static final int MESSAGE_TYPE_INBOX  = 1;
+
+        /** Message type: sent messages. */
+        public static final int MESSAGE_TYPE_SENT   = 2;
+
+        /** Message type: drafts. */
+        public static final int MESSAGE_TYPE_DRAFT  = 3;
+
+        /** Message type: outbox. */
+        public static final int MESSAGE_TYPE_OUTBOX = 4;
+
+        /** Message type: failed outgoing message. */
+        public static final int MESSAGE_TYPE_FAILED = 5;
+
+        /** Message type: queued to send later. */
+        public static final int MESSAGE_TYPE_QUEUED = 6;
+
+        /**
+         * The type of message.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String TYPE = "type";
+
+        /**
+         * The thread ID of the message.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String THREAD_ID = "thread_id";
+
+        /**
+         * The address of the other party.
+         * <P>Type: TEXT</P>
+         */
+        public static final String ADDRESS = "address";
+
+        /**
+         * The date the message was received.
+         * <P>Type: INTEGER (long)</P>
+         */
+        public static final String DATE = "date";
+
+        /**
+         * The date the message was sent.
+         * <P>Type: INTEGER (long)</P>
+         */
+        public static final String DATE_SENT = "date_sent";
+
+        /**
+         * Has the message been read?
+         * <P>Type: INTEGER (boolean)</P>
+         */
+        public static final String READ = "read";
+
+        /**
+         * Has the message been seen by the user? The "seen" flag determines
+         * whether we need to show a notification.
+         * <P>Type: INTEGER (boolean)</P>
+         */
+        public static final String SEEN = "seen";
+
+        /**
+         * {@code TP-Status} value for the message, or -1 if no status has been received.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String STATUS = "status";
+
+        /** TP-Status: no status received. */
+        public static final int STATUS_NONE = -1;
+        /** TP-Status: complete. */
+        public static final int STATUS_COMPLETE = 0;
+        /** TP-Status: pending. */
+        public static final int STATUS_PENDING = 32;
+        /** TP-Status: failed. */
+        public static final int STATUS_FAILED = 64;
+
+        /**
+         * The subject of the message, if present.
+         * <P>Type: TEXT</P>
+         */
+        public static final String SUBJECT = "subject";
+
+        /**
+         * The body of the message.
+         * <P>Type: TEXT</P>
+         */
+        public static final String BODY = "body";
+
+        /**
+         * The ID of the sender of the conversation, if present.
+         * <P>Type: INTEGER (reference to item in {@code content://contacts/people})</P>
+         */
+        public static final String PERSON = "person";
+
+        /**
+         * The protocol identifier code.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String PROTOCOL = "protocol";
+
+        /**
+         * Is the {@code TP-Reply-Path} flag set?
+         * <P>Type: BOOLEAN</P>
+         */
+        public static final String REPLY_PATH_PRESENT = "reply_path_present";
+
+        /**
+         * The service center (SC) through which to send the message, if present.
+         * <P>Type: TEXT</P>
+         */
+        public static final String SERVICE_CENTER = "service_center";
+
+        /**
+         * Is the message locked?
+         * <P>Type: INTEGER (boolean)</P>
+         */
+        public static final String LOCKED = "locked";
+
+        /**
+         * The subscription to which the message belongs to. Its value will be
+         * < 0 if the sub id cannot be determined.
+         * <p>Type: INTEGER (long) </p>
+         */
+        public static final String SUBSCRIPTION_ID = "sub_id";
+
+        /**
+         * The MTU size of the mobile interface to which the APN connected
+         * @hide
+         */
+        public static final String MTU = "mtu";
+
+        /**
+         * Error code associated with sending or receiving this message
+         * <P>Type: INTEGER</P>
+         */
+        public static final String ERROR_CODE = "error_code";
+
+        /**
+         * The identity of the sender of a sent message. It is
+         * usually the package name of the app which sends the message.
+         * <p class="note"><strong>Note:</strong>
+         * This column is read-only. It is set by the provider and can not be changed by apps.
+         * <p>Type: TEXT</p>
+         */
+        public static final String CREATOR = "creator";
+    }
+
+    /**
+     * Columns in sms_changes table.
+     * @hide
+     */
+    public interface TextBasedSmsChangesColumns {
+        /**
+         * The {@code content://} style URL for this table.
+         * @hide
+         */
+        public static final Uri CONTENT_URI = Uri.parse("content://sms-changes");
+
+        /**
+         * Primary key.
+         * <P>Type: INTEGER (long)</P>
+         * @hide
+         */
+        public static final String ID = "_id";
+
+        /**
+         * Triggers on sms table create a row in this table for each update/delete.
+         * This column is the "_id" of the row from sms table that was updated/deleted.
+         * <P>Type: INTEGER (long)</P>
+         * @hide
+         */
+        public static final String ORIG_ROW_ID = "orig_rowid";
+
+        /**
+         * Triggers on sms table create a row in this table for each update/delete.
+         * This column is the "sub_id" of the row from sms table that was updated/deleted.
+         * @hide
+         * <P>Type: INTEGER (long)</P>
+         */
+        public static final String SUB_ID = "sub_id";
+
+        /**
+         * The type of operation that created this row.
+         *    {@link #TYPE_UPDATE} = update op
+         *    {@link #TYPE_DELETE} = delete op
+         * @hide
+         * <P>Type: INTEGER (long)</P>
+         */
+        public static final String TYPE = "type";
+
+        /**
+         * One of the possible values for the above column "type". Indicates it is an update op.
+         * @hide
+         */
+        public static final int TYPE_UPDATE = 0;
+
+        /**
+         * One of the possible values for the above column "type". Indicates it is a delete op.
+         * @hide
+         */
+        public static final int TYPE_DELETE = 1;
+
+        /**
+         * This column contains a non-null value only if the operation on sms table is an update op
+         * and the column "read" is changed by the update op.
+         * <P>Type: INTEGER (boolean)</P>
+         * @hide
+         */
+        public static final String NEW_READ_STATUS = "new_read_status";
+    }
+
+    /**
+     * Contains all text-based SMS messages.
+     */
+    public static final class Sms implements BaseColumns, TextBasedSmsColumns {
+
+        /**
+         * Not instantiable.
+         * @hide
+         */
+        private Sms() {
+        }
+
+        /**
+         * Used to determine the currently configured default SMS package.
+         * @param context context of the requesting application
+         * @return package name for the default SMS package or null
+         */
+        public static String getDefaultSmsPackage(Context context) {
+            ComponentName component = SmsApplication.getDefaultSmsApplication(context, false);
+            if (component != null) {
+                return component.getPackageName();
+            }
+            return null;
+        }
+
+        /**
+         * Return cursor for table query.
+         * @hide
+         */
+        public static Cursor query(ContentResolver cr, String[] projection) {
+            return cr.query(CONTENT_URI, projection, null, null, DEFAULT_SORT_ORDER);
+        }
+
+        /**
+         * Return cursor for table query.
+         * @hide
+         */
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+        public static Cursor query(ContentResolver cr, String[] projection,
+                String where, String orderBy) {
+            return cr.query(CONTENT_URI, projection, where,
+                    null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
+        }
+
+        /**
+         * The {@code content://} style URL for this table.
+         */
+        public static final Uri CONTENT_URI = Uri.parse("content://sms");
+
+        /**
+         * The default sort order for this table.
+         */
+        public static final String DEFAULT_SORT_ORDER = "date DESC";
+
+        /**
+         * Add an SMS to the given URI.
+         *
+         * @param resolver the content resolver to use
+         * @param uri the URI to add the message to
+         * @param address the address of the sender
+         * @param body the body of the message
+         * @param subject the pseudo-subject of the message
+         * @param date the timestamp for the message
+         * @param read true if the message has been read, false if not
+         * @param deliveryReport true if a delivery report was requested, false if not
+         * @return the URI for the new message
+         * @hide
+         */
+        @UnsupportedAppUsage
+        public static Uri addMessageToUri(ContentResolver resolver,
+                Uri uri, String address, String body, String subject,
+                Long date, boolean read, boolean deliveryReport) {
+            return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
+                    resolver, uri, address, body, subject, date, read, deliveryReport, -1L);
+        }
+
+        /**
+         * Add an SMS to the given URI.
+         *
+         * @param resolver the content resolver to use
+         * @param uri the URI to add the message to
+         * @param address the address of the sender
+         * @param body the body of the message
+         * @param subject the psuedo-subject of the message
+         * @param date the timestamp for the message
+         * @param read true if the message has been read, false if not
+         * @param deliveryReport true if a delivery report was requested, false if not
+         * @param subId the subscription which the message belongs to
+         * @return the URI for the new message
+         * @hide
+         */
+        @UnsupportedAppUsage
+        public static Uri addMessageToUri(int subId, ContentResolver resolver,
+                Uri uri, String address, String body, String subject,
+                Long date, boolean read, boolean deliveryReport) {
+            return addMessageToUri(subId, resolver, uri, address, body, subject,
+                    date, read, deliveryReport, -1L);
+        }
+
+        /**
+         * Add an SMS to the given URI with the specified thread ID.
+         *
+         * @param resolver the content resolver to use
+         * @param uri the URI to add the message to
+         * @param address the address of the sender
+         * @param body the body of the message
+         * @param subject the pseudo-subject of the message
+         * @param date the timestamp for the message
+         * @param read true if the message has been read, false if not
+         * @param deliveryReport true if a delivery report was requested, false if not
+         * @param threadId the thread_id of the message
+         * @return the URI for the new message
+         * @hide
+         */
+        @UnsupportedAppUsage
+        public static Uri addMessageToUri(ContentResolver resolver,
+                Uri uri, String address, String body, String subject,
+                Long date, boolean read, boolean deliveryReport, long threadId) {
+            return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
+                    resolver, uri, address, body, subject,
+                    date, read, deliveryReport, threadId);
+        }
+
+        /**
+         * Add an SMS to the given URI with thread_id specified.
+         *
+         * @param resolver the content resolver to use
+         * @param uri the URI to add the message to
+         * @param address the address of the sender
+         * @param body the body of the message
+         * @param subject the psuedo-subject of the message
+         * @param date the timestamp for the message
+         * @param read true if the message has been read, false if not
+         * @param deliveryReport true if a delivery report was requested, false if not
+         * @param threadId the thread_id of the message
+         * @param subId the subscription which the message belongs to
+         * @return the URI for the new message
+         * @hide
+         */
+        @UnsupportedAppUsage
+        public static Uri addMessageToUri(int subId, ContentResolver resolver,
+                Uri uri, String address, String body, String subject,
+                Long date, boolean read, boolean deliveryReport, long threadId) {
+            ContentValues values = new ContentValues(8);
+            Rlog.v(TAG,"Telephony addMessageToUri sub id: " + subId);
+
+            values.put(SUBSCRIPTION_ID, subId);
+            values.put(ADDRESS, address);
+            if (date != null) {
+                values.put(DATE, date);
+            }
+            values.put(READ, read ? Integer.valueOf(1) : Integer.valueOf(0));
+            values.put(SUBJECT, subject);
+            values.put(BODY, body);
+            if (deliveryReport) {
+                values.put(STATUS, STATUS_PENDING);
+            }
+            if (threadId != -1L) {
+                values.put(THREAD_ID, threadId);
+            }
+            return resolver.insert(uri, values);
+        }
+
+        /**
+         * Move a message to the given folder.
+         *
+         * @param context the context to use
+         * @param uri the message to move
+         * @param folder the folder to move to
+         * @return true if the operation succeeded
+         * @hide
+         */
+        @UnsupportedAppUsage
+        public static boolean moveMessageToFolder(Context context,
+                Uri uri, int folder, int error) {
+            if (uri == null) {
+                return false;
+            }
+
+            boolean markAsUnread = false;
+            boolean markAsRead = false;
+            switch(folder) {
+            case MESSAGE_TYPE_INBOX:
+            case MESSAGE_TYPE_DRAFT:
+                break;
+            case MESSAGE_TYPE_OUTBOX:
+            case MESSAGE_TYPE_SENT:
+                markAsRead = true;
+                break;
+            case MESSAGE_TYPE_FAILED:
+            case MESSAGE_TYPE_QUEUED:
+                markAsUnread = true;
+                break;
+            default:
+                return false;
+            }
+
+            ContentValues values = new ContentValues(3);
+
+            values.put(TYPE, folder);
+            if (markAsUnread) {
+                values.put(READ, 0);
+            } else if (markAsRead) {
+                values.put(READ, 1);
+            }
+            values.put(ERROR_CODE, error);
+
+            return 1 == SqliteWrapper.update(context, context.getContentResolver(),
+                            uri, values, null, null);
+        }
+
+        /**
+         * Returns true iff the folder (message type) identifies an
+         * outgoing message.
+         * @hide
+         */
+        @UnsupportedAppUsage
+        public static boolean isOutgoingFolder(int messageType) {
+            return  (messageType == MESSAGE_TYPE_FAILED)
+                    || (messageType == MESSAGE_TYPE_OUTBOX)
+                    || (messageType == MESSAGE_TYPE_SENT)
+                    || (messageType == MESSAGE_TYPE_QUEUED);
+        }
+
+        /**
+         * Contains all text-based SMS messages in the SMS app inbox.
+         */
+        public static final class Inbox implements BaseColumns, TextBasedSmsColumns {
+
+            /**
+             * Not instantiable.
+             * @hide
+             */
+            private Inbox() {
+            }
+
+            /**
+             * The {@code content://} style URL for this table.
+             */
+            public static final Uri CONTENT_URI = Uri.parse("content://sms/inbox");
+
+            /**
+             * The default sort order for this table.
+             */
+            public static final String DEFAULT_SORT_ORDER = "date DESC";
+
+            /**
+             * Add an SMS to the Draft box.
+             *
+             * @param resolver the content resolver to use
+             * @param address the address of the sender
+             * @param body the body of the message
+             * @param subject the pseudo-subject of the message
+             * @param date the timestamp for the message
+             * @param read true if the message has been read, false if not
+             * @return the URI for the new message
+             * @hide
+             */
+            @UnsupportedAppUsage
+            public static Uri addMessage(ContentResolver resolver,
+                    String address, String body, String subject, Long date,
+                    boolean read) {
+                return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
+                        resolver, CONTENT_URI, address, body, subject, date, read, false);
+            }
+
+            /**
+             * Add an SMS to the Draft box.
+             *
+             * @param resolver the content resolver to use
+             * @param address the address of the sender
+             * @param body the body of the message
+             * @param subject the psuedo-subject of the message
+             * @param date the timestamp for the message
+             * @param read true if the message has been read, false if not
+             * @param subId the subscription which the message belongs to
+             * @return the URI for the new message
+             * @hide
+             */
+            @UnsupportedAppUsage
+            public static Uri addMessage(int subId, ContentResolver resolver,
+                    String address, String body, String subject, Long date, boolean read) {
+                return addMessageToUri(subId, resolver, CONTENT_URI, address, body,
+                        subject, date, read, false);
+            }
+        }
+
+        /**
+         * Contains all sent text-based SMS messages in the SMS app.
+         */
+        public static final class Sent implements BaseColumns, TextBasedSmsColumns {
+
+            /**
+             * Not instantiable.
+             * @hide
+             */
+            private Sent() {
+            }
+
+            /**
+             * The {@code content://} style URL for this table.
+             */
+            public static final Uri CONTENT_URI = Uri.parse("content://sms/sent");
+
+            /**
+             * The default sort order for this table.
+             */
+            public static final String DEFAULT_SORT_ORDER = "date DESC";
+
+            /**
+             * Add an SMS to the Draft box.
+             *
+             * @param resolver the content resolver to use
+             * @param address the address of the sender
+             * @param body the body of the message
+             * @param subject the pseudo-subject of the message
+             * @param date the timestamp for the message
+             * @return the URI for the new message
+             * @hide
+             */
+            @UnsupportedAppUsage
+            public static Uri addMessage(ContentResolver resolver,
+                    String address, String body, String subject, Long date) {
+                return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
+                        resolver, CONTENT_URI, address, body, subject, date, true, false);
+            }
+
+            /**
+             * Add an SMS to the Draft box.
+             *
+             * @param resolver the content resolver to use
+             * @param address the address of the sender
+             * @param body the body of the message
+             * @param subject the psuedo-subject of the message
+             * @param date the timestamp for the message
+             * @param subId the subscription which the message belongs to
+             * @return the URI for the new message
+             * @hide
+             */
+            @UnsupportedAppUsage
+            public static Uri addMessage(int subId, ContentResolver resolver,
+                    String address, String body, String subject, Long date) {
+                return addMessageToUri(subId, resolver, CONTENT_URI, address, body,
+                        subject, date, true, false);
+            }
+        }
+
+        /**
+         * Contains all draft text-based SMS messages in the SMS app.
+         */
+        public static final class Draft implements BaseColumns, TextBasedSmsColumns {
+
+            /**
+             * Not instantiable.
+             * @hide
+             */
+            private Draft() {
+            }
+
+            /**
+             * The {@code content://} style URL for this table.
+             */
+            public static final Uri CONTENT_URI = Uri.parse("content://sms/draft");
+
+           /**
+            * @hide
+            */
+            @UnsupportedAppUsage
+            public static Uri addMessage(ContentResolver resolver,
+                    String address, String body, String subject, Long date) {
+                return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
+                        resolver, CONTENT_URI, address, body, subject, date, true, false);
+            }
+
+            /**
+             * Add an SMS to the Draft box.
+             *
+             * @param resolver the content resolver to use
+             * @param address the address of the sender
+             * @param body the body of the message
+             * @param subject the psuedo-subject of the message
+             * @param date the timestamp for the message
+             * @param subId the subscription which the message belongs to
+             * @return the URI for the new message
+             * @hide
+             */
+            @UnsupportedAppUsage
+            public static Uri addMessage(int subId, ContentResolver resolver,
+                    String address, String body, String subject, Long date) {
+                return addMessageToUri(subId, resolver, CONTENT_URI, address, body,
+                        subject, date, true, false);
+            }
+
+            /**
+             * The default sort order for this table.
+             */
+            public static final String DEFAULT_SORT_ORDER = "date DESC";
+        }
+
+        /**
+         * Contains all pending outgoing text-based SMS messages.
+         */
+        public static final class Outbox implements BaseColumns, TextBasedSmsColumns {
+
+            /**
+             * Not instantiable.
+             * @hide
+             */
+            private Outbox() {
+            }
+
+            /**
+             * The {@code content://} style URL for this table.
+             */
+            public static final Uri CONTENT_URI = Uri.parse("content://sms/outbox");
+
+            /**
+             * The default sort order for this table.
+             */
+            public static final String DEFAULT_SORT_ORDER = "date DESC";
+
+            /**
+             * Add an SMS to the outbox.
+             *
+             * @param resolver the content resolver to use
+             * @param address the address of the sender
+             * @param body the body of the message
+             * @param subject the pseudo-subject of the message
+             * @param date the timestamp for the message
+             * @param deliveryReport whether a delivery report was requested for the message
+             * @return the URI for the new message
+             * @hide
+             */
+            @UnsupportedAppUsage
+            public static Uri addMessage(ContentResolver resolver,
+                    String address, String body, String subject, Long date,
+                    boolean deliveryReport, long threadId) {
+                return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
+                        resolver, CONTENT_URI, address, body, subject, date,
+                        true, deliveryReport, threadId);
+            }
+
+            /**
+             * Add an SMS to the Out box.
+             *
+             * @param resolver the content resolver to use
+             * @param address the address of the sender
+             * @param body the body of the message
+             * @param subject the psuedo-subject of the message
+             * @param date the timestamp for the message
+             * @param deliveryReport whether a delivery report was requested for the message
+             * @param subId the subscription which the message belongs to
+             * @return the URI for the new message
+             * @hide
+             */
+            public static Uri addMessage(int subId, ContentResolver resolver,
+                    String address, String body, String subject, Long date,
+                    boolean deliveryReport, long threadId) {
+                return addMessageToUri(subId, resolver, CONTENT_URI, address, body,
+                        subject, date, true, deliveryReport, threadId);
+            }
+        }
+
+        /**
+         * Contains a view of SMS conversations (also referred to as threads). This is similar to
+         * {@link Threads}, but only includes SMS messages and columns relevant to SMS
+         * conversations.
+         * <p>
+         * Note that this view ignores any information about MMS messages, it is a
+         * view of conversations as if MMS messages did not exist at all. This means that all
+         * relevant information, such as snippets and message count, will ignore any MMS messages
+         * that might be in the same thread through other views and present only data based on the
+         * SMS messages in that thread.
+         */
+        public static final class Conversations
+                implements BaseColumns, TextBasedSmsColumns {
+
+            /**
+             * Not instantiable.
+             * @hide
+             */
+            private Conversations() {
+            }
+
+            /**
+             * The {@code content://} style URL for this table.
+             */
+            public static final Uri CONTENT_URI = Uri.parse("content://sms/conversations");
+
+            /**
+             * The default sort order for this table.
+             */
+            public static final String DEFAULT_SORT_ORDER = "date DESC";
+
+            /**
+             * The first 45 characters of the body of the most recent message.
+             * <P>Type: TEXT</P>
+             */
+            public static final String SNIPPET = "snippet";
+
+            /**
+             * The number of messages in the conversation.
+             * <P>Type: INTEGER</P>
+             */
+            public static final String MESSAGE_COUNT = "msg_count";
+        }
+
+        /**
+         * Contains constants for SMS related Intents that are broadcast.
+         */
+        public static final class Intents {
+
+            /**
+             * Not instantiable.
+             * @hide
+             */
+            private Intents() {
+            }
+
+            /**
+             * Set by BroadcastReceiver to indicate that the message was handled
+             * successfully.
+             */
+            public static final int RESULT_SMS_HANDLED = 1;
+
+            /**
+             * Set by BroadcastReceiver to indicate a generic error while
+             * processing the message.
+             */
+            public static final int RESULT_SMS_GENERIC_ERROR = 2;
+
+            /**
+             * Set as a "result" extra in the {@link #SMS_REJECTED_ACTION} intent to indicate
+             * insufficient memory to store the message.
+             */
+            public static final int RESULT_SMS_OUT_OF_MEMORY = 3;
+
+            /**
+             * Set as a "result" extra in the {@link #SMS_REJECTED_ACTION} intent to indicate that
+             * the message, while possibly valid, is of a format or encoding that is not supported.
+             */
+            public static final int RESULT_SMS_UNSUPPORTED = 4;
+
+            /**
+             * Set as a "result" extra in the {@link #SMS_REJECTED_ACTION} intent to indicate a
+             * duplicate incoming message.
+             */
+            public static final int RESULT_SMS_DUPLICATED = 5;
+
+            /**
+             * Set as a "result" extra in the {@link #SMS_REJECTED_ACTION} intent to indicate a
+             * dispatch failure.
+             */
+            public static final int RESULT_SMS_DISPATCH_FAILURE = 6;
+
+            /**
+             * Set as a "result" extra in the {@link #SMS_REJECTED_ACTION} intent to indicate a null
+             * PDU was received.
+             */
+            public static final int RESULT_SMS_NULL_PDU = 7;
+
+            /**
+             * Set as a "result" extra in the {@link #SMS_REJECTED_ACTION} intent to indicate a null
+             * message was encountered.
+             */
+            public static final int RESULT_SMS_NULL_MESSAGE = 8;
+
+            /**
+             * Set as a "result" extra in the {@link #SMS_REJECTED_ACTION} intent to indicate an sms
+             * was received while the phone was in encrypted state.
+             */
+            public static final int RESULT_SMS_RECEIVED_WHILE_ENCRYPTED = 9;
+
+            /**
+             * Set as a "result" extra in the {@link #SMS_REJECTED_ACTION} intent to indicate a
+             * telephony database error.
+             */
+            public static final int RESULT_SMS_DATABASE_ERROR = 10;
+
+            /**
+             * Set as a "result" extra in the {@link #SMS_REJECTED_ACTION} intent to indicate an
+             * invalid uri.
+             */
+            public static final int RESULT_SMS_INVALID_URI = 11;
+
+            /**
+             * Activity action: Ask the user to change the default
+             * SMS application. This will show a dialog that asks the
+             * user whether they want to replace the current default
+             * SMS application with the one specified in
+             * {@link #EXTRA_PACKAGE_NAME}.
+             * <p>
+             * This is no longer supported since Q, please use
+             * {@link android.app.role.RoleManager#createRequestRoleIntent(String)} with
+             * {@link android.app.role.RoleManager#ROLE_SMS} instead.
+             */
+            @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+            public static final String ACTION_CHANGE_DEFAULT =
+                    "android.provider.Telephony.ACTION_CHANGE_DEFAULT";
+
+            /**
+             * The PackageName string passed in as an
+             * extra for {@link #ACTION_CHANGE_DEFAULT}
+             *
+             * @see #ACTION_CHANGE_DEFAULT
+             * <p>
+             * This is no longer supported since Q, please use
+             * {@link android.app.role.RoleManager#createRequestRoleIntent(String)} with
+             * {@link android.app.role.RoleManager#ROLE_SMS} instead.
+             */
+            public static final String EXTRA_PACKAGE_NAME = "package";
+
+            /**
+             * Broadcast Action: A new text-based SMS message has been received
+             * by the device. This intent will only be delivered to the default
+             * sms app. That app is responsible for writing the message and notifying
+             * the user. The intent will have the following extra values:</p>
+             *
+             * <ul>
+             *   <li><em>"pdus"</em> - An Object[] of byte[]s containing the PDUs
+             *   that make up the message.</li>
+             *   <li><em>"format"</em> - A String describing the format of the PDUs. It can
+             *   be either "3gpp" or "3gpp2".</li>
+             *   <li><em>"subscription"</em> - An optional long value of the subscription id which
+             *   received the message.</li>
+             *   <li><em>"slot"</em> - An optional int value of the SIM slot containing the
+             *   subscription.</li>
+             *   <li><em>"phone"</em> - An optional int value of the phone id associated with the
+             *   subscription.</li>
+             *   <li><em>"errorCode"</em> - An optional int error code associated with receiving
+             *   the message.</li>
+             * </ul>
+             *
+             * <p>The extra values can be extracted using
+             * {@link #getMessagesFromIntent(Intent)}.</p>
+             *
+             * <p>If a BroadcastReceiver encounters an error while processing
+             * this intent it should set the result code appropriately.</p>
+             *
+             * <p class="note"><strong>Note:</strong>
+             * The broadcast receiver that filters for this intent must declare
+             * {@link android.Manifest.permission#BROADCAST_SMS} as a required permission in
+             * the <a href="{@docRoot}guide/topics/manifest/receiver-element.html">{@code
+             * <receiver>}</a> tag.
+             *
+             * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
+             */
+            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+            public static final String SMS_DELIVER_ACTION =
+                    "android.provider.Telephony.SMS_DELIVER";
+
+            /**
+             * Broadcast Action: A new text-based SMS message has been received
+             * by the device. This intent will be delivered to all registered
+             * receivers as a notification. These apps are not expected to write the
+             * message or notify the user. The intent will have the following extra
+             * values:</p>
+             *
+             * <ul>
+             *   <li><em>"pdus"</em> - An Object[] of byte[]s containing the PDUs
+             *   that make up the message.</li>
+             * </ul>
+             *
+             * <p>The extra values can be extracted using
+             * {@link #getMessagesFromIntent(Intent)}.</p>
+             *
+             * <p>If a BroadcastReceiver encounters an error while processing
+             * this intent it should set the result code appropriately.</p>
+             *
+             * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
+             */
+            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+            public static final String SMS_RECEIVED_ACTION =
+                    "android.provider.Telephony.SMS_RECEIVED";
+
+            /**
+             * Broadcast Action: A new data based SMS message has been received
+             * by the device. This intent will be delivered to all registered
+             * receivers as a notification. The intent will have the following extra
+             * values:</p>
+             *
+             * <ul>
+             *   <li><em>"pdus"</em> - An Object[] of byte[]s containing the PDUs
+             *   that make up the message.</li>
+             * </ul>
+             *
+             * <p>The extra values can be extracted using
+             * {@link #getMessagesFromIntent(Intent)}.</p>
+             *
+             * <p>If a BroadcastReceiver encounters an error while processing
+             * this intent it should set the result code appropriately.</p>
+             *
+             * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
+             */
+            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+            public static final String DATA_SMS_RECEIVED_ACTION =
+                    "android.intent.action.DATA_SMS_RECEIVED";
+
+            /**
+             * Broadcast Action: A new WAP PUSH message has been received by the
+             * device. This intent will only be delivered to the default
+             * sms app. That app is responsible for writing the message and notifying
+             * the user. The intent will have the following extra values:</p>
+             *
+             * <ul>
+             *   <li><em>"transactionId"</em> - (Integer) The WAP transaction ID</li>
+             *   <li><em>"pduType"</em> - (Integer) The WAP PDU type</li>
+             *   <li><em>"header"</em> - (byte[]) The header of the message</li>
+             *   <li><em>"data"</em> - (byte[]) The data payload of the message</li>
+             *   <li><em>"contentTypeParameters" </em>
+             *   -(HashMap&lt;String,String&gt;) Any parameters associated with the content type
+             *   (decoded from the WSP Content-Type header)</li>
+             *   <li><em>"subscription"</em> - An optional long value of the subscription id which
+             *   received the message.</li>
+             *   <li><em>"slot"</em> - An optional int value of the SIM slot containing the
+             *   subscription.</li>
+             *   <li><em>"phone"</em> - An optional int value of the phone id associated with the
+             *   subscription.</li>
+             * </ul>
+             *
+             * <p>If a BroadcastReceiver encounters an error while processing
+             * this intent it should set the result code appropriately.</p>
+             *
+             * <p>The contentTypeParameters extra value is map of content parameters keyed by
+             * their names.</p>
+             *
+             * <p>If any unassigned well-known parameters are encountered, the key of the map will
+             * be 'unassigned/0x...', where '...' is the hex value of the unassigned parameter.  If
+             * a parameter has No-Value the value in the map will be null.</p>
+             *
+             * <p>Requires {@link android.Manifest.permission#RECEIVE_MMS} or
+             * {@link android.Manifest.permission#RECEIVE_WAP_PUSH} (depending on WAP PUSH type) to
+             * receive.</p>
+             *
+             * <p class="note"><strong>Note:</strong>
+             * The broadcast receiver that filters for this intent must declare
+             * {@link android.Manifest.permission#BROADCAST_WAP_PUSH} as a required permission in
+             * the <a href="{@docRoot}guide/topics/manifest/receiver-element.html">{@code
+             * <receiver>}</a> tag.
+             */
+            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+            public static final String WAP_PUSH_DELIVER_ACTION =
+                    "android.provider.Telephony.WAP_PUSH_DELIVER";
+
+            /**
+             * Broadcast Action: A new WAP PUSH message has been received by the
+             * device. This intent will be delivered to all registered
+             * receivers as a notification. These apps are not expected to write the
+             * message or notify the user. The intent will have the following extra
+             * values:</p>
+             *
+             * <ul>
+             *   <li><em>"transactionId"</em> - (Integer) The WAP transaction ID</li>
+             *   <li><em>"pduType"</em> - (Integer) The WAP PDU type</li>
+             *   <li><em>"header"</em> - (byte[]) The header of the message</li>
+             *   <li><em>"data"</em> - (byte[]) The data payload of the message</li>
+             *   <li><em>"contentTypeParameters"</em>
+             *   - (HashMap&lt;String,String&gt;) Any parameters associated with the content type
+             *   (decoded from the WSP Content-Type header)</li>
+             * </ul>
+             *
+             * <p>If a BroadcastReceiver encounters an error while processing
+             * this intent it should set the result code appropriately.</p>
+             *
+             * <p>The contentTypeParameters extra value is map of content parameters keyed by
+             * their names.</p>
+             *
+             * <p>If any unassigned well-known parameters are encountered, the key of the map will
+             * be 'unassigned/0x...', where '...' is the hex value of the unassigned parameter.  If
+             * a parameter has No-Value the value in the map will be null.</p>
+             *
+             * <p>Requires {@link android.Manifest.permission#RECEIVE_MMS} or
+             * {@link android.Manifest.permission#RECEIVE_WAP_PUSH} (depending on WAP PUSH type) to
+             * receive.</p>
+             */
+            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+            public static final String WAP_PUSH_RECEIVED_ACTION =
+                    "android.provider.Telephony.WAP_PUSH_RECEIVED";
+
+            /**
+             * Broadcast Action: A new Cell Broadcast message has been received
+             * by the device. The intent will have the following extra
+             * values:</p>
+             *
+             * <ul>
+             *   <li><em>"message"</em> - An SmsCbMessage object containing the broadcast message
+             *   data. This is not an emergency alert, so ETWS and CMAS data will be null.</li>
+             * </ul>
+             *
+             * <p>The extra values can be extracted using
+             * {@link #getMessagesFromIntent(Intent)}.</p>
+             *
+             * <p>If a BroadcastReceiver encounters an error while processing
+             * this intent it should set the result code appropriately.</p>
+             *
+             * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
+             */
+            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+            public static final String SMS_CB_RECEIVED_ACTION =
+                    "android.provider.Telephony.SMS_CB_RECEIVED";
+
+            /**
+             * Action: A SMS based carrier provision intent. Used to identify default
+             * carrier provisioning app on the device.
+             * @hide
+             */
+            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+            @TestApi
+            public static final String SMS_CARRIER_PROVISION_ACTION =
+                    "android.provider.Telephony.SMS_CARRIER_PROVISION";
+
+            /**
+             * Broadcast Action: A new Emergency Broadcast message has been received
+             * by the device. The intent will have the following extra
+             * values:</p>
+             *
+             * <ul>
+             *   <li><em>"message"</em> - An {@link android.telephony.SmsCbMessage} object
+             *   containing the broadcast message data, including ETWS or CMAS warning notification
+             *   info if present.</li>
+             * </ul>
+             *
+             * <p>The extra values can be extracted using
+             * {@link #getMessagesFromIntent(Intent)}.</p>
+             *
+             * <p>If a BroadcastReceiver encounters an error while processing
+             * this intent it should set the result code appropriately.</p>
+             *
+             * <p>Requires {@link android.Manifest.permission#RECEIVE_EMERGENCY_BROADCAST} to
+             * receive.</p>
+             * @hide
+             */
+            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+            @SystemApi
+            public static final String ACTION_SMS_EMERGENCY_CB_RECEIVED =
+                    "android.provider.action.SMS_EMERGENCY_CB_RECEIVED";
+
+            /**
+             * Broadcast Action: A new CDMA SMS has been received containing Service Category
+             * Program Data (updates the list of enabled broadcast channels). The intent will
+             * have the following extra values:</p>
+             *
+             * <ul>
+             *   <li><em>"operations"</em> - An array of CdmaSmsCbProgramData objects containing
+             *   the service category operations (add/delete/clear) to perform.</li>
+             * </ul>
+             *
+             * <p>The extra values can be extracted using
+             * {@link #getMessagesFromIntent(Intent)}.</p>
+             *
+             * <p>If a BroadcastReceiver encounters an error while processing
+             * this intent it should set the result code appropriately.</p>
+             *
+             * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
+             */
+            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+            public static final String SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION =
+                    "android.provider.Telephony.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED";
+
+            /**
+             * Broadcast Action: The SIM storage for SMS messages is full.  If
+             * space is not freed, messages targeted for the SIM (class 2) may
+             * not be saved.
+             *
+             * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
+             */
+            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+            public static final String SIM_FULL_ACTION =
+                    "android.provider.Telephony.SIM_FULL";
+
+            /**
+             * Broadcast Action: An incoming SMS has been rejected by the
+             * telephony framework.  This intent is sent in lieu of any
+             * of the RECEIVED_ACTION intents.  The intent will have the
+             * following extra value:</p>
+             *
+             * <ul>
+             *   <li><em>"result"</em> - An int result code, e.g. {@link #RESULT_SMS_OUT_OF_MEMORY}
+             *   indicating the error returned to the network.</li>
+             * </ul>
+             *
+             * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
+             */
+            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+            public static final String SMS_REJECTED_ACTION =
+                "android.provider.Telephony.SMS_REJECTED";
+
+            /**
+             * Broadcast Action: An incoming MMS has been downloaded. The intent is sent to all
+             * users, except for secondary users where SMS has been disabled and to managed
+             * profiles.
+             * @hide
+             */
+            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+            public static final String MMS_DOWNLOADED_ACTION =
+                "android.provider.Telephony.MMS_DOWNLOADED";
+
+            /**
+             * Broadcast Action: A debug code has been entered in the dialer. This intent is
+             * broadcast by the system and OEM telephony apps may need to receive these broadcasts.
+             * These "secret codes" are used to activate developer menus by dialing certain codes.
+             * And they are of the form {@code *#*#<code>#*#*}. The intent will have the data
+             * URI: {@code android_secret_code://<code>}. It is possible that a manifest
+             * receiver would be woken up even if it is not currently running.
+             *
+             * <p>Requires {@code android.Manifest.permission#CONTROL_INCALL_EXPERIENCE} to
+             * send and receive.</p>
+             * @deprecated it is no longer supported, use {@link
+             * TelephonyManager#ACTION_SECRET_CODE} instead
+             */
+            @Deprecated
+            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+            public static final String SECRET_CODE_ACTION =
+                    "android.provider.Telephony.SECRET_CODE";
+
+            /**
+             * Broadcast action: When the default SMS package changes,
+             * the previous default SMS package and the new default SMS
+             * package are sent this broadcast to notify them of the change.
+             * A boolean is specified in {@link #EXTRA_IS_DEFAULT_SMS_APP} to
+             * indicate whether the package is the new default SMS package.
+            */
+            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+            public static final String ACTION_DEFAULT_SMS_PACKAGE_CHANGED =
+                            "android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED";
+
+            /**
+             * The IsDefaultSmsApp boolean passed as an
+             * extra for {@link #ACTION_DEFAULT_SMS_PACKAGE_CHANGED} to indicate whether the
+             * SMS app is becoming the default SMS app or is no longer the default.
+             *
+             * @see #ACTION_DEFAULT_SMS_PACKAGE_CHANGED
+             */
+            public static final String EXTRA_IS_DEFAULT_SMS_APP =
+                    "android.provider.extra.IS_DEFAULT_SMS_APP";
+
+            /**
+             * Broadcast action: When a change is made to the SmsProvider or
+             * MmsProvider by a process other than the default SMS application,
+             * this intent is broadcast to the default SMS application so it can
+             * re-sync or update the change. The uri that was used to call the provider
+             * can be retrieved from the intent with getData(). The actual affected uris
+             * (which would depend on the selection specified) are not included.
+            */
+            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+            public static final String ACTION_EXTERNAL_PROVIDER_CHANGE =
+                          "android.provider.action.EXTERNAL_PROVIDER_CHANGE";
+
+            /**
+             * Same as {@link #ACTION_DEFAULT_SMS_PACKAGE_CHANGED} but it's implicit (e.g. sent to
+             * all apps) and requires
+             * {@link android.Manifest.permission#MONITOR_DEFAULT_SMS_PACKAGE} to receive.
+             *
+             * @hide
+             */
+            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+            public static final String ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL =
+                    "android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL";
+
+            /**
+             * Broadcast action: When SMS-MMS db is being created. If file-based encryption is
+             * supported, this broadcast indicates creation of the db in credential-encrypted
+             * storage. A boolean is specified in {@link #EXTRA_IS_INITIAL_CREATE} to indicate if
+             * this is the initial create of the db. Requires
+             * {@link android.Manifest.permission#READ_SMS} to receive.
+             *
+             * @see #EXTRA_IS_INITIAL_CREATE
+             *
+             * @hide
+             */
+            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+            public static final String ACTION_SMS_MMS_DB_CREATED =
+                    "android.provider.action.SMS_MMS_DB_CREATED";
+
+            /**
+             * Boolean flag passed as an extra with {@link #ACTION_SMS_MMS_DB_CREATED} to indicate
+             * whether the DB creation is the initial creation on the device, that is it is after a
+             * factory-data reset or a new device. Any subsequent creations of the DB (which
+             * happens only in error scenarios) will have this flag set to false.
+             *
+             * @see #ACTION_SMS_MMS_DB_CREATED
+             *
+             * @hide
+             */
+            public static final String EXTRA_IS_INITIAL_CREATE =
+                    "android.provider.extra.IS_INITIAL_CREATE";
+
+            /**
+             * Broadcast intent action indicating that the telephony provider SMS MMS database is
+             * corrupted. A boolean is specified in {@link #EXTRA_IS_CORRUPTED} to indicate if the
+             * database is corrupted. Requires the
+             * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE permission.
+             *
+             * @hide
+             */
+            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+            @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+            public static final String ACTION_SMS_MMS_DB_LOST =
+                    "android.provider.action.SMS_MMS_DB_LOST";
+
+            /**
+             * Boolean flag passed as an extra with {@link #ACTION_SMS_MMS_DB_LOST} to indicate
+             * whether the DB got corrupted or not.
+             *
+             * @see #ACTION_SMS_MMS_DB_LOST
+             *
+             * @hide
+             */
+            public static final String EXTRA_IS_CORRUPTED =
+                    "android.provider.extra.IS_CORRUPTED";
+
+            /**
+             * Read the PDUs out of an {@link #SMS_RECEIVED_ACTION} or a
+             * {@link #DATA_SMS_RECEIVED_ACTION} intent.
+             *
+             * @param intent the intent to read from
+             * @return an array of SmsMessages for the PDUs
+             */
+            public static SmsMessage[] getMessagesFromIntent(Intent intent) {
+                Object[] messages;
+                try {
+                    messages = (Object[]) intent.getSerializableExtra("pdus");
+                }
+                catch (ClassCastException e) {
+                    Rlog.e(TAG, "getMessagesFromIntent: " + e);
+                    return null;
+                }
+
+                if (messages == null) {
+                    Rlog.e(TAG, "pdus does not exist in the intent");
+                    return null;
+                }
+
+                String format = intent.getStringExtra("format");
+                int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
+                        SubscriptionManager.getDefaultSmsSubscriptionId());
+
+                Rlog.v(TAG, " getMessagesFromIntent sub_id : " + subId);
+
+                int pduCount = messages.length;
+                SmsMessage[] msgs = new SmsMessage[pduCount];
+
+                for (int i = 0; i < pduCount; i++) {
+                    byte[] pdu = (byte[]) messages[i];
+                    msgs[i] = SmsMessage.createFromPdu(pdu, format);
+                    if (msgs[i] != null) msgs[i].setSubId(subId);
+                }
+                return msgs;
+            }
+        }
+    }
+
+    /**
+     * Base column for the table that contain Carrier Public key.
+     * @hide
+     */
+    @SystemApi
+    public interface CarrierColumns extends BaseColumns {
+
+        /**
+         * Mobile Country Code (MCC).
+         * <P> Type: TEXT </P>
+         */
+        public static final String MCC = "mcc";
+
+        /**
+         * Mobile Network Code (MNC).
+         * <P> Type: TEXT </P>
+         */
+        public static final String MNC = "mnc";
+
+        /**
+         * KeyType whether the key is being used for WLAN or ePDG.
+         * <P> Type: INTEGER </P>
+         */
+        public static final String KEY_TYPE = "key_type";
+
+        /**
+         * MVNO type:
+         * {@code SPN (Service Provider Name), IMSI, GID (Group Identifier Level 1)}.
+         * <P> Type: TEXT </P>
+         */
+        public static final String MVNO_TYPE = "mvno_type";
+
+        /**
+         * MVNO data.
+         * Use the following examples.
+         * <ul>
+         *     <li>SPN: A MOBILE, BEN NL, ...</li>
+         *     <li>IMSI: 302720x94, 2060188, ...</li>
+         *     <li>GID: 4E, 33, ...</li>
+         * </ul>
+         * <P> Type: TEXT </P>
+         */
+        public static final String MVNO_MATCH_DATA = "mvno_match_data";
+
+        /**
+         * The carrier public key that is used for the IMSI encryption.
+         * <P> Type: TEXT </P>
+         */
+        public static final String PUBLIC_KEY = "public_key";
+
+        /**
+         * The key identifier Attribute value pair that helps a server locate
+         * the private key to decrypt the permanent identity.
+         * <P> Type: TEXT </P>
+         */
+        public static final String KEY_IDENTIFIER = "key_identifier";
+
+        /**
+         * Date-Time in UTC when the key will expire.
+         * <P> Type: INTEGER (long) </P>
+         */
+        public static final String EXPIRATION_TIME = "expiration_time";
+
+        /**
+         * Timestamp when this table was last modified, in milliseconds since
+         * January 1, 1970 00:00:00.0 UTC.
+         * <P> Type: INTEGER (long) </P>
+         */
+        public static final String LAST_MODIFIED = "last_modified";
+
+        /**
+         * The {@code content://} style URL for this table.
+         */
+        @NonNull
+        public static final Uri CONTENT_URI = Uri.parse("content://carrier_information/carrier");
+    }
+
+    /**
+     * Base columns for tables that contain MMSs.
+     */
+    public interface BaseMmsColumns extends BaseColumns {
+
+        /** Message box: all messages. */
+        public static final int MESSAGE_BOX_ALL    = 0;
+        /** Message box: inbox. */
+        public static final int MESSAGE_BOX_INBOX  = 1;
+        /** Message box: sent messages. */
+        public static final int MESSAGE_BOX_SENT   = 2;
+        /** Message box: drafts. */
+        public static final int MESSAGE_BOX_DRAFTS = 3;
+        /** Message box: outbox. */
+        public static final int MESSAGE_BOX_OUTBOX = 4;
+        /** Message box: failed. */
+        public static final int MESSAGE_BOX_FAILED = 5;
+
+        /**
+         * The thread ID of the message.
+         * <P>Type: INTEGER (long)</P>
+         */
+        public static final String THREAD_ID = "thread_id";
+
+        /**
+         * The date the message was received.
+         * <P>Type: INTEGER (long)</P>
+         */
+        public static final String DATE = "date";
+
+        /**
+         * The date the message was sent.
+         * <P>Type: INTEGER (long)</P>
+         */
+        public static final String DATE_SENT = "date_sent";
+
+        /**
+         * The box which the message belongs to, e.g. {@link #MESSAGE_BOX_INBOX}.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String MESSAGE_BOX = "msg_box";
+
+        /**
+         * Has the message been read?
+         * <P>Type: INTEGER (boolean)</P>
+         */
+        public static final String READ = "read";
+
+        /**
+         * Has the message been seen by the user? The "seen" flag determines
+         * whether we need to show a new message notification.
+         * <P>Type: INTEGER (boolean)</P>
+         */
+        public static final String SEEN = "seen";
+
+        /**
+         * Does the message have only a text part (can also have a subject) with
+         * no picture, slideshow, sound, etc. parts?
+         * <P>Type: INTEGER (boolean)</P>
+         */
+        public static final String TEXT_ONLY = "text_only";
+
+        /**
+         * The {@code Message-ID} of the message.
+         * <P>Type: TEXT</P>
+         */
+        public static final String MESSAGE_ID = "m_id";
+
+        /**
+         * The subject of the message, if present.
+         * <P>Type: TEXT</P>
+         */
+        public static final String SUBJECT = "sub";
+
+        /**
+         * The character set of the subject, if present.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String SUBJECT_CHARSET = "sub_cs";
+
+        /**
+         * The {@code Content-Type} of the message.
+         * <P>Type: TEXT</P>
+         */
+        public static final String CONTENT_TYPE = "ct_t";
+
+        /**
+         * The {@code Content-Location} of the message.
+         * <P>Type: TEXT</P>
+         */
+        public static final String CONTENT_LOCATION = "ct_l";
+
+        /**
+         * The expiry time of the message.
+         * <P>Type: INTEGER (long)</P>
+         */
+        public static final String EXPIRY = "exp";
+
+        /**
+         * The class of the message.
+         * <P>Type: TEXT</P>
+         */
+        public static final String MESSAGE_CLASS = "m_cls";
+
+        /**
+         * The type of the message defined by MMS spec.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String MESSAGE_TYPE = "m_type";
+
+        /**
+         * The version of the specification that this message conforms to.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String MMS_VERSION = "v";
+
+        /**
+         * The size of the message.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String MESSAGE_SIZE = "m_size";
+
+        /**
+         * The priority of the message.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String PRIORITY = "pri";
+
+        /**
+         * The {@code read-report} of the message.
+         * <P>Type: INTEGER (boolean)</P>
+         */
+        public static final String READ_REPORT = "rr";
+
+        /**
+         * Is read report allowed?
+         * <P>Type: INTEGER (boolean)</P>
+         */
+        public static final String REPORT_ALLOWED = "rpt_a";
+
+        /**
+         * The {@code response-status} of the message.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String RESPONSE_STATUS = "resp_st";
+
+        /**
+         * The {@code status} of the message.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String STATUS = "st";
+
+        /**
+         * The {@code transaction-id} of the message.
+         * <P>Type: TEXT</P>
+         */
+        public static final String TRANSACTION_ID = "tr_id";
+
+        /**
+         * The {@code retrieve-status} of the message.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String RETRIEVE_STATUS = "retr_st";
+
+        /**
+         * The {@code retrieve-text} of the message.
+         * <P>Type: TEXT</P>
+         */
+        public static final String RETRIEVE_TEXT = "retr_txt";
+
+        /**
+         * The character set of the retrieve-text.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String RETRIEVE_TEXT_CHARSET = "retr_txt_cs";
+
+        /**
+         * The {@code read-status} of the message.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String READ_STATUS = "read_status";
+
+        /**
+         * The {@code content-class} of the message.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String CONTENT_CLASS = "ct_cls";
+
+        /**
+         * The {@code delivery-report} of the message.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String DELIVERY_REPORT = "d_rpt";
+
+        /**
+         * The {@code delivery-time-token} of the message.
+         * <P>Type: INTEGER</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String DELIVERY_TIME_TOKEN = "d_tm_tok";
+
+        /**
+         * The {@code delivery-time} of the message.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String DELIVERY_TIME = "d_tm";
+
+        /**
+         * The {@code response-text} of the message.
+         * <P>Type: TEXT</P>
+         */
+        public static final String RESPONSE_TEXT = "resp_txt";
+
+        /**
+         * The {@code sender-visibility} of the message.
+         * <P>Type: TEXT</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String SENDER_VISIBILITY = "s_vis";
+
+        /**
+         * The {@code reply-charging} of the message.
+         * <P>Type: INTEGER</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String REPLY_CHARGING = "r_chg";
+
+        /**
+         * The {@code reply-charging-deadline-token} of the message.
+         * <P>Type: INTEGER</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String REPLY_CHARGING_DEADLINE_TOKEN = "r_chg_dl_tok";
+
+        /**
+         * The {@code reply-charging-deadline} of the message.
+         * <P>Type: INTEGER</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String REPLY_CHARGING_DEADLINE = "r_chg_dl";
+
+        /**
+         * The {@code reply-charging-id} of the message.
+         * <P>Type: TEXT</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String REPLY_CHARGING_ID = "r_chg_id";
+
+        /**
+         * The {@code reply-charging-size} of the message.
+         * <P>Type: INTEGER</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String REPLY_CHARGING_SIZE = "r_chg_sz";
+
+        /**
+         * The {@code previously-sent-by} of the message.
+         * <P>Type: TEXT</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String PREVIOUSLY_SENT_BY = "p_s_by";
+
+        /**
+         * The {@code previously-sent-date} of the message.
+         * <P>Type: INTEGER</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String PREVIOUSLY_SENT_DATE = "p_s_d";
+
+        /**
+         * The {@code store} of the message.
+         * <P>Type: TEXT</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String STORE = "store";
+
+        /**
+         * The {@code mm-state} of the message.
+         * <P>Type: INTEGER</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String MM_STATE = "mm_st";
+
+        /**
+         * The {@code mm-flags-token} of the message.
+         * <P>Type: INTEGER</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String MM_FLAGS_TOKEN = "mm_flg_tok";
+
+        /**
+         * The {@code mm-flags} of the message.
+         * <P>Type: TEXT</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String MM_FLAGS = "mm_flg";
+
+        /**
+         * The {@code store-status} of the message.
+         * <P>Type: TEXT</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String STORE_STATUS = "store_st";
+
+        /**
+         * The {@code store-status-text} of the message.
+         * <P>Type: TEXT</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String STORE_STATUS_TEXT = "store_st_txt";
+
+        /**
+         * The {@code stored} of the message.
+         * <P>Type: TEXT</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String STORED = "stored";
+
+        /**
+         * The {@code totals} of the message.
+         * <P>Type: TEXT</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String TOTALS = "totals";
+
+        /**
+         * The {@code mbox-totals} of the message.
+         * <P>Type: TEXT</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String MBOX_TOTALS = "mb_t";
+
+        /**
+         * The {@code mbox-totals-token} of the message.
+         * <P>Type: INTEGER</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String MBOX_TOTALS_TOKEN = "mb_t_tok";
+
+        /**
+         * The {@code quotas} of the message.
+         * <P>Type: TEXT</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String QUOTAS = "qt";
+
+        /**
+         * The {@code mbox-quotas} of the message.
+         * <P>Type: TEXT</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String MBOX_QUOTAS = "mb_qt";
+
+        /**
+         * The {@code mbox-quotas-token} of the message.
+         * <P>Type: INTEGER</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String MBOX_QUOTAS_TOKEN = "mb_qt_tok";
+
+        /**
+         * The {@code message-count} of the message.
+         * <P>Type: INTEGER</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String MESSAGE_COUNT = "m_cnt";
+
+        /**
+         * The {@code start} of the message.
+         * <P>Type: INTEGER</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String START = "start";
+
+        /**
+         * The {@code distribution-indicator} of the message.
+         * <P>Type: TEXT</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String DISTRIBUTION_INDICATOR = "d_ind";
+
+        /**
+         * The {@code element-descriptor} of the message.
+         * <P>Type: TEXT</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String ELEMENT_DESCRIPTOR = "e_des";
+
+        /**
+         * The {@code limit} of the message.
+         * <P>Type: INTEGER</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String LIMIT = "limit";
+
+        /**
+         * The {@code recommended-retrieval-mode} of the message.
+         * <P>Type: INTEGER</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String RECOMMENDED_RETRIEVAL_MODE = "r_r_mod";
+
+        /**
+         * The {@code recommended-retrieval-mode-text} of the message.
+         * <P>Type: TEXT</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String RECOMMENDED_RETRIEVAL_MODE_TEXT = "r_r_mod_txt";
+
+        /**
+         * The {@code status-text} of the message.
+         * <P>Type: TEXT</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String STATUS_TEXT = "st_txt";
+
+        /**
+         * The {@code applic-id} of the message.
+         * <P>Type: TEXT</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String APPLIC_ID = "apl_id";
+
+        /**
+         * The {@code reply-applic-id} of the message.
+         * <P>Type: TEXT</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String REPLY_APPLIC_ID = "r_apl_id";
+
+        /**
+         * The {@code aux-applic-id} of the message.
+         * <P>Type: TEXT</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String AUX_APPLIC_ID = "aux_apl_id";
+
+        /**
+         * The {@code drm-content} of the message.
+         * <P>Type: TEXT</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String DRM_CONTENT = "drm_c";
+
+        /**
+         * The {@code adaptation-allowed} of the message.
+         * <P>Type: TEXT</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String ADAPTATION_ALLOWED = "adp_a";
+
+        /**
+         * The {@code replace-id} of the message.
+         * <P>Type: TEXT</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String REPLACE_ID = "repl_id";
+
+        /**
+         * The {@code cancel-id} of the message.
+         * <P>Type: TEXT</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String CANCEL_ID = "cl_id";
+
+        /**
+         * The {@code cancel-status} of the message.
+         * <P>Type: INTEGER</P>
+         * @deprecated this column is no longer supported.
+         * @hide
+         */
+        @Deprecated
+        public static final String CANCEL_STATUS = "cl_st";
+
+        /**
+         * Is the message locked?
+         * <P>Type: INTEGER (boolean)</P>
+         */
+        public static final String LOCKED = "locked";
+
+        /**
+         * The subscription to which the message belongs to. Its value will be
+         * < 0 if the sub id cannot be determined.
+         * <p>Type: INTEGER (long)</p>
+         */
+        public static final String SUBSCRIPTION_ID = "sub_id";
+
+        /**
+         * The identity of the sender of a sent message. It is
+         * usually the package name of the app which sends the message.
+         * <p class="note"><strong>Note:</strong>
+         * This column is read-only. It is set by the provider and can not be changed by apps.
+         * <p>Type: TEXT</p>
+         */
+        public static final String CREATOR = "creator";
+    }
+
+    /**
+     * Columns for the "canonical_addresses" table used by MMS and SMS.
+     */
+    public interface CanonicalAddressesColumns extends BaseColumns {
+        /**
+         * An address used in MMS or SMS.  Email addresses are
+         * converted to lower case and are compared by string
+         * equality.  Other addresses are compared using
+         * PHONE_NUMBERS_EQUAL.
+         * <P>Type: TEXT</P>
+         */
+        public static final String ADDRESS = "address";
+    }
+
+    /**
+     * Columns for the "threads" table used by MMS and SMS.
+     */
+    public interface ThreadsColumns extends BaseColumns {
+
+        /**
+         * The date at which the thread was created.
+         * <P>Type: INTEGER (long)</P>
+         */
+        public static final String DATE = "date";
+
+        /**
+         * A string encoding of the recipient IDs of the recipients of
+         * the message, in numerical order and separated by spaces.
+         * <P>Type: TEXT</P>
+         */
+        public static final String RECIPIENT_IDS = "recipient_ids";
+
+        /**
+         * The message count of the thread.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String MESSAGE_COUNT = "message_count";
+
+        /**
+         * Indicates whether all messages of the thread have been read.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String READ = "read";
+
+        /**
+         * The snippet of the latest message in the thread.
+         * <P>Type: TEXT</P>
+         */
+        public static final String SNIPPET = "snippet";
+
+        /**
+         * The charset of the snippet.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String SNIPPET_CHARSET = "snippet_cs";
+
+        /**
+         * Type of the thread, either {@link Threads#COMMON_THREAD} or
+         * {@link Threads#BROADCAST_THREAD}.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String TYPE = "type";
+
+        /**
+         * Indicates whether there is a transmission error in the thread.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String ERROR = "error";
+
+        /**
+         * Indicates whether this thread contains any attachments.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String HAS_ATTACHMENT = "has_attachment";
+
+        /**
+         * If the thread is archived
+         * <P>Type: INTEGER (boolean)</P>
+         */
+        public static final String ARCHIVED = "archived";
+    }
+
+    /**
+     * Helper functions for the "threads" table used by MMS and SMS.
+     *
+     * Thread IDs are determined by the participants in a conversation and can be used to match
+     * both SMS and MMS messages.
+     *
+     * To avoid issues where applications might cache a thread ID, the thread ID of a deleted thread
+     * must not be reused to point at a new thread.
+     */
+    public static final class Threads implements ThreadsColumns {
+
+        @UnsupportedAppUsage
+        private static final String[] ID_PROJECTION = { BaseColumns._ID };
+
+        /**
+         * Private {@code content://} style URL for this table. Used by
+         * {@link #getOrCreateThreadId(android.content.Context, java.util.Set)}.
+         */
+        @UnsupportedAppUsage
+        private static final Uri THREAD_ID_CONTENT_URI = Uri.parse(
+                "content://mms-sms/threadID");
+
+        /**
+         * The {@code content://} style URL for this table, by conversation.
+         */
+        public static final Uri CONTENT_URI = Uri.withAppendedPath(
+                MmsSms.CONTENT_URI, "conversations");
+
+        /**
+         * The {@code content://} style URL for this table, for obsolete threads.
+         */
+        public static final Uri OBSOLETE_THREADS_URI = Uri.withAppendedPath(
+                CONTENT_URI, "obsolete");
+
+        /** Thread type: common thread. */
+        public static final int COMMON_THREAD    = 0;
+
+        /** Thread type: broadcast thread. */
+        public static final int BROADCAST_THREAD = 1;
+
+        /**
+         * Not instantiable.
+         * @hide
+         */
+        private Threads() {
+        }
+
+        /**
+         * This is a single-recipient version of {@code getOrCreateThreadId}.
+         * It's convenient for use with SMS messages.
+         * @param context the context object to use.
+         * @param recipient the recipient to send to.
+         */
+        public static long getOrCreateThreadId(Context context, String recipient) {
+            Set<String> recipients = new HashSet<String>();
+
+            recipients.add(recipient);
+            return getOrCreateThreadId(context, recipients);
+        }
+
+        /**
+         * Given a set of recipients return its thread ID.
+         * <p>
+         * If a thread exists containing the provided participants, return its thread ID. Otherwise,
+         * this will create a new thread containing the provided participants and return its ID.
+         */
+        public static long getOrCreateThreadId(
+                Context context, Set<String> recipients) {
+            Uri.Builder uriBuilder = THREAD_ID_CONTENT_URI.buildUpon();
+
+            for (String recipient : recipients) {
+                if (Mms.isEmailAddress(recipient)) {
+                    recipient = Mms.extractAddrSpec(recipient);
+                }
+
+                uriBuilder.appendQueryParameter("recipient", recipient);
+            }
+
+            Uri uri = uriBuilder.build();
+            //if (DEBUG) Rlog.v(TAG, "getOrCreateThreadId uri: " + uri);
+
+            Cursor cursor = SqliteWrapper.query(context, context.getContentResolver(),
+                    uri, ID_PROJECTION, null, null, null);
+            if (cursor != null) {
+                try {
+                    if (cursor.moveToFirst()) {
+                        return cursor.getLong(0);
+                    } else {
+                        Rlog.e(TAG, "getOrCreateThreadId returned no rows!");
+                    }
+                } finally {
+                    cursor.close();
+                }
+            }
+
+            Rlog.e(TAG, "getOrCreateThreadId failed with " + recipients.size() + " recipients");
+            throw new IllegalArgumentException("Unable to find or allocate a thread ID.");
+        }
+    }
+
+    /**
+     * Columns for the "rcs_*" tables used by {@link android.telephony.ims.RcsMessageStore} classes.
+     *
+     * @hide - not meant for public use
+     */
+    public interface RcsColumns {
+        // TODO(sahinc): Turn this to true once the schema finalizes, so that people can update
+        //  their messaging databases. NOTE: move the switch/case update in MmsSmsDatabaseHelper to
+        //  the latest version of the database before turning this flag to true.
+        boolean IS_RCS_TABLE_SCHEMA_CODE_COMPLETE = false;
+
+        /**
+         * The authority for the content provider
+         */
+        String AUTHORITY = "rcs";
+
+        /**
+         * The URI to start building upon to use {@link com.android.providers.telephony.RcsProvider}
+         */
+        Uri CONTENT_AND_AUTHORITY = Uri.parse("content://" + AUTHORITY);
+
+        /**
+         * The value to be used whenever a transaction that expects an integer to be returned
+         * failed.
+         */
+        int TRANSACTION_FAILED = Integer.MIN_VALUE;
+
+        /**
+         * The value that denotes a timestamp was not set before (e.g. a message that is not
+         * delivered yet will not have a DELIVERED_TIMESTAMP)
+         */
+        long TIMESTAMP_NOT_SET = 0;
+
+        /**
+         * The table that {@link android.telephony.ims.RcsThread} gets persisted to
+         */
+        interface RcsThreadColumns {
+            /**
+             * The path that should be used for referring to
+             * {@link android.telephony.ims.RcsThread}s in
+             * {@link com.android.providers.telephony.RcsProvider} URIs.
+             */
+            String RCS_THREAD_URI_PART = "thread";
+
+            /**
+             * The URI to query or modify {@link android.telephony.ims.RcsThread} via the content
+             * provider.
+             */
+            Uri RCS_THREAD_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY, RCS_THREAD_URI_PART);
+
+            /**
+             * The unique identifier of an {@link android.telephony.ims.RcsThread}
+             */
+            String RCS_THREAD_ID_COLUMN = "rcs_thread_id";
+        }
+
+        /**
+         * The table that {@link android.telephony.ims.Rcs1To1Thread} gets persisted to
+         */
+        interface Rcs1To1ThreadColumns extends RcsThreadColumns {
+            /**
+             * The path that should be used for referring to
+             * {@link android.telephony.ims.Rcs1To1Thread}s in
+             * {@link com.android.providers.telephony.RcsProvider} URIs.
+             */
+            String RCS_1_TO_1_THREAD_URI_PART = "p2p_thread";
+
+            /**
+             * The URI to query or modify {@link android.telephony.ims.Rcs1To1Thread}s via the
+             * content provider. Can also insert to this URI to create a new 1-to-1 thread. When
+             * performing an insert, ensure that the provided content values contain the other
+             * participant's ID under the key
+             * {@link RcsParticipantColumns.RCS_PARTICIPANT_ID_COLUMN}
+             */
+            Uri RCS_1_TO_1_THREAD_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
+                    RCS_1_TO_1_THREAD_URI_PART);
+
+            /**
+             * The SMS/MMS thread to fallback to in case of an RCS outage
+             */
+            String FALLBACK_THREAD_ID_COLUMN = "rcs_fallback_thread_id";
+        }
+
+        /**
+         * The table that {@link android.telephony.ims.RcsGroupThread} gets persisted to
+         */
+        interface RcsGroupThreadColumns extends RcsThreadColumns {
+            /**
+             * The path that should be used for referring to
+             * {@link android.telephony.ims.RcsGroupThread}s in
+             * {@link com.android.providers.telephony.RcsProvider} URIs.
+             */
+            String RCS_GROUP_THREAD_URI_PART = "group_thread";
+
+            /**
+             * The URI to query or modify {@link android.telephony.ims.RcsGroupThread}s via the
+             * content provider
+             */
+            Uri RCS_GROUP_THREAD_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
+                    RCS_GROUP_THREAD_URI_PART);
+
+            /**
+             * The owner/admin of the {@link android.telephony.ims.RcsGroupThread}
+             */
+            String OWNER_PARTICIPANT_COLUMN = "owner_participant";
+
+            /**
+             * The user visible name of the group
+             */
+            String GROUP_NAME_COLUMN = "group_name";
+
+            /**
+             * The user visible icon of the group
+             */
+            String GROUP_ICON_COLUMN = "group_icon";
+
+            /**
+             * The RCS conference URI for this group
+             */
+            String CONFERENCE_URI_COLUMN = "conference_uri";
+        }
+
+        /**
+         * The view that enables polling from all types of RCS threads at once
+         */
+        interface RcsUnifiedThreadColumns extends RcsThreadColumns, Rcs1To1ThreadColumns,
+                RcsGroupThreadColumns {
+            /**
+             * The type of this {@link android.telephony.ims.RcsThread}
+             */
+            String THREAD_TYPE_COLUMN = "thread_type";
+
+            /**
+             * Integer returned as a result from a database query that denotes the thread is 1 to 1
+             */
+            int THREAD_TYPE_1_TO_1 = 0;
+
+            /**
+             * Integer returned as a result from a database query that denotes the thread is 1 to 1
+             */
+            int THREAD_TYPE_GROUP = 1;
+        }
+
+        /**
+         * The table that {@link android.telephony.ims.RcsParticipant} gets persisted to
+         */
+        interface RcsParticipantColumns {
+            /**
+             * The path that should be used for referring to
+             * {@link android.telephony.ims.RcsParticipant}s in
+             * {@link com.android.providers.telephony.RcsProvider} URIs.
+             */
+            String RCS_PARTICIPANT_URI_PART = "participant";
+
+            /**
+             * The URI to query or modify {@link android.telephony.ims.RcsParticipant}s via the
+             * content provider
+             */
+            Uri RCS_PARTICIPANT_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
+                    RCS_PARTICIPANT_URI_PART);
+
+            /**
+             * The unique identifier of the entry in the database
+             */
+            String RCS_PARTICIPANT_ID_COLUMN = "rcs_participant_id";
+
+            /**
+             * A foreign key on canonical_address table, also used by SMS/MMS
+             */
+            String CANONICAL_ADDRESS_ID_COLUMN = "canonical_address_id";
+
+            /**
+             * The user visible RCS alias for this participant.
+             */
+            String RCS_ALIAS_COLUMN = "rcs_alias";
+        }
+
+        /**
+         * Additional constants to enable access to {@link android.telephony.ims.RcsParticipant}
+         * related data
+         */
+        interface RcsParticipantHelpers extends RcsParticipantColumns {
+            /**
+             * The view that unifies "rcs_participant" and "canonical_addresses" tables for easy
+             * access to participant address.
+             */
+            String RCS_PARTICIPANT_WITH_ADDRESS_VIEW = "rcs_participant_with_address_view";
+
+            /**
+             * The view that unifies "rcs_participant", "canonical_addresses" and
+             * "rcs_thread_participant" junction table to get full information on participants that
+             * contribute to threads.
+             */
+            String RCS_PARTICIPANT_WITH_THREAD_VIEW = "rcs_participant_with_thread_view";
+        }
+
+        /**
+         * The table that {@link android.telephony.ims.RcsMessage} gets persisted to
+         */
+        interface RcsMessageColumns {
+            /**
+             * Denotes the type of this message (i.e.
+             * {@link android.telephony.ims.RcsIncomingMessage} or
+             * {@link android.telephony.ims.RcsOutgoingMessage}
+             */
+            String MESSAGE_TYPE_COLUMN = "rcs_message_type";
+
+            /**
+             * The unique identifier for the message in the database - i.e. the primary key.
+             */
+            String MESSAGE_ID_COLUMN = "rcs_message_row_id";
+
+            /**
+             * The globally unique RCS identifier for the message. Please see 4.4.5.2 - GSMA
+             * RCC.53 (RCS Device API 1.6 Specification)
+             */
+            String GLOBAL_ID_COLUMN = "rcs_message_global_id";
+
+            /**
+             * The subscription where this message was sent from/to.
+             */
+            String SUB_ID_COLUMN = "sub_id";
+
+            /**
+             * The sending status of the message.
+             * @see android.telephony.ims.RcsMessage.RcsMessageStatus
+             */
+            String STATUS_COLUMN = "status";
+
+            /**
+             * The creation timestamp of the message.
+             */
+            String ORIGINATION_TIMESTAMP_COLUMN = "origination_timestamp";
+
+            /**
+             * The text content of the message.
+             */
+            String MESSAGE_TEXT_COLUMN = "rcs_text";
+
+            /**
+             * The latitude content of the message, if it contains a location.
+             */
+            String LATITUDE_COLUMN = "latitude";
+
+            /**
+             * The longitude content of the message, if it contains a location.
+             */
+            String LONGITUDE_COLUMN = "longitude";
+        }
+
+        /**
+         * The table that additional information of {@link android.telephony.ims.RcsIncomingMessage}
+         * gets persisted to.
+         */
+        interface RcsIncomingMessageColumns extends RcsMessageColumns {
+            /**
+             The path that should be used for referring to
+             * {@link android.telephony.ims.RcsIncomingMessage}s in
+             * {@link com.android.providers.telephony.RcsProvider} URIs.
+             */
+            String INCOMING_MESSAGE_URI_PART = "incoming_message";
+
+            /**
+             * The URI to query incoming messages through
+             * {@link com.android.providers.telephony.RcsProvider}
+             */
+            Uri INCOMING_MESSAGE_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
+                    INCOMING_MESSAGE_URI_PART);
+
+            /**
+             * The ID of the {@link android.telephony.ims.RcsParticipant} that sent this message
+             */
+            String SENDER_PARTICIPANT_ID_COLUMN = "sender_participant";
+
+            /**
+             * The timestamp of arrival for this message.
+             */
+            String ARRIVAL_TIMESTAMP_COLUMN = "arrival_timestamp";
+
+            /**
+             * The time when the recipient has read this message.
+             */
+            String SEEN_TIMESTAMP_COLUMN = "seen_timestamp";
+        }
+
+        /**
+         * The table that additional information of {@link android.telephony.ims.RcsOutgoingMessage}
+         * gets persisted to.
+         */
+        interface RcsOutgoingMessageColumns extends RcsMessageColumns {
+            /**
+             * The path that should be used for referring to
+             * {@link android.telephony.ims.RcsOutgoingMessage}s in
+             * {@link com.android.providers.telephony.RcsProvider} URIs.
+             */
+            String OUTGOING_MESSAGE_URI_PART = "outgoing_message";
+
+            /**
+             * The URI to query or modify {@link android.telephony.ims.RcsOutgoingMessage}s via the
+             * content provider
+             */
+            Uri OUTGOING_MESSAGE_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
+                    OUTGOING_MESSAGE_URI_PART);
+        }
+
+        /**
+         * The delivery information of an {@link android.telephony.ims.RcsOutgoingMessage}
+         */
+        interface RcsMessageDeliveryColumns extends RcsOutgoingMessageColumns {
+            /**
+             * The path that should be used for referring to
+             * {@link android.telephony.ims.RcsOutgoingMessageDelivery}s in
+             * {@link com.android.providers.telephony.RcsProvider} URIs.
+             */
+            String DELIVERY_URI_PART = "delivery";
+
+            /**
+             * The timestamp of delivery of this message.
+             */
+            String DELIVERED_TIMESTAMP_COLUMN = "delivered_timestamp";
+
+            /**
+             * The time when the recipient has read this message.
+             */
+            String SEEN_TIMESTAMP_COLUMN = "seen_timestamp";
+        }
+
+        /**
+         * The views that allow querying {@link android.telephony.ims.RcsIncomingMessage} and
+         * {@link android.telephony.ims.RcsOutgoingMessage} at the same time.
+         */
+        interface RcsUnifiedMessageColumns extends RcsIncomingMessageColumns,
+                RcsOutgoingMessageColumns {
+            /**
+             * The path that is used to query all {@link android.telephony.ims.RcsMessage} in
+             * {@link com.android.providers.telephony.RcsProvider} URIs.
+             */
+            String UNIFIED_MESSAGE_URI_PART = "message";
+
+            /**
+             * The URI to query all types of {@link android.telephony.ims.RcsMessage}s
+             */
+            Uri UNIFIED_MESSAGE_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
+                    UNIFIED_MESSAGE_URI_PART);
+
+            /**
+             * The name of the view that unites rcs_message and rcs_incoming_message tables.
+             */
+            String UNIFIED_INCOMING_MESSAGE_VIEW = "unified_incoming_message_view";
+
+            /**
+             * The name of the view that unites rcs_message and rcs_outgoing_message tables.
+             */
+            String UNIFIED_OUTGOING_MESSAGE_VIEW = "unified_outgoing_message_view";
+
+            /**
+             * The column that shows from which table the message entry came from.
+             */
+            String MESSAGE_TYPE_COLUMN = "message_type";
+
+            /**
+             * Integer returned as a result from a database query that denotes that the message is
+             * an incoming message
+             */
+            int MESSAGE_TYPE_INCOMING = 1;
+
+            /**
+             * Integer returned as a result from a database query that denotes that the message is
+             * an outgoing message
+             */
+            int MESSAGE_TYPE_OUTGOING = 0;
+        }
+
+        /**
+         * The table that {@link android.telephony.ims.RcsFileTransferPart} gets persisted to.
+         */
+        interface RcsFileTransferColumns {
+            /**
+             * The path that should be used for referring to
+             * {@link android.telephony.ims.RcsFileTransferPart}s in
+             * {@link com.android.providers.telephony.RcsProvider} URIs.
+             */
+            String FILE_TRANSFER_URI_PART = "file_transfer";
+
+            /**
+             * The URI to query or modify {@link android.telephony.ims.RcsFileTransferPart}s via the
+             * content provider
+             */
+            Uri FILE_TRANSFER_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
+                    FILE_TRANSFER_URI_PART);
+
+            /**
+             * The globally unique file transfer ID for this RCS file transfer.
+             */
+            String FILE_TRANSFER_ID_COLUMN = "rcs_file_transfer_id";
+
+            /**
+             * The RCS session ID for this file transfer. The ID is implementation dependent but
+             * should be unique.
+             */
+            String SESSION_ID_COLUMN = "session_id";
+
+            /**
+             * The URI that points to the content of this file transfer
+             */
+            String CONTENT_URI_COLUMN = "content_uri";
+
+            /**
+             * The file type of this file transfer in bytes. The validity of types is not enforced
+             * in {@link android.telephony.ims.RcsMessageStore} APIs.
+             */
+            String CONTENT_TYPE_COLUMN = "content_type";
+
+            /**
+             * The size of the file transfer in bytes.
+             */
+            String FILE_SIZE_COLUMN = "file_size";
+
+            /**
+             * Number of bytes that was successfully transmitted for this file transfer
+             */
+            String SUCCESSFULLY_TRANSFERRED_BYTES = "transfer_offset";
+
+            /**
+             * The status of this file transfer
+             * @see android.telephony.ims.RcsFileTransferPart.RcsFileTransferStatus
+             */
+            String TRANSFER_STATUS_COLUMN = "transfer_status";
+
+            /**
+             * The on-screen width of the file transfer, if it contains multi-media
+             */
+            String WIDTH_COLUMN = "width";
+
+            /**
+             * The on-screen height of the file transfer, if it contains multi-media
+             */
+            String HEIGHT_COLUMN = "height";
+
+            /**
+             * The duration of the content in milliseconds if this file transfer contains
+             * multi-media
+             */
+            String DURATION_MILLIS_COLUMN = "duration";
+
+            /**
+             * The URI to the preview of the content of this file transfer
+             */
+            String PREVIEW_URI_COLUMN = "preview_uri";
+
+            /**
+             * The type of the preview of the content of this file transfer. The validity of types
+             * is not enforced in {@link android.telephony.ims.RcsMessageStore} APIs.
+             */
+            String PREVIEW_TYPE_COLUMN = "preview_type";
+        }
+
+        /**
+         * The table that holds the information for
+         * {@link android.telephony.ims.RcsGroupThreadEvent} and its subclasses.
+         */
+        interface RcsThreadEventColumns {
+            /**
+             * The string used in the {@link com.android.providers.telephony.RcsProvider} URI to
+             * refer to participant joined events (example URI:
+             * {@code content://rcs/group_thread/3/participant_joined_event})
+             */
+            String PARTICIPANT_JOINED_URI_PART = "participant_joined_event";
+
+            /**
+             * The string used in the {@link com.android.providers.telephony.RcsProvider} URI to
+             * refer to participant left events. (example URI:
+             * {@code content://rcs/group_thread/3/participant_left_event/4})
+             */
+            String PARTICIPANT_LEFT_URI_PART = "participant_left_event";
+
+            /**
+             * The string used in the {@link com.android.providers.telephony.RcsProvider} URI to
+             * refer to name changed events. (example URI:
+             * {@code content://rcs/group_thread/3/name_changed_event})
+             */
+            String NAME_CHANGED_URI_PART = "name_changed_event";
+
+            /**
+             * The string used in the {@link com.android.providers.telephony.RcsProvider} URI to
+             * refer to icon changed events. (example URI:
+             * {@code content://rcs/group_thread/3/icon_changed_event})
+             */
+            String ICON_CHANGED_URI_PART = "icon_changed_event";
+
+            /**
+             * The unique ID of this event in the database, i.e. the primary key
+             */
+            String EVENT_ID_COLUMN = "event_id";
+
+            /**
+             * The type of this event
+             *
+             * @see RcsEventTypes
+             */
+            String EVENT_TYPE_COLUMN = "event_type";
+
+            /**
+             * The timestamp in milliseconds of when this event happened
+             */
+            String TIMESTAMP_COLUMN = "origination_timestamp";
+
+            /**
+             * The participant that generated this event
+             */
+            String SOURCE_PARTICIPANT_ID_COLUMN = "source_participant";
+
+            /**
+             * The receiving participant of this event if this was an
+             * {@link android.telephony.ims.RcsGroupThreadParticipantJoinedEvent} or
+             * {@link android.telephony.ims.RcsGroupThreadParticipantLeftEvent}
+             */
+            String DESTINATION_PARTICIPANT_ID_COLUMN = "destination_participant";
+
+            /**
+             * The URI for the new icon of the group thread if this was an
+             * {@link android.telephony.ims.RcsGroupThreadIconChangedEvent}
+             */
+            String NEW_ICON_URI_COLUMN = "new_icon_uri";
+
+            /**
+             * The URI for the new name of the group thread if this was an
+             * {@link android.telephony.ims.RcsGroupThreadNameChangedEvent}
+             */
+            String NEW_NAME_COLUMN = "new_name";
+        }
+
+        /**
+         * The table that {@link android.telephony.ims.RcsParticipantAliasChangedEvent} gets
+         * persisted to
+         */
+        interface RcsParticipantEventColumns {
+            /**
+             * The path that should be used for referring to
+             * {@link android.telephony.ims.RcsParticipantAliasChangedEvent}s in
+             * {@link com.android.providers.telephony.RcsProvider} URIs.
+             */
+            String ALIAS_CHANGE_EVENT_URI_PART = "alias_change_event";
+
+            /**
+             * The new alias of the participant
+             */
+            String NEW_ALIAS_COLUMN = "new_alias";
+        }
+
+        /**
+         * These values are used in {@link com.android.providers.telephony.RcsProvider} to determine
+         * what kind of event is present in the storage.
+         */
+        interface RcsEventTypes {
+            /**
+             * Integer constant that is stored in the
+             * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
+             * is of type {@link android.telephony.ims.RcsParticipantAliasChangedEvent}
+             */
+            int PARTICIPANT_ALIAS_CHANGED_EVENT_TYPE = 1;
+
+            /**
+             * Integer constant that is stored in the
+             * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
+             * is of type {@link android.telephony.ims.RcsGroupThreadParticipantJoinedEvent}
+             */
+            int PARTICIPANT_JOINED_EVENT_TYPE = 2;
+
+            /**
+             * Integer constant that is stored in the
+             * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
+             * is of type {@link android.telephony.ims.RcsGroupThreadParticipantLeftEvent}
+             */
+            int PARTICIPANT_LEFT_EVENT_TYPE = 4;
+
+            /**
+             * Integer constant that is stored in the
+             * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
+             * is of type {@link android.telephony.ims.RcsGroupThreadIconChangedEvent}
+             */
+            int ICON_CHANGED_EVENT_TYPE = 8;
+
+            /**
+             * Integer constant that is stored in the
+             * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
+             * is of type {@link android.telephony.ims.RcsGroupThreadNameChangedEvent}
+             */
+            int NAME_CHANGED_EVENT_TYPE = 16;
+        }
+
+        /**
+         * The view that allows unified querying across all events
+         */
+        interface RcsUnifiedEventHelper extends RcsParticipantEventColumns, RcsThreadEventColumns {
+            /**
+             * The path that should be used for referring to
+             * {@link android.telephony.ims.RcsEvent}s in
+             * {@link com.android.providers.telephony.RcsProvider} URIs.
+             */
+            String RCS_EVENT_QUERY_URI_PATH = "event";
+
+            /**
+             * The URI to query {@link android.telephony.ims.RcsEvent}s via the content provider.
+             */
+            Uri RCS_EVENT_QUERY_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
+                    RCS_EVENT_QUERY_URI_PATH);
+        }
+
+        /**
+         * Allows RCS specific canonical address handling.
+         */
+        interface RcsCanonicalAddressHelper {
+            /**
+             * Returns the canonical address ID for a canonical address, if now row exists, this
+             * will add a row and return its ID. This helper works against the same table used by
+             * the SMS and MMS threads, but is accessible only by the phone process for use by RCS
+             * message storage.
+             *
+             * @throws IllegalArgumentException if unable to retrieve or create the canonical
+             *                                  address entry.
+             */
+            static long getOrCreateCanonicalAddressId(
+                    ContentResolver contentResolver, String canonicalAddress) {
+
+                Uri.Builder uriBuilder = CONTENT_AND_AUTHORITY.buildUpon();
+                uriBuilder.appendPath("canonical-address");
+                uriBuilder.appendQueryParameter("address", canonicalAddress);
+                Uri uri = uriBuilder.build();
+
+                try (Cursor cursor = contentResolver.query(uri, null, null, null)) {
+                    if (cursor != null && cursor.moveToFirst()) {
+                        return cursor.getLong(cursor.getColumnIndex(CanonicalAddressesColumns._ID));
+                    } else {
+                        Rlog.e(TAG, "getOrCreateCanonicalAddressId returned no rows");
+                    }
+                }
+
+                Rlog.e(TAG, "getOrCreateCanonicalAddressId failed");
+                throw new IllegalArgumentException(
+                        "Unable to find or allocate a canonical address ID");
+            }
+        }
+    }
+
+    /**
+     * Contains all MMS messages.
+     */
+    public static final class Mms implements BaseMmsColumns {
+
+        /**
+         * Not instantiable.
+         * @hide
+         */
+        private Mms() {
+        }
+
+        /**
+         * The {@code content://} URI for this table.
+         */
+        public static final Uri CONTENT_URI = Uri.parse("content://mms");
+
+        /**
+         * Content URI for getting MMS report requests.
+         */
+        public static final Uri REPORT_REQUEST_URI = Uri.withAppendedPath(
+                                            CONTENT_URI, "report-request");
+
+        /**
+         * Content URI for getting MMS report status.
+         */
+        public static final Uri REPORT_STATUS_URI = Uri.withAppendedPath(
+                                            CONTENT_URI, "report-status");
+
+        /**
+         * The default sort order for this table.
+         */
+        public static final String DEFAULT_SORT_ORDER = "date DESC";
+
+        /**
+         * Regex pattern for names and email addresses.
+         * <ul>
+         *     <li><em>mailbox</em> = {@code name-addr}</li>
+         *     <li><em>name-addr</em> = {@code [display-name] angle-addr}</li>
+         *     <li><em>angle-addr</em> = {@code [CFWS] "<" addr-spec ">" [CFWS]}</li>
+         * </ul>
+         * @hide
+         */
+        @UnsupportedAppUsage
+        public static final Pattern NAME_ADDR_EMAIL_PATTERN =
+                Pattern.compile("\\s*(\"[^\"]*\"|[^<>\"]+)\\s*<([^<>]+)>\\s*");
+
+        /**
+         * Helper method to query this table.
+         * @hide
+         */
+        public static Cursor query(
+                ContentResolver cr, String[] projection) {
+            return cr.query(CONTENT_URI, projection, null, null, DEFAULT_SORT_ORDER);
+        }
+
+        /**
+         * Helper method to query this table.
+         * @hide
+         */
+        public static Cursor query(
+                ContentResolver cr, String[] projection,
+                String where, String orderBy) {
+            return cr.query(CONTENT_URI, projection,
+                    where, null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
+        }
+
+        /**
+         * Helper method to extract email address from address string.
+         * @hide
+         */
+        @UnsupportedAppUsage
+        public static String extractAddrSpec(String address) {
+            Matcher match = NAME_ADDR_EMAIL_PATTERN.matcher(address);
+
+            if (match.matches()) {
+                return match.group(2);
+            }
+            return address;
+        }
+
+        /**
+         * Is the specified address an email address?
+         *
+         * @param address the input address to test
+         * @return true if address is an email address; false otherwise.
+         * @hide
+         */
+        @UnsupportedAppUsage
+        public static boolean isEmailAddress(String address) {
+            if (TextUtils.isEmpty(address)) {
+                return false;
+            }
+
+            String s = extractAddrSpec(address);
+            Matcher match = Patterns.EMAIL_ADDRESS.matcher(s);
+            return match.matches();
+        }
+
+        /**
+         * Is the specified number a phone number?
+         *
+         * @param number the input number to test
+         * @return true if number is a phone number; false otherwise.
+         * @hide
+         */
+        @UnsupportedAppUsage
+        public static boolean isPhoneNumber(String number) {
+            if (TextUtils.isEmpty(number)) {
+                return false;
+            }
+
+            Matcher match = Patterns.PHONE.matcher(number);
+            return match.matches();
+        }
+
+        /**
+         * Contains all MMS messages in the MMS app inbox.
+         */
+        public static final class Inbox implements BaseMmsColumns {
+
+            /**
+             * Not instantiable.
+             * @hide
+             */
+            private Inbox() {
+            }
+
+            /**
+             * The {@code content://} style URL for this table.
+             */
+            public static final Uri
+                    CONTENT_URI = Uri.parse("content://mms/inbox");
+
+            /**
+             * The default sort order for this table.
+             */
+            public static final String DEFAULT_SORT_ORDER = "date DESC";
+        }
+
+        /**
+         * Contains all MMS messages in the MMS app sent folder.
+         */
+        public static final class Sent implements BaseMmsColumns {
+
+            /**
+             * Not instantiable.
+             * @hide
+             */
+            private Sent() {
+            }
+
+            /**
+             * The {@code content://} style URL for this table.
+             */
+            public static final Uri
+                    CONTENT_URI = Uri.parse("content://mms/sent");
+
+            /**
+             * The default sort order for this table.
+             */
+            public static final String DEFAULT_SORT_ORDER = "date DESC";
+        }
+
+        /**
+         * Contains all MMS messages in the MMS app drafts folder.
+         */
+        public static final class Draft implements BaseMmsColumns {
+
+            /**
+             * Not instantiable.
+             * @hide
+             */
+            private Draft() {
+            }
+
+            /**
+             * The {@code content://} style URL for this table.
+             */
+            public static final Uri
+                    CONTENT_URI = Uri.parse("content://mms/drafts");
+
+            /**
+             * The default sort order for this table.
+             */
+            public static final String DEFAULT_SORT_ORDER = "date DESC";
+        }
+
+        /**
+         * Contains all MMS messages in the MMS app outbox.
+         */
+        public static final class Outbox implements BaseMmsColumns {
+
+            /**
+             * Not instantiable.
+             * @hide
+             */
+            private Outbox() {
+            }
+
+            /**
+             * The {@code content://} style URL for this table.
+             */
+            public static final Uri
+                    CONTENT_URI = Uri.parse("content://mms/outbox");
+
+            /**
+             * The default sort order for this table.
+             */
+            public static final String DEFAULT_SORT_ORDER = "date DESC";
+        }
+
+        /**
+         * Contains address information for an MMS message.
+         */
+        public static final class Addr implements BaseColumns {
+
+            /**
+             * Not instantiable.
+             * @hide
+             */
+            private Addr() {
+            }
+
+            /**
+             * The ID of MM which this address entry belongs to.
+             * <P>Type: INTEGER (long)</P>
+             */
+            public static final String MSG_ID = "msg_id";
+
+            /**
+             * The ID of contact entry in Phone Book.
+             * <P>Type: INTEGER (long)</P>
+             */
+            public static final String CONTACT_ID = "contact_id";
+
+            /**
+             * The address text.
+             * <P>Type: TEXT</P>
+             */
+            public static final String ADDRESS = "address";
+
+            /**
+             * Type of address: must be one of {@code PduHeaders.BCC},
+             * {@code PduHeaders.CC}, {@code PduHeaders.FROM}, {@code PduHeaders.TO}.
+             * <P>Type: INTEGER</P>
+             */
+            public static final String TYPE = "type";
+
+            /**
+             * Character set of this entry (MMS charset value).
+             * <P>Type: INTEGER</P>
+             */
+            public static final String CHARSET = "charset";
+
+            /**
+             * Generates a Addr {@link Uri} for message, used to perform Addr table operation
+             * for mms.
+             *
+             * @param messageId the messageId used to generate Addr {@link Uri} dynamically
+             * @return the addrUri used to perform Addr table operation for mms
+             */
+            @NonNull
+            public static Uri getAddrUriForMessage(@NonNull String messageId) {
+                Uri addrUri = Mms.CONTENT_URI.buildUpon()
+                        .appendPath(String.valueOf(messageId)).appendPath("addr").build();
+                return addrUri;
+            }
+        }
+
+        /**
+         * Contains message parts.
+         *
+         * To avoid issues where applications might cache a part ID, the ID of a deleted part must
+         * not be reused to point at a new part.
+         */
+        public static final class Part implements BaseColumns {
+
+            /**
+             * Not instantiable.
+             * @hide
+             */
+            private Part() {
+            }
+
+            /**
+             * The name of part table.
+             */
+            private static final String TABLE_PART = "part";
+
+            /**
+             * The {@code content://} style URL for this table. Can be appended with a part ID to
+             * address individual parts.
+             */
+            @NonNull
+            public static final Uri CONTENT_URI = Uri.withAppendedPath(Mms.CONTENT_URI, TABLE_PART);
+
+            /**
+             * The identifier of the message which this part belongs to.
+             * <P>Type: INTEGER</P>
+             */
+            public static final String MSG_ID = "mid";
+
+            /**
+             * The order of the part.
+             * <P>Type: INTEGER</P>
+             */
+            public static final String SEQ = "seq";
+
+            /**
+             * The content type of the part.
+             * <P>Type: TEXT</P>
+             */
+            public static final String CONTENT_TYPE = "ct";
+
+            /**
+             * The name of the part.
+             * <P>Type: TEXT</P>
+             */
+            public static final String NAME = "name";
+
+            /**
+             * The charset of the part.
+             * <P>Type: TEXT</P>
+             */
+            public static final String CHARSET = "chset";
+
+            /**
+             * The file name of the part.
+             * <P>Type: TEXT</P>
+             */
+            public static final String FILENAME = "fn";
+
+            /**
+             * The content disposition of the part.
+             * <P>Type: TEXT</P>
+             */
+            public static final String CONTENT_DISPOSITION = "cd";
+
+            /**
+             * The content ID of the part.
+             * <P>Type: INTEGER</P>
+             */
+            public static final String CONTENT_ID = "cid";
+
+            /**
+             * The content location of the part.
+             * <P>Type: INTEGER</P>
+             */
+            public static final String CONTENT_LOCATION = "cl";
+
+            /**
+             * The start of content-type of the message.
+             * <P>Type: INTEGER</P>
+             */
+            public static final String CT_START = "ctt_s";
+
+            /**
+             * The type of content-type of the message.
+             * <P>Type: TEXT</P>
+             */
+            public static final String CT_TYPE = "ctt_t";
+
+            /**
+             * The location (on filesystem) of the binary data of the part.
+             * <P>Type: INTEGER</P>
+             */
+            public static final String _DATA = "_data";
+
+            /**
+             * The message text.
+             * <P>Type: TEXT</P>
+             */
+            public static final String TEXT = "text";
+
+            /**
+             * Generates a Part {@link Uri} for message, used to perform Part table operation
+             * for mms.
+             *
+             * @param messageId the messageId used to generate Part {@link Uri} dynamically
+             * @return the partUri used to perform Part table operation for mms
+             */
+            @NonNull
+            public static Uri getPartUriForMessage(@NonNull String messageId) {
+                Uri partUri = Mms.CONTENT_URI.buildUpon()
+                        .appendPath(String.valueOf(messageId)).appendPath(
+                                TABLE_PART).build();
+                return partUri;
+            }
+        }
+
+        /**
+         * Message send rate table.
+         */
+        public static final class Rate {
+
+            /**
+             * Not instantiable.
+             * @hide
+             */
+            private Rate() {
+            }
+
+            /**
+             * The {@code content://} style URL for this table.
+             */
+            public static final Uri CONTENT_URI = Uri.withAppendedPath(
+                    Mms.CONTENT_URI, "rate");
+
+            /**
+             * When a message was successfully sent.
+             * <P>Type: INTEGER (long)</P>
+             */
+            public static final String SENT_TIME = "sent_time";
+        }
+
+        /**
+         * Intents class.
+         */
+        public static final class Intents {
+
+            /**
+             * Not instantiable.
+             * @hide
+             */
+            private Intents() {
+            }
+
+            /**
+             * Indicates that the contents of specified URIs were changed.
+             * The application which is showing or caching these contents
+             * should be updated.
+             */
+            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+            public static final String CONTENT_CHANGED_ACTION
+                    = "android.intent.action.CONTENT_CHANGED";
+
+            /**
+             * An extra field which stores the URI of deleted contents.
+             */
+            public static final String DELETED_CONTENTS = "deleted_contents";
+        }
+    }
+
+    /**
+     * Contains all MMS and SMS messages.
+     */
+    public static final class MmsSms implements BaseColumns {
+
+        /**
+         * Not instantiable.
+         * @hide
+         */
+        private MmsSms() {
+        }
+
+        /**
+         * The column to distinguish SMS and MMS messages in query results.
+         */
+        public static final String TYPE_DISCRIMINATOR_COLUMN =
+                "transport_type";
+
+        /**
+         * The {@code content://} style URL for this table.
+         */
+        public static final Uri CONTENT_URI = Uri.parse("content://mms-sms/");
+
+        /**
+         * The {@code content://} style URL for this table, by conversation.
+         */
+        public static final Uri CONTENT_CONVERSATIONS_URI = Uri.parse(
+                "content://mms-sms/conversations");
+
+        /**
+         * The {@code content://} style URL for this table, by phone number.
+         */
+        public static final Uri CONTENT_FILTER_BYPHONE_URI = Uri.parse(
+                "content://mms-sms/messages/byphone");
+
+        /**
+         * The {@code content://} style URL for undelivered messages in this table.
+         */
+        public static final Uri CONTENT_UNDELIVERED_URI = Uri.parse(
+                "content://mms-sms/undelivered");
+
+        /**
+         * The {@code content://} style URL for draft messages in this table.
+         */
+        public static final Uri CONTENT_DRAFT_URI = Uri.parse(
+                "content://mms-sms/draft");
+
+        /**
+         * The {@code content://} style URL for locked messages in this table.
+         * <P>This {@link Uri} is used to check at most one locked message found in the union of MMS
+         * and SMS messages. Also this will return only _id column in response.</P>
+         */
+        public static final Uri CONTENT_LOCKED_URI = Uri.parse(
+                "content://mms-sms/locked");
+
+        /**
+         * Pass in a query parameter called "pattern" which is the text to search for.
+         * The sort order is fixed to be: {@code thread_id ASC, date DESC}.
+         */
+        public static final Uri SEARCH_URI = Uri.parse(
+                "content://mms-sms/search");
+
+        // Constants for message protocol types.
+
+        /** SMS protocol type. */
+        public static final int SMS_PROTO = 0;
+
+        /** MMS protocol type. */
+        public static final int MMS_PROTO = 1;
+
+        // Constants for error types of pending messages.
+
+        /** Error type: no error. */
+        public static final int NO_ERROR                      = 0;
+
+        /** Error type: generic transient error. */
+        public static final int ERR_TYPE_GENERIC              = 1;
+
+        /** Error type: SMS protocol transient error. */
+        public static final int ERR_TYPE_SMS_PROTO_TRANSIENT  = 2;
+
+        /** Error type: MMS protocol transient error. */
+        public static final int ERR_TYPE_MMS_PROTO_TRANSIENT  = 3;
+
+        /** Error type: transport failure. */
+        public static final int ERR_TYPE_TRANSPORT_FAILURE    = 4;
+
+        /** Error type: permanent error (along with all higher error values). */
+        public static final int ERR_TYPE_GENERIC_PERMANENT    = 10;
+
+        /** Error type: SMS protocol permanent error. */
+        public static final int ERR_TYPE_SMS_PROTO_PERMANENT  = 11;
+
+        /** Error type: MMS protocol permanent error. */
+        public static final int ERR_TYPE_MMS_PROTO_PERMANENT  = 12;
+
+        /**
+         * Contains pending messages info.
+         */
+        public static final class PendingMessages implements BaseColumns {
+
+            /**
+             * Not instantiable.
+             * @hide
+             */
+            private PendingMessages() {
+            }
+
+            public static final Uri CONTENT_URI = Uri.withAppendedPath(
+                    MmsSms.CONTENT_URI, "pending");
+
+            /**
+             * The type of transport protocol (MMS or SMS).
+             * <P>Type: INTEGER</P>
+             */
+            public static final String PROTO_TYPE = "proto_type";
+
+            /**
+             * The ID of the message to be sent or downloaded.
+             * <P>Type: INTEGER (long)</P>
+             */
+            public static final String MSG_ID = "msg_id";
+
+            /**
+             * The type of the message to be sent or downloaded.
+             * This field is only valid for MM. For SM, its value is always set to 0.
+             * <P>Type: INTEGER</P>
+             */
+            public static final String MSG_TYPE = "msg_type";
+
+            /**
+             * The type of the error code.
+             * <P>Type: INTEGER</P>
+             */
+            public static final String ERROR_TYPE = "err_type";
+
+            /**
+             * The error code of sending/retrieving process.
+             * <P>Type: INTEGER</P>
+             */
+            public static final String ERROR_CODE = "err_code";
+
+            /**
+             * How many times we tried to send or download the message.
+             * <P>Type: INTEGER</P>
+             */
+            public static final String RETRY_INDEX = "retry_index";
+
+            /**
+             * The time to do next retry.
+             * <P>Type: INTEGER (long)</P>
+             */
+            public static final String DUE_TIME = "due_time";
+
+            /**
+             * The time we last tried to send or download the message.
+             * <P>Type: INTEGER (long)</P>
+             */
+            public static final String LAST_TRY = "last_try";
+
+            /**
+             * The subscription to which the message belongs to. Its value will be
+             * < 0 if the sub id cannot be determined.
+             * <p>Type: INTEGER (long) </p>
+             */
+            public static final String SUBSCRIPTION_ID = "pending_sub_id";
+        }
+
+        /**
+         * Words table used by provider for full-text searches.
+         * @hide
+         */
+        public static final class WordsTable {
+
+            /**
+             * Not instantiable.
+             * @hide
+             */
+            private WordsTable() {}
+
+            /**
+             * Primary key.
+             * <P>Type: INTEGER (long)</P>
+             */
+            public static final String ID = "_id";
+
+            /**
+             * Source row ID.
+             * <P>Type: INTEGER (long)</P>
+             */
+            public static final String SOURCE_ROW_ID = "source_id";
+
+            /**
+             * Table ID (either 1 or 2).
+             * <P>Type: INTEGER</P>
+             */
+            public static final String TABLE_ID = "table_to_use";
+
+            /**
+             * The words to index.
+             * <P>Type: TEXT</P>
+             */
+            public static final String INDEXED_TEXT = "index_text";
+        }
+    }
+
+    /**
+     * Carriers class contains information about APNs, including MMSC information.
+     */
+    public static final class Carriers implements BaseColumns {
+
+        /**
+         * Not instantiable.
+         * @hide
+         */
+        private Carriers() {}
+
+        /**
+         * The {@code content://} style URL for this table.
+         * For MSIM, this will return APNs for the default subscription
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}. To specify subId for MSIM,
+         * use {@link Uri#withAppendedPath(Uri, String)} to append with subscription id.
+         */
+        @NonNull
+        public static final Uri CONTENT_URI = Uri.parse("content://telephony/carriers");
+
+        /**
+         * The {@code content://} style URL for this table. Used for APN query based on current
+         * subscription. Instead of specifying carrier matching information in the selection,
+         * this API will return all matching APNs from current subscription carrier and queries
+         * will be applied on top of that. If there is no match for MVNO (Mobile Virtual Network
+         * Operator) APNs, return APNs from its MNO (based on mccmnc) instead. For MSIM, this will
+         * return APNs for the default subscription
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}. To specify subId for MSIM,
+         * use {@link Uri#withAppendedPath(Uri, String)} to append with subscription id.
+         */
+        @NonNull
+        public static final Uri SIM_APN_URI = Uri.parse(
+                "content://telephony/carriers/sim_apn_list");
+
+        /**
+         * The {@code content://} style URL to be called from DevicePolicyManagerService,
+         * can manage DPC-owned APNs.
+         * @hide
+         */
+        public static final Uri DPC_URI = Uri.parse("content://telephony/carriers/dpc");
+
+        /**
+         * The {@code content://} style URL to be called from Telephony to query APNs.
+         * When DPC-owned APNs are enforced, only DPC-owned APNs are returned, otherwise only
+         * non-DPC-owned APNs are returned. For MSIM, this will return APNs for the default
+         * subscription {@link SubscriptionManager#getDefaultSubscriptionId()}. To specify subId
+         * for MSIM, use {@link Uri#withAppendedPath(Uri, String)} to append with subscription id.
+         * @hide
+         */
+        public static final Uri FILTERED_URI = Uri.parse("content://telephony/carriers/filtered");
+
+        /**
+         * The {@code content://} style URL to be called from DevicePolicyManagerService
+         * or Telephony to manage whether DPC-owned APNs are enforced.
+         * @hide
+         */
+        public static final Uri ENFORCE_MANAGED_URI = Uri.parse(
+                "content://telephony/carriers/enforce_managed");
+
+        /**
+         * The column name for ENFORCE_MANAGED_URI, indicates whether DPC-owned APNs are enforced.
+         * @hide
+         */
+        public static final String ENFORCE_KEY = "enforced";
+
+        /**
+         * The default sort order for this table.
+         */
+        public static final String DEFAULT_SORT_ORDER = "name ASC";
+
+        /**
+         * Entry name.
+         * <P>Type: TEXT</P>
+         */
+        public static final String NAME = "name";
+
+        /**
+         * APN name.
+         * <P>Type: TEXT</P>
+         */
+        public static final String APN = "apn";
+
+        /**
+         * Proxy address.
+         * <P>Type: TEXT</P>
+         */
+        public static final String PROXY = "proxy";
+
+        /**
+         * Proxy port.
+         * <P>Type: TEXT</P>
+         */
+        public static final String PORT = "port";
+
+        /**
+         * MMS proxy address.
+         * <P>Type: TEXT</P>
+         */
+        public static final String MMSPROXY = "mmsproxy";
+
+        /**
+         * MMS proxy port.
+         * <P>Type: TEXT</P>
+         */
+        public static final String MMSPORT = "mmsport";
+
+        /**
+         * Server address.
+         * <P>Type: TEXT</P>
+         */
+        public static final String SERVER = "server";
+
+        /**
+         * APN username.
+         * <P>Type: TEXT</P>
+         */
+        public static final String USER = "user";
+
+        /**
+         * APN password.
+         * <P>Type: TEXT</P>
+         */
+        public static final String PASSWORD = "password";
+
+        /**
+         * MMSC URL.
+         * <P>Type: TEXT</P>
+         */
+        public static final String MMSC = "mmsc";
+
+        /**
+         * Mobile Country Code (MCC).
+         * <P>Type: TEXT</P>
+         * @deprecated Use {@link #SIM_APN_URI} to query APN instead, this API will return
+         * matching APNs based on current subscription carrier, thus no need to specify MCC and
+         * other carrier matching information. In the future, Android will not support MCC for
+         * APN query.
+         */
+        public static final String MCC = "mcc";
+
+        /**
+         * Mobile Network Code (MNC).
+         * <P>Type: TEXT</P>
+         * @deprecated Use {@link #SIM_APN_URI} to query APN instead, this API will return
+         * matching APNs based on current subscription carrier, thus no need to specify MNC and
+         * other carrier matching information. In the future, Android will not support MNC for
+         * APN query.
+         */
+        public static final String MNC = "mnc";
+
+        /**
+         * Numeric operator ID (as String). Usually {@code MCC + MNC}.
+         * <P>Type: TEXT</P>
+         * @deprecated Use {@link #SIM_APN_URI} to query APN instead, this API will return
+         * matching APNs based on current subscription carrier, thus no need to specify Numeric
+         * and other carrier matching information. In the future, Android will not support Numeric
+         * for APN query.
+         */
+        public static final String NUMERIC = "numeric";
+
+        /**
+         * Authentication type.
+         * <P>Type:  INTEGER</P>
+         */
+        public static final String AUTH_TYPE = "authtype";
+
+        /**
+         * Comma-delimited list of APN types.
+         * <P>Type: TEXT</P>
+         */
+        public static final String TYPE = "type";
+
+        /**
+         * The protocol to use to connect to this APN.
+         *
+         * One of the {@code PDP_type} values in TS 27.007 section 10.1.1.
+         * For example: {@code IP}, {@code IPV6}, {@code IPV4V6}, or {@code PPP}.
+         * <P>Type: TEXT</P>
+         */
+        public static final String PROTOCOL = "protocol";
+
+        /**
+         * The protocol to use to connect to this APN when roaming.
+         * The syntax is the same as protocol.
+         * <P>Type: TEXT</P>
+         */
+        public static final String ROAMING_PROTOCOL = "roaming_protocol";
+
+        /**
+         * Is this the current APN?
+         * <P>Type: INTEGER (boolean)</P>
+         */
+        public static final String CURRENT = "current";
+
+        /**
+         * Is this APN enabled?
+         * <P>Type: INTEGER (boolean)</P>
+         */
+        public static final String CARRIER_ENABLED = "carrier_enabled";
+
+        /**
+         * Radio Access Technology info.
+         * To check what values are allowed, refer to {@link android.telephony.ServiceState}.
+         * This should be spread to other technologies,
+         * but is currently only used for LTE (14) and eHRPD (13).
+         * <P>Type: INTEGER</P>
+         * @deprecated this column is no longer supported, use {@link #NETWORK_TYPE_BITMASK} instead
+         */
+        @Deprecated
+        public static final String BEARER = "bearer";
+
+        /**
+         * Radio Access Technology bitmask.
+         * To check what values can be contained, refer to {@link android.telephony.ServiceState}.
+         * 0 indicates all techs otherwise first bit refers to RAT/bearer 1, second bit refers to
+         * RAT/bearer 2 and so on.
+         * Bitmask for a radio tech R is (1 << (R - 1))
+         * <P>Type: INTEGER</P>
+         * @hide
+         * @deprecated this column is no longer supported, use {@link #NETWORK_TYPE_BITMASK} instead
+         */
+        @Deprecated
+        public static final String BEARER_BITMASK = "bearer_bitmask";
+
+        /**
+         * Radio technology (network type) bitmask.
+         * To check what values can be contained, refer to the NETWORK_TYPE_ constants in
+         * {@link android.telephony.TelephonyManager}.
+         * Bitmask for a radio tech R is (1 << (R - 1))
+         * <P>Type: INTEGER</P>
+         */
+        public static final String NETWORK_TYPE_BITMASK = "network_type_bitmask";
+
+        /**
+         * MVNO type:
+         * {@code SPN (Service Provider Name), IMSI, GID (Group Identifier Level 1)}.
+         * <P>Type: TEXT</P>
+         * @deprecated Use {@link #SIM_APN_URI} to query APN instead, this API will return
+         * matching APNs based on current subscription carrier, thus no need to specify MVNO_TYPE
+         * and other carrier matching information. In the future, Android will not support MVNO_TYPE
+         * for APN query.
+         */
+        public static final String MVNO_TYPE = "mvno_type";
+
+        /**
+         * MVNO data.
+         * Use the following examples.
+         * <ul>
+         *     <li>SPN: A MOBILE, BEN NL, ...</li>
+         *     <li>IMSI: 302720x94, 2060188, ...</li>
+         *     <li>GID: 4E, 33, ...</li>
+         * </ul>
+         * <P>Type: TEXT</P>
+         * @deprecated Use {@link #SIM_APN_URI} to query APN instead, this API will return
+         * matching APNs based on current subscription carrier, thus no need to specify
+         * MVNO_MATCH_DATA and other carrier matching information. In the future, Android will not
+         * support MVNO_MATCH_DATA for APN query.
+         */
+        public static final String MVNO_MATCH_DATA = "mvno_match_data";
+
+        /**
+         * The subscription to which the APN belongs to
+         * <p>Type: INTEGER (long) </p>
+         */
+        public static final String SUBSCRIPTION_ID = "sub_id";
+
+        /**
+         * The profile_id to which the APN saved in modem.
+         * <p>Type: INTEGER</p>
+         *@hide
+         */
+        public static final String PROFILE_ID = "profile_id";
+
+        /**
+         * If set to {@code true}, then the APN setting will persist to the modem.
+         * <p>Type: INTEGER (boolean)</p>
+         *@hide
+         */
+        @SystemApi
+        public static final String MODEM_PERSIST = "modem_cognitive";
+
+        /**
+         * The max number of connections of this APN.
+         * <p>Type: INTEGER</p>
+         *@hide
+         */
+        @SystemApi
+        public static final String MAX_CONNECTIONS = "max_conns";
+
+        /**
+         * The wait time for retrying the APN, in milliseconds.
+         * <p>Type: INTEGER</p>
+         *@hide
+         */
+        @SystemApi
+        public static final String WAIT_TIME_RETRY = "wait_time";
+
+        /**
+         * The max number of seconds this APN will support its maximum number of connections
+         * as defined in {@link #MAX_CONNECTIONS}.
+         * <p>Type: INTEGER</p>
+         *@hide
+         */
+        @SystemApi
+        public static final String TIME_LIMIT_FOR_MAX_CONNECTIONS = "max_conns_time";
+
+        /**
+         * The MTU (maximum transmit unit) size of the mobile interface to which the APN is
+         * connected, in bytes.
+         * <p>Type: INTEGER </p>
+         * @hide
+         */
+        @SystemApi
+        public static final String MTU = "mtu";
+
+        /**
+         * APN edit status. APN could be added/edited/deleted by a user or carrier.
+         * see all possible returned APN edit status.
+         * <ul>
+         *     <li>{@link #UNEDITED}</li>
+         *     <li>{@link #USER_EDITED}</li>
+         *     <li>{@link #USER_DELETED}</li>
+         *     <li>{@link #CARRIER_EDITED}</li>
+         *     <li>{@link #CARRIER_DELETED}</li>
+         * </ul>
+         * <p>Type: INTEGER </p>
+         * @hide
+         */
+        @SystemApi
+        public static final String EDITED_STATUS = "edited";
+
+        /**
+         * {@code true} if this APN visible to the user, {@code false} otherwise.
+         * <p>Type: INTEGER (boolean)</p>
+         * @hide
+         */
+        @SystemApi
+        public static final String USER_VISIBLE = "user_visible";
+
+        /**
+         * {@code true} if the user allowed to edit this APN, {@code false} otherwise.
+         * <p>Type: INTEGER (boolean)</p>
+         * @hide
+         */
+        @SystemApi
+        public static final String USER_EDITABLE = "user_editable";
+
+        /**
+         * {@link #EDITED_STATUS APN edit status} indicates that this APN has not been edited or
+         * fails to edit.
+         * <p>Type: INTEGER </p>
+         * @hide
+         */
+        @SystemApi
+        public static final @EditStatus int UNEDITED = 0;
+
+        /**
+         * {@link #EDITED_STATUS APN edit status} indicates that this APN has been edited by users.
+         * <p>Type: INTEGER </p>
+         * @hide
+         */
+        @SystemApi
+        public static final @EditStatus int USER_EDITED = 1;
+
+        /**
+         * {@link #EDITED_STATUS APN edit status} indicates that this APN has been deleted by users.
+         * <p>Type: INTEGER </p>
+         * @hide
+         */
+        @SystemApi
+        public static final @EditStatus int USER_DELETED = 2;
+
+        /**
+         * {@link #EDITED_STATUS APN edit status} is an intermediate value used to indicate that an
+         * entry deleted by the user is still present in the new APN database and therefore must
+         * remain tagged as user deleted rather than completely removed from the database.
+         * @hide
+         */
+        public static final int USER_DELETED_BUT_PRESENT_IN_XML = 3;
+
+        /**
+         * {@link #EDITED_STATUS APN edit status} indicates that this APN has been edited by
+         * carriers.
+         * <p>Type: INTEGER </p>
+         * @hide
+         */
+        @SystemApi
+        public static final @EditStatus int CARRIER_EDITED = 4;
+
+        /**
+         * {@link #EDITED_STATUS APN edit status} indicates that this APN has been deleted by
+         * carriers. CARRIER_DELETED values are currently not used as there is no use case.
+         * If they are used, delete() will have to change accordingly. Currently it is hardcoded to
+         * USER_DELETED.
+         * <p>Type: INTEGER </p>
+         * @hide
+         */
+        public static final @EditStatus int CARRIER_DELETED = 5;
+
+        /**
+         * {@link #EDITED_STATUS APN edit status} is an intermediate value used to indicate that an
+         * entry deleted by the carrier is still present in the new APN database and therefore must
+         * remain tagged as user deleted rather than completely removed from the database.
+         * @hide
+         */
+        public static final int CARRIER_DELETED_BUT_PRESENT_IN_XML = 6;
+
+        /**
+         * The owner of the APN.
+         * <p>Type: INTEGER</p>
+         * @hide
+         */
+        public static final String OWNED_BY = "owned_by";
+
+        /**
+         * Possible value for the OWNED_BY field.
+         * APN is owned by DPC.
+         * @hide
+         */
+        public static final int OWNED_BY_DPC = 0;
+
+        /**
+         * Possible value for the OWNED_BY field.
+         * APN is owned by other sources.
+         * @hide
+         */
+        public static final int OWNED_BY_OTHERS = 1;
+
+        /**
+         * The APN set id. When the user manually selects an APN or the framework sets an APN as
+         * preferred, all APNs with the same set id as the selected APN should be prioritized over
+         * APNs in other sets.
+         * <p>Type: INTEGER</p>
+         * @hide
+         */
+        @SystemApi
+        public static final String APN_SET_ID = "apn_set_id";
+
+        /**
+         * Possible value for the {@link #APN_SET_ID} field. By default APNs will not belong to a
+         * set. If the user manually selects an APN without apn set id, there is no need to
+         * prioritize any specific APN set ids.
+         * <p>Type: INTEGER</p>
+         * @hide
+         */
+        @SystemApi
+        public static final int NO_APN_SET_ID = 0;
+
+        /**
+         * A unique carrier id associated with this APN
+         * {@see TelephonyManager#getSimCarrierId()}
+         * <p>Type: STRING</p>
+         */
+        public static final String CARRIER_ID = "carrier_id";
+
+        /**
+         * The skip 464xlat flag. Flag works as follows.
+         * {@link #SKIP_464XLAT_DEFAULT}: the APN will skip only APN is IMS and no internet.
+         * {@link #SKIP_464XLAT_DISABLE}: the APN will NOT skip 464xlat
+         * {@link #SKIP_464XLAT_ENABLE}: the APN will skip 464xlat
+         * <p>Type: INTEGER</p>
+         *
+         * @hide
+         */
+        public static final String SKIP_464XLAT = "skip_464xlat";
+
+        /**
+         * Possible value for the {@link #SKIP_464XLAT} field.
+         * <p>Type: INTEGER</p>
+         *
+         * @hide
+         */
+        public static final int SKIP_464XLAT_DEFAULT = -1;
+
+        /**
+         * Possible value for the {@link #SKIP_464XLAT} field.
+         * <p>Type: INTEGER</p>
+         *
+         * @hide
+         */
+        public static final int SKIP_464XLAT_DISABLE = 0;
+
+        /**
+         * Possible value for the {@link #SKIP_464XLAT} field.
+         * <p>Type: INTEGER</p>
+         *
+         * @hide
+         */
+        public static final int SKIP_464XLAT_ENABLE = 1;
+
+
+        /** @hide */
+        @IntDef({
+                UNEDITED,
+                USER_EDITED,
+                USER_DELETED,
+                CARRIER_DELETED,
+                CARRIER_EDITED,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface EditStatus {}
+
+        /** @hide */
+        @IntDef({
+                SKIP_464XLAT_DEFAULT,
+                SKIP_464XLAT_DISABLE,
+                SKIP_464XLAT_ENABLE,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface Skip464XlatStatus {}
+
+    }
+
+    /**
+     * Contains received cell broadcast messages. More details are available in 3GPP TS 23.041.
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public static final class CellBroadcasts implements BaseColumns {
+
+        /**
+         * Not instantiable.
+         * @hide
+         */
+        private CellBroadcasts() {}
+
+        /**
+         * The {@code content://} URI for this table.
+         * Only privileged framework components running on phone or network stack uid can
+         * query or modify this table.
+         */
+        @NonNull
+        public static final Uri CONTENT_URI = Uri.parse("content://cellbroadcasts");
+
+        /**
+         * The {@code content://} URI for query cellbroadcast message history.
+         * query results include following entries
+         * <ul>
+         *     <li>{@link #_ID}</li>
+         *     <li>{@link #SLOT_INDEX}</li>
+         *     <li>{@link #GEOGRAPHICAL_SCOPE}</li>
+         *     <li>{@link #PLMN}</li>
+         *     <li>{@link #LAC}</li>
+         *     <li>{@link #CID}</li>
+         *     <li>{@link #SERIAL_NUMBER}</li>
+         *     <li>{@link #SERVICE_CATEGORY}</li>
+         *     <li>{@link #LANGUAGE_CODE}</li>
+         *     <li>{@link #MESSAGE_BODY}</li>
+         *     <li>{@link #DELIVERY_TIME}</li>
+         *     <li>{@link #MESSAGE_READ}</li>
+         *     <li>{@link #MESSAGE_FORMAT}</li>
+         *     <li>{@link #MESSAGE_PRIORITY}</li>
+         *     <li>{@link #ETWS_WARNING_TYPE}</li>
+         *     <li>{@link #CMAS_MESSAGE_CLASS}</li>
+         *     <li>{@link #CMAS_CATEGORY}</li>
+         *     <li>{@link #CMAS_RESPONSE_TYPE}</li>
+         *     <li>{@link #CMAS_SEVERITY}</li>
+         *     <li>{@link #CMAS_URGENCY}</li>
+         *     <li>{@link #CMAS_CERTAINTY}</li>
+         * </ul>
+         */
+        @RequiresPermission(Manifest.permission.READ_CELL_BROADCASTS)
+        @NonNull
+        public static final Uri MESSAGE_HISTORY_URI = Uri.parse("content://cellbroadcasts/history");
+
+        /**
+         * The subscription which received this cell broadcast message.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String SUB_ID = "sub_id";
+
+        /**
+         * The slot which received this cell broadcast message.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String SLOT_INDEX = "slot_index";
+
+        /**
+         * Message geographical scope. Valid values are:
+         * <ul>
+         * <li>{@link android.telephony.SmsCbMessage#GEOGRAPHICAL_SCOPE_CELL_WIDE}. meaning the
+         * message is for the radio service cell</li>
+         * <li>{@link android.telephony.SmsCbMessage#GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE},
+         * meaning the message is for the radio service cell and immediately displayed</li>
+         * <li>{@link android.telephony.SmsCbMessage#GEOGRAPHICAL_SCOPE_PLMN_WIDE}, meaning the
+         * message is for the PLMN (i.e. MCC/MNC)</li>
+         * <li>{@link android.telephony.SmsCbMessage#GEOGRAPHICAL_SCOPE_LOCATION_AREA_WIDE},
+         * meaning the message is for the location area (in GSM) or service area (in UMTS)</li>
+         * </ul>
+         *
+         * <p>A message meant for a particular scope is automatically dismissed when the device
+         * exits that scope.</p>
+         * <P>Type: INTEGER</P>
+         */
+        public static final String GEOGRAPHICAL_SCOPE = "geo_scope";
+
+        /**
+         * Message serial number.
+         * <p>
+         * A 16-bit integer which identifies a particular CBS (cell
+         * broadcast short message service) message. The core network is responsible for
+         * allocating this value, and the value may be managed cyclically (3GPP TS 23.041 section
+         * 9.2.1) once the serial message has been incremented a sufficient number of times.
+         * </p>
+         * <P>Type: INTEGER</P>
+         */
+        public static final String SERIAL_NUMBER = "serial_number";
+
+        /**
+         * PLMN (i.e. MCC/MNC) of broadcast sender. {@code SERIAL_NUMBER + PLMN + LAC + CID}
+         * uniquely identifies a broadcast for duplicate detection purposes.
+         * <P>Type: TEXT</P>
+         */
+        public static final String PLMN = "plmn";
+
+        /**
+         * Location area code (LAC).
+         * <p>Code representing location area (GSM) or service area (UMTS) of broadcast sender.
+         * Unused for CDMA. Only included if Geographical Scope of message is not PLMN wide (01).
+         * This value is sent by the network based on the cell tower.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String LAC = "lac";
+
+        /**
+         * Cell ID of message sender (GSM/UMTS). Unused for CDMA. Only included when the
+         * Geographical Scope of message is cell wide (00 or 11).
+         * <P>Type: INTEGER</P>
+         */
+        public static final String CID = "cid";
+
+        /**
+         * Service category which represents the general topic of the message.
+         * <p>
+         * For GSM/UMTS: message identifier (see 3GPP TS 23.041 section 9.4.1.2.2)
+         * For CDMA: a 16-bit CDMA service category (see 3GPP2 C.R1001-D section 9.3)
+         * </p>
+         * <P>Type: INTEGER</P>
+         */
+        public static final String SERVICE_CATEGORY = "service_category";
+
+        /**
+         * Message language code. (See 3GPP TS 23.041 section 9.4.1.2.3 for details).
+         * <P>Type: TEXT</P>
+         */
+        public static final String LANGUAGE_CODE = "language";
+
+        /**
+         * Message body.
+         * <P>Type: TEXT</P>
+         */
+        public static final String MESSAGE_BODY = "body";
+
+        /**
+         * Message delivery time.
+         * <p>This value is a system timestamp using {@link System#currentTimeMillis}</p>
+         * <P>Type: INTEGER (long)</P>
+         */
+        public static final String DELIVERY_TIME = "date";
+
+        /**
+         * Has the message been viewed?
+         * <P>Type: INTEGER (boolean)</P>
+         */
+        public static final String MESSAGE_READ = "read";
+
+        /**
+         * Message format ({@link android.telephony.SmsCbMessage#MESSAGE_FORMAT_3GPP} or
+         * {@link android.telephony.SmsCbMessage#MESSAGE_FORMAT_3GPP2}).
+         * <P>Type: INTEGER</P>
+         */
+        public static final String MESSAGE_FORMAT = "format";
+
+        /**
+         * Message priority.
+         * <p>This includes
+         * <ul>
+         * <li>{@link android.telephony.SmsCbMessage#MESSAGE_PRIORITY_NORMAL}</li>
+         * <li>{@link android.telephony.SmsCbMessage#MESSAGE_PRIORITY_INTERACTIVE}</li>
+         * <li>{@link android.telephony.SmsCbMessage#MESSAGE_PRIORITY_URGENT}</li>
+         * <li>{@link android.telephony.SmsCbMessage#MESSAGE_PRIORITY_EMERGENCY}</li>
+         * </p>
+         * </ul>
+         * <P>Type: INTEGER</P>
+         */
+        public static final String MESSAGE_PRIORITY = "priority";
+
+        /**
+         * ETWS (Earthquake and Tsunami Warning System) warning type (ETWS alerts only).
+         * <p>See {@link android.telephony.SmsCbEtwsInfo}</p>
+         * <P>Type: INTEGER</P>
+         */
+        public static final String ETWS_WARNING_TYPE = "etws_warning_type";
+
+        /**
+         * CMAS (Commercial Mobile Alert System) message class (CMAS alerts only).
+         * <p>See {@link android.telephony.SmsCbCmasInfo}</p>
+         * <P>Type: INTEGER</P>
+         */
+        public static final String CMAS_MESSAGE_CLASS = "cmas_message_class";
+
+        /**
+         * CMAS category (CMAS alerts only).
+         * <P>Type: INTEGER</P>
+         */
+        public static final String CMAS_CATEGORY = "cmas_category";
+
+        /**
+         * CMAS response type (CMAS alerts only).
+         * <P>Type: INTEGER</P>
+         */
+        public static final String CMAS_RESPONSE_TYPE = "cmas_response_type";
+
+        /**
+         * CMAS severity (CMAS alerts only).
+         * <P>Type: INTEGER</P>
+         */
+        public static final String CMAS_SEVERITY = "cmas_severity";
+
+        /**
+         * CMAS urgency (CMAS alerts only).
+         * <P>Type: INTEGER</P>
+         */
+        public static final String CMAS_URGENCY = "cmas_urgency";
+
+        /**
+         * CMAS certainty (CMAS alerts only).
+         * <P>Type: INTEGER</P>
+         */
+        public static final String CMAS_CERTAINTY = "cmas_certainty";
+
+        /** The default sort order for this table. */
+        public static final String DEFAULT_SORT_ORDER = DELIVERY_TIME + " DESC";
+
+        /**
+         * The timestamp in millisecond of when the device received the message.
+         * <P>Type: BIGINT</P>
+         */
+        public static final String RECEIVED_TIME = "received_time";
+
+        /**
+         * Indicates that whether the message has been broadcasted to the application.
+         * <P>Type: BOOLEAN</P>
+         */
+        public static final String MESSAGE_BROADCASTED = "message_broadcasted";
+
+        /**
+         * The Warning Area Coordinates Elements. This element is used for geo-fencing purpose.
+         *
+         * The geometry and its coordinates are separated vertical bar, the first item is the
+         * geometry type and the remaining items are the parameter of this geometry.
+         *
+         * Only circle and polygon are supported. The coordinates are represented in Horizontal
+         * coordinates format.
+         *
+         * Coordinate encoding:
+         * "latitude, longitude"
+         * where -90.00000 <= latitude <= 90.00000 and -180.00000 <= longitude <= 180.00000
+         *
+         * Polygon encoding:
+         * "polygon|lat1,lng1|lat2,lng2|...|latn,lngn"
+         * lat1,lng1 ... latn,lngn are the vertices coordinate of the polygon.
+         *
+         * Circle encoding:
+         * "circle|lat,lng|radius".
+         * lat,lng is the center of the circle. The unit of circle's radius is meter.
+         *
+         * Example:
+         * "circle|0,0|100" mean a circle which center located at (0,0) and its radius is 100 meter.
+         * "polygon|0,1.5|0,1|1,1|1,0" mean a polygon has vertices (0,1.5),(0,1),(1,1),(1,0).
+         *
+         * There could be more than one geometry store in this field, they are separated by a
+         * semicolon.
+         *
+         * Example:
+         * "circle|0,0|100;polygon|0,0|0,1.5|1,1|1,0;circle|100.123,100|200.123"
+         *
+         * <P>Type: TEXT</P>
+         */
+        public static final String GEOMETRIES = "geometries";
+
+        /**
+         * Geo-Fencing Maximum Wait Time in second. The range of the time is [0, 255]. A device
+         * shall allow to determine its position meeting operator policy. If the device is unable to
+         * determine its position meeting operator policy within the GeoFencing Maximum Wait Time,
+         * it shall present the alert to the user and discontinue further positioning determination
+         * for the alert.
+         *
+         * <P>Type: INTEGER</P>
+         */
+        public static final String MAXIMUM_WAIT_TIME = "maximum_wait_time";
+
+        /**
+         * Query columns for instantiating com.android.cellbroadcastreceiver.CellBroadcastMessage.
+         * @hide
+         */
+        @NonNull
+        public static final String[] QUERY_COLUMNS = {
+                _ID,
+                GEOGRAPHICAL_SCOPE,
+                PLMN,
+                LAC,
+                CID,
+                SERIAL_NUMBER,
+                SERVICE_CATEGORY,
+                LANGUAGE_CODE,
+                MESSAGE_BODY,
+                DELIVERY_TIME,
+                MESSAGE_READ,
+                MESSAGE_FORMAT,
+                MESSAGE_PRIORITY,
+                ETWS_WARNING_TYPE,
+                CMAS_MESSAGE_CLASS,
+                CMAS_CATEGORY,
+                CMAS_RESPONSE_TYPE,
+                CMAS_SEVERITY,
+                CMAS_URGENCY,
+                CMAS_CERTAINTY
+        };
+
+        /**
+         * Query columns for instantiating {@link android.telephony.SmsCbMessage} objects.
+         * @hide
+         */
+        public static final String[] QUERY_COLUMNS_FWK = {
+                _ID,
+                SLOT_INDEX,
+                SUB_ID,
+                GEOGRAPHICAL_SCOPE,
+                PLMN,
+                LAC,
+                CID,
+                SERIAL_NUMBER,
+                SERVICE_CATEGORY,
+                LANGUAGE_CODE,
+                MESSAGE_BODY,
+                MESSAGE_FORMAT,
+                MESSAGE_PRIORITY,
+                ETWS_WARNING_TYPE,
+                CMAS_MESSAGE_CLASS,
+                CMAS_CATEGORY,
+                CMAS_RESPONSE_TYPE,
+                CMAS_SEVERITY,
+                CMAS_URGENCY,
+                CMAS_CERTAINTY,
+                RECEIVED_TIME,
+                MESSAGE_BROADCASTED,
+                GEOMETRIES,
+                MAXIMUM_WAIT_TIME
+        };
+    }
+
+    /**
+     * Constants for interfacing with the ServiceStateProvider and the different fields of the
+     * {@link ServiceState} class accessible through the provider.
+     */
+    public static final class ServiceStateTable {
+
+        /**
+         * Not instantiable.
+         * @hide
+         */
+        private ServiceStateTable() {}
+
+        /**
+         * The authority string for the ServiceStateProvider
+         */
+        public static final String AUTHORITY = "service-state";
+
+        /**
+         * The {@code content://} style URL for the ServiceStateProvider
+         */
+        public static final Uri CONTENT_URI = Uri.parse("content://service-state/");
+
+        /**
+         * Generates a content {@link Uri} used to receive updates on a specific field in the
+         * ServiceState provider.
+         * <p>
+         * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+         * {@link ServiceState} while your app is running.
+         * You can also use a {@link android.app.job.JobService} to
+         * ensure your app is notified of changes to the {@link Uri} even when it is not running.
+         * Note, however, that using a {@link android.app.job.JobService}
+         * does not guarantee timely delivery of
+         * updates to the {@link Uri}.
+         *
+         * @param subscriptionId the subscriptionId to receive updates on
+         * @param field the ServiceState field to receive updates on
+         * @return the Uri used to observe {@link ServiceState} changes
+         */
+        public static Uri getUriForSubscriptionIdAndField(int subscriptionId, String field) {
+            return CONTENT_URI.buildUpon().appendEncodedPath(String.valueOf(subscriptionId))
+                    .appendEncodedPath(field).build();
+        }
+
+        /**
+         * Generates a content {@link Uri} used to receive updates on every field in the
+         * ServiceState provider.
+         * <p>
+         * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+         * {@link ServiceState} while your app is running.  You can also use a
+         * {@link android.app.job.JobService} to
+         * ensure your app is notified of changes to the {@link Uri} even when it is not running.
+         * Note, however, that using a {@link android.app.job.JobService}
+         * does not guarantee timely delivery of
+         * updates to the {@link Uri}.
+         *
+         * @param subscriptionId the subscriptionId to receive updates on
+         * @return the Uri used to observe {@link ServiceState} changes
+         */
+        public static Uri getUriForSubscriptionId(int subscriptionId) {
+            return CONTENT_URI.buildUpon().appendEncodedPath(String.valueOf(subscriptionId)).build();
+        }
+
+        /**
+         * Used to insert a ServiceState into the ServiceStateProvider as a ContentValues instance.
+         *
+         * @param state the ServiceState to convert into ContentValues
+         * @return the convertedContentValues instance
+         * @hide
+         */
+        public static ContentValues getContentValuesForServiceState(ServiceState state) {
+            ContentValues values = new ContentValues();
+            final Parcel p = Parcel.obtain();
+            state.writeToParcel(p, 0);
+            // Turn the parcel to byte array. Safe to do this because the content values were never
+            // written into a persistent storage. ServiceStateProvider keeps values in the memory.
+            values.put(SERVICE_STATE, p.marshall());
+            return values;
+        }
+
+        /**
+         * The current service state.
+         *
+         * This is the entire {@link ServiceState} object in byte array.
+         *
+         * @hide
+         */
+        public static final String SERVICE_STATE = "service_state";
+
+        /**
+         * An integer value indicating the current voice service state.
+         * <p>
+         * Valid values: {@link ServiceState#STATE_IN_SERVICE},
+         * {@link ServiceState#STATE_OUT_OF_SERVICE}, {@link ServiceState#STATE_EMERGENCY_ONLY},
+         * {@link ServiceState#STATE_POWER_OFF}.
+         * <p>
+         * This is the same as {@link ServiceState#getState()}.
+         */
+        public static final String VOICE_REG_STATE = "voice_reg_state";
+
+        /**
+         * An integer value indicating the current data service state.
+         * <p>
+         * Valid values: {@link ServiceState#STATE_IN_SERVICE},
+         * {@link ServiceState#STATE_OUT_OF_SERVICE}, {@link ServiceState#STATE_EMERGENCY_ONLY},
+         * {@link ServiceState#STATE_POWER_OFF}.
+         * <p>
+         * This is the same as {@link ServiceState#getDataRegState()}.
+         * @hide
+         */
+        public static final String DATA_REG_STATE = "data_reg_state";
+
+        /**
+         * An integer value indicating the current voice roaming type.
+         * <p>
+         * This is the same as {@link ServiceState#getVoiceRoamingType()}.
+         * @hide
+         */
+        public static final String VOICE_ROAMING_TYPE = "voice_roaming_type";
+
+        /**
+         * An integer value indicating the current data roaming type.
+         * <p>
+         * This is the same as {@link ServiceState#getDataRoamingType()}.
+         * @hide
+         */
+        public static final String DATA_ROAMING_TYPE = "data_roaming_type";
+
+        /**
+         * The current registered voice network operator name in long alphanumeric format.
+         * <p>
+         * This is the same as {@link ServiceState#getOperatorAlphaLong()}.
+         * @hide
+         */
+        public static final String VOICE_OPERATOR_ALPHA_LONG = "voice_operator_alpha_long";
+
+        /**
+         * The current registered operator name in short alphanumeric format.
+         * <p>
+         * In GSM/UMTS, short format can be up to 8 characters long. The current registered voice
+         * network operator name in long alphanumeric format.
+         * <p>
+         * This is the same as {@link ServiceState#getOperatorAlphaShort()}.
+         * @hide
+         */
+        public static final String VOICE_OPERATOR_ALPHA_SHORT = "voice_operator_alpha_short";
+
+        /**
+         * The current registered operator numeric id.
+         * <p>
+         * In GSM/UMTS, numeric format is 3 digit country code plus 2 or 3 digit
+         * network code.
+         * <p>
+         * This is the same as {@link ServiceState#getOperatorNumeric()}.
+         */
+        public static final String VOICE_OPERATOR_NUMERIC = "voice_operator_numeric";
+
+        /**
+         * The current registered data network operator name in long alphanumeric format.
+         * <p>
+         * This is the same as {@link ServiceState#getOperatorAlphaLong()}.
+         * @hide
+         */
+        public static final String DATA_OPERATOR_ALPHA_LONG = "data_operator_alpha_long";
+
+        /**
+         * The current registered data network operator name in short alphanumeric format.
+         * <p>
+         * This is the same as {@link ServiceState#getOperatorAlphaShort()}.
+         * @hide
+         */
+        public static final String DATA_OPERATOR_ALPHA_SHORT = "data_operator_alpha_short";
+
+        /**
+         * The current registered data network operator numeric id.
+         * <p>
+         * This is the same as {@link ServiceState#getOperatorNumeric()}.
+         * @hide
+         */
+        public static final String DATA_OPERATOR_NUMERIC = "data_operator_numeric";
+
+        /**
+         * The current network selection mode.
+         * <p>
+         * This is the same as {@link ServiceState#getIsManualSelection()}.
+         */
+        public static final String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection";
+
+        /**
+         * This is the same as {@link ServiceState#getRilVoiceRadioTechnology()}.
+         * @hide
+         */
+        public static final String RIL_VOICE_RADIO_TECHNOLOGY = "ril_voice_radio_technology";
+
+        /**
+         * This is the same as {@link ServiceState#getRilDataRadioTechnology()}.
+         * @hide
+         */
+        public static final String RIL_DATA_RADIO_TECHNOLOGY = "ril_data_radio_technology";
+
+        /**
+         * This is the same as {@link ServiceState#getCssIndicator()}.
+         * @hide
+         */
+        public static final String CSS_INDICATOR = "css_indicator";
+
+        /**
+         * This is the same as {@link ServiceState#getCdmaNetworkId()}.
+         * @hide
+         */
+        public static final String NETWORK_ID = "network_id";
+
+        /**
+         * This is the same as {@link ServiceState#getCdmaSystemId()}.
+         * @hide
+         */
+        public static final String SYSTEM_ID = "system_id";
+
+        /**
+         * This is the same as {@link ServiceState#getCdmaRoamingIndicator()}.
+         * @hide
+         */
+        public static final String CDMA_ROAMING_INDICATOR = "cdma_roaming_indicator";
+
+        /**
+         * This is the same as {@link ServiceState#getCdmaDefaultRoamingIndicator()}.
+         * @hide
+         */
+        public static final String CDMA_DEFAULT_ROAMING_INDICATOR =
+                "cdma_default_roaming_indicator";
+
+        /**
+         * This is the same as {@link ServiceState#getCdmaEriIconIndex()}.
+         * @hide
+         */
+        public static final String CDMA_ERI_ICON_INDEX = "cdma_eri_icon_index";
+
+        /**
+         * This is the same as {@link ServiceState#getCdmaEriIconMode()}.
+         * @hide
+         */
+        public static final String CDMA_ERI_ICON_MODE = "cdma_eri_icon_mode";
+
+        /**
+         * This is the same as {@link ServiceState#isEmergencyOnly()}.
+         * @hide
+         */
+        public static final String IS_EMERGENCY_ONLY = "is_emergency_only";
+
+        /**
+         * This is the same as {@link ServiceState#getDataRoamingFromRegistration()}.
+         * @hide
+         */
+        public static final String IS_DATA_ROAMING_FROM_REGISTRATION =
+                "is_data_roaming_from_registration";
+
+        /**
+         * This is the same as {@link ServiceState#isUsingCarrierAggregation()}.
+         * @hide
+         */
+        public static final String IS_USING_CARRIER_AGGREGATION = "is_using_carrier_aggregation";
+
+        /**
+         * The current registered raw data network operator name in long alphanumeric format.
+         * <p>
+         * This is the same as {@link ServiceState#getOperatorAlphaLongRaw()}.
+         * @hide
+         */
+        public static final String OPERATOR_ALPHA_LONG_RAW = "operator_alpha_long_raw";
+
+        /**
+         * The current registered raw data network operator name in short alphanumeric format.
+         * <p>
+         * This is the same as {@link ServiceState#getOperatorAlphaShortRaw()}.
+         * @hide
+         */
+        public static final String OPERATOR_ALPHA_SHORT_RAW = "operator_alpha_short_raw";
+    }
+
+    /**
+     * Contains carrier identification information for the current subscriptions.
+     */
+    public static final class CarrierId implements BaseColumns {
+        /**
+         * Not instantiable.
+         * @hide
+         */
+        private CarrierId() {}
+
+        /**
+         * The {@code content://} style URI for this provider.
+         */
+        public static final Uri CONTENT_URI = Uri.parse("content://carrier_id");
+
+        /**
+         * The authority string for the CarrierId Provider
+         * @hide
+         */
+        public static final String AUTHORITY = "carrier_id";
+
+
+        /**
+         * Generates a content {@link Uri} used to receive updates on carrier identity change
+         * on the given subscriptionId
+         * <p>
+         * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+         * carrier identity {@link TelephonyManager#getSimCarrierId()}
+         * while your app is running. You can also use a {@link android.app.job.JobService}
+         * to ensure your app
+         * is notified of changes to the {@link Uri} even when it is not running.
+         * Note, however, that using a {@link android.app.job.JobService} does not guarantee
+         * timely delivery of updates to the {@link Uri}.
+         *
+         * @param subscriptionId the subscriptionId to receive updates on
+         * @return the Uri used to observe carrier identity changes
+         */
+        public static Uri getUriForSubscriptionId(int subscriptionId) {
+            return CONTENT_URI.buildUpon().appendEncodedPath(
+                    String.valueOf(subscriptionId)).build();
+        }
+
+        /**
+         * Generates a content {@link Uri} used to receive updates on specific carrier identity
+         * change on the given subscriptionId returned by
+         * {@link TelephonyManager#getSimSpecificCarrierId()}.
+         * @see TelephonyManager#ACTION_SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED
+         * <p>
+         * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+         * specific carrier identity {@link TelephonyManager#getSimSpecificCarrierId()}
+         * while your app is running. You can also use a {@link android.app.job.JobService}
+         * to ensure your app
+         * is notified of changes to the {@link Uri} even when it is not running.
+         * Note, however, that using a {@link android.app.job.JobService} does not guarantee timely
+         * delivery of updates to the {@link Uri}.
+         *
+         * @param subscriptionId the subscriptionId to receive updates on
+         * @return the Uri used to observe specific carrier identity changes
+         */
+        @NonNull
+        public static Uri getSpecificCarrierIdUriForSubscriptionId(int subscriptionId) {
+            return Uri.withAppendedPath(Uri.withAppendedPath(CONTENT_URI, "specific"),
+                    String.valueOf(subscriptionId));
+        }
+
+        /**
+         * A user facing carrier name.
+         * @see TelephonyManager#getSimCarrierIdName()
+         * <P>Type: TEXT </P>
+         */
+        public static final String CARRIER_NAME = "carrier_name";
+
+        /**
+         * A unique carrier id
+         * @see TelephonyManager#getSimCarrierId()
+         * <P>Type: INTEGER </P>
+         */
+        public static final String CARRIER_ID = "carrier_id";
+
+        /**
+         * A fine-grained carrier id.
+         * The specific carrier ID would be used for configuration purposes, but apps wishing to
+         * know about the carrier itself should use the regular carrier ID returned by
+         * {@link TelephonyManager#getSimCarrierId()}.
+         *
+         * @see TelephonyManager#getSimSpecificCarrierId()
+         * This is not a database column, only used to notify content observers for
+         * {@link #getSpecificCarrierIdUriForSubscriptionId(int)}
+         */
+        public static final String SPECIFIC_CARRIER_ID = "specific_carrier_id";
+
+        /**
+         * A user facing carrier name for specific carrier id {@link #SPECIFIC_CARRIER_ID}.
+         * @see TelephonyManager#getSimSpecificCarrierIdName()
+         * This is not a database column, only used to notify content observers for
+         * {@link #getSpecificCarrierIdUriForSubscriptionId(int)}
+         */
+        public static final String SPECIFIC_CARRIER_ID_NAME = "specific_carrier_id_name";
+
+        /**
+         * A unique parent carrier id. The parent-child
+         * relationship can be used to further differentiate a single carrier by different networks,
+         * by prepaid v.s. postpaid. It's an optional field.
+         * A carrier id with a valid parent_carrier_id is considered fine-grained specific carrier
+         * ID, will not be returned as {@link #CARRIER_ID} but {@link #SPECIFIC_CARRIER_ID}.
+         * <P>Type: INTEGER </P>
+         * @hide
+         */
+        public static final String PARENT_CARRIER_ID = "parent_carrier_id";
+
+        /**
+         * Contains mappings between matching rules with carrier id for all carriers.
+         * @hide
+         */
+        @SystemApi
+        public static final class All implements BaseColumns {
+
+            /**
+             * Not instantiable.
+             * @hide
+             */
+            private All() {
+            }
+
+            /**
+             * Numeric operator ID (as String). {@code MCC + MNC}
+             * <P>Type: TEXT </P>
+             */
+            public static final String MCCMNC = "mccmnc";
+
+            /**
+             * Group id level 1 (as String).
+             * <P>Type: TEXT </P>
+             */
+            public static final String GID1 = "gid1";
+
+            /**
+             * Group id level 2 (as String).
+             * <P>Type: TEXT </P>
+             */
+            public static final String GID2 = "gid2";
+
+            /**
+             * Public Land Mobile Network name.
+             * <P>Type: TEXT </P>
+             */
+            public static final String PLMN = "plmn";
+
+            /**
+             * Prefix xpattern of IMSI (International Mobile Subscriber Identity).
+             * <P>Type: TEXT </P>
+             */
+            public static final String IMSI_PREFIX_XPATTERN = "imsi_prefix_xpattern";
+
+            /**
+             * Service Provider Name.
+             * <P>Type: TEXT </P>
+             */
+            public static final String SPN = "spn";
+
+            /**
+             * Prefer APN name.
+             * <P>Type: TEXT </P>
+             */
+            public static final String APN = "apn";
+
+            /**
+             * Prefix of Integrated Circuit Card Identifier.
+             * <P>Type: TEXT </P>
+             */
+            public static final String ICCID_PREFIX = "iccid_prefix";
+
+            /**
+             * Certificate for carrier privilege access rules.
+             * <P>Type: TEXT in hex string </P>
+             */
+            public static final String PRIVILEGE_ACCESS_RULE = "privilege_access_rule";
+
+            /**
+             * The {@code content://} URI for this table.
+             */
+            @NonNull
+            public static final Uri CONTENT_URI = Uri.parse("content://carrier_id/all");
+        }
+    }
+
+    /**
+     * Contains SIM Information
+     * @hide
+     */
+    @SystemApi
+    public static final class SimInfo {
+        /**
+         * Not instantiable.
+         * @hide
+         */
+        private SimInfo() {}
+
+        /**
+         * The {@code content://} style URI for this provider.
+         */
+        @NonNull
+        public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
+    }
+}
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 48ba429..4df4362 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -216,10 +216,21 @@
      */
     public static final int NEGATIVE_BUTTON_STYLE_REJECT = 1;
 
+    /**
+     * Style for the negative button of the save UI to never do the
+     * save operation. This means that the user does not need to save
+     * any data on this activity or application. Once the user tapping
+     * the negative button, the service should never trigger the save
+     * UI again. In addition to this, must consider providing restore
+     * options for the user.
+     */
+    public static final int NEGATIVE_BUTTON_STYLE_NEVER = 2;
+
     /** @hide */
     @IntDef(prefix = { "NEGATIVE_BUTTON_STYLE_" }, value = {
             NEGATIVE_BUTTON_STYLE_CANCEL,
-            NEGATIVE_BUTTON_STYLE_REJECT
+            NEGATIVE_BUTTON_STYLE_REJECT,
+            NEGATIVE_BUTTON_STYLE_NEVER
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface NegativeButtonStyle{}
@@ -571,6 +582,7 @@
          *
          * @see #NEGATIVE_BUTTON_STYLE_CANCEL
          * @see #NEGATIVE_BUTTON_STYLE_REJECT
+         * @see #NEGATIVE_BUTTON_STYLE_NEVER
          *
          * @throws IllegalArgumentException If the style is invalid
          */
@@ -578,11 +590,7 @@
                 @Nullable IntentSender listener) {
             throwIfDestroyed();
             Preconditions.checkArgumentInRange(style, NEGATIVE_BUTTON_STYLE_CANCEL,
-                    NEGATIVE_BUTTON_STYLE_REJECT, "style");
-            if (style != NEGATIVE_BUTTON_STYLE_CANCEL
-                    && style != NEGATIVE_BUTTON_STYLE_REJECT) {
-                throw new IllegalArgumentException("Invalid style: " + style);
-            }
+                    NEGATIVE_BUTTON_STYLE_NEVER, "style");
             mNegativeButtonStyle = style;
             mNegativeActionListener = listener;
             return this;
diff --git a/core/java/android/service/autofill/augmented/FillWindow.java b/core/java/android/service/autofill/augmented/FillWindow.java
index 6a29d48..5d00370 100644
--- a/core/java/android/service/autofill/augmented/FillWindow.java
+++ b/core/java/android/service/autofill/augmented/FillWindow.java
@@ -242,6 +242,7 @@
         synchronized (mLock) {
             if (mDestroyed) return;
             if (mUpdateCalled) {
+                mFillView.setOnClickListener(null);
                 hide();
                 mProxy.report(AutofillProxy.REPORT_EVENT_UI_DESTROYED);
             }
diff --git a/core/java/android/service/controls/BooleanAction.aidl b/core/java/android/service/controls/BooleanAction.aidl
new file mode 100644
index 0000000..730ad36
--- /dev/null
+++ b/core/java/android/service/controls/BooleanAction.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+parcelable BooleanAction;
\ No newline at end of file
diff --git a/core/java/android/service/controls/BooleanAction.java b/core/java/android/service/controls/BooleanAction.java
new file mode 100644
index 0000000..8508c63
--- /dev/null
+++ b/core/java/android/service/controls/BooleanAction.java
@@ -0,0 +1,93 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+
+/**
+ * Action sent by a {@link ToggleTemplate}
+ * @hide
+ */
+public final class BooleanAction extends ControlAction {
+
+    private final boolean mNewState;
+
+    /**
+     * @param templateId the identifier of the {@link ToggleTemplate} that produced this action.
+     * @param newState new value for the state displayed by the {@link ToggleTemplate}.
+     */
+    public BooleanAction(@NonNull String templateId, boolean newState) {
+        this(templateId, newState, null);
+    }
+
+    /**
+     * @param templateId the identifier of the {@link ToggleTemplate} that originated this action.
+     * @param newValue new value for the state displayed by the {@link ToggleTemplate}.
+     * @param challengeValue a value sent by the user along with the action to authenticate. {@code}
+     *                       null is sent when no authentication is needed or has not been
+     *                       requested.
+     */
+    public BooleanAction(@NonNull String templateId, boolean newValue,
+            @Nullable String challengeValue) {
+        super(templateId, challengeValue);
+        mNewState = newValue;
+    }
+
+    BooleanAction(Parcel in) {
+        super(in);
+        mNewState = in.readByte() == 1;
+    }
+
+    /**
+     * The new state set for the button in the corresponding {@link ToggleTemplate}.
+     *
+     * @return {@code true} if the button was toggled from an {@code off} state to an {@code on}
+     *         state.
+     */
+    public boolean getNewState() {
+        return mNewState;
+    }
+
+    /**
+     * @return {@link ControlAction#TYPE_BOOLEAN}
+     */
+    @Override
+    public int getActionType() {
+        return ControlAction.TYPE_BOOLEAN;
+    }
+
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeByte(mNewState ? (byte) 1 : (byte) 0);
+    }
+
+    public static final @NonNull Creator<BooleanAction> CREATOR = new Creator<BooleanAction>() {
+        @Override
+        public BooleanAction createFromParcel(Parcel source) {
+            return new BooleanAction(source);
+        }
+
+        @Override
+        public BooleanAction[] newArray(int size) {
+            return new BooleanAction[size];
+        }
+    };
+}
diff --git a/core/java/android/service/controls/Control.aidl b/core/java/android/service/controls/Control.aidl
new file mode 100644
index 0000000..f4964f2
--- /dev/null
+++ b/core/java/android/service/controls/Control.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+parcelable Control;
\ No newline at end of file
diff --git a/core/java/android/service/controls/Control.java b/core/java/android/service/controls/Control.java
new file mode 100644
index 0000000..a69408c
--- /dev/null
+++ b/core/java/android/service/controls/Control.java
@@ -0,0 +1,284 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.graphics.drawable.Icon;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Represents a physical object that can be represented by a {@link ControlTemplate} and whose
+ * properties may be modified through a {@link ControlAction}.
+ *
+ * The information is provided by a {@link ControlProviderService} and represents static
+ * information (not current status) about the device.
+ * <p>
+ * Each control needs a unique (per provider) identifier that is persistent across reboots of the
+ * system.
+ * <p>
+ * Each {@link Control} will have a name and an icon. The name is usually set up by the user in the
+ * {@link ControlProvider} while the icon is usually decided by the {@link ControlProvider} based
+ * on the type of device.
+ * <p>
+ * The {@link ControlTemplate.TemplateType} provided will be used as a hint when displaying this in
+ * non-interactive situations (for example when there's no state to display). This template is not
+ * the one that will be shown with the current state and provide interactions. That template is set
+ * using {@link ControlState}.
+ * <p>
+ * An {@link Intent} linking to the provider Activity that expands this {@link Control} should be
+ * provided.
+ * @hide
+ */
+public class Control implements Parcelable {
+
+    private final @NonNull String mControlId;
+    private final @NonNull Icon mIcon;
+    private final @NonNull CharSequence mTitle;
+    private final @Nullable ColorStateList mTintColor;
+    private final @NonNull Intent mAppIntent;
+    private final @ControlTemplate.TemplateType int mPrimaryType;
+
+    /**
+     * @param controlId the unique persistent identifier for this object.
+     * @param icon an icon to display identifying the control.
+     * @param title the user facing name of this control (e.g. "Bedroom thermostat").
+     * @param tintColor the color to tint parts of the element UI. If {@code null} is passed, the
+     *                  system accent color will be used.
+     * @param appIntent an intent linking to a page to interact with the corresponding device.
+     * @param primaryType the primary template for this type.
+     */
+    public Control(@NonNull String controlId,
+            @NonNull Icon icon,
+            @NonNull CharSequence title,
+            @Nullable ColorStateList tintColor,
+            @NonNull Intent appIntent,
+            int primaryType) {
+        Preconditions.checkNotNull(controlId);
+        Preconditions.checkNotNull(icon);
+        Preconditions.checkNotNull(title);
+        Preconditions.checkNotNull(appIntent);
+        mControlId = controlId;
+        mIcon = icon;
+        mTitle = title;
+        mTintColor = tintColor;
+        mAppIntent = appIntent;
+        mPrimaryType = primaryType;
+    }
+
+    public Control(Parcel in) {
+        mControlId = in.readString();
+        mIcon = Icon.CREATOR.createFromParcel(in);
+        mTitle = in.readCharSequence();
+        if (in.readByte() == 1) {
+            mTintColor = ColorStateList.CREATOR.createFromParcel(in);
+        } else {
+            mTintColor = null;
+        }
+        mAppIntent = Intent.CREATOR.createFromParcel(in);
+        mPrimaryType = in.readInt();
+    }
+
+    @NonNull
+    public String getControlId() {
+        return mControlId;
+    }
+
+    @NonNull
+    public Icon getIcon() {
+        return mIcon;
+    }
+
+    @NonNull
+    public CharSequence getTitle() {
+        return mTitle;
+    }
+
+    @Nullable
+    public ColorStateList getTint() {
+        return mTintColor;
+    }
+
+    @NonNull
+    public Intent getAppIntent() {
+        return mAppIntent;
+    }
+
+    @ControlTemplate.TemplateType
+    public int getPrimaryType() {
+        return mPrimaryType;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mControlId);
+        mIcon.writeToParcel(dest, flags);
+        dest.writeCharSequence(mTitle);
+        if (mTintColor != null) {
+            dest.writeByte((byte) 1);
+            mTintColor.writeToParcel(dest, flags);
+        } else {
+            dest.writeByte((byte) 0);
+        }
+        mAppIntent.writeToParcel(dest, flags);
+        dest.writeInt(mPrimaryType);
+    }
+
+    public static final Creator<Control> CREATOR = new Creator<Control>() {
+        @Override
+        public Control createFromParcel(Parcel source) {
+            return new Control(source);
+        }
+
+        @Override
+        public Control[] newArray(int size) {
+            return new Control[size];
+        }
+    };
+
+    /**
+     * Builder class for {@link Control}.
+     *
+     * This class facilitates the creation of {@link Control}. It provides the following
+     * defaults for non-optional parameters:
+     * <ul>
+     *     <li> Title: {@code ""}
+     *     <li> Primary template: {@link ControlTemplate#TYPE_NONE}
+     * </ul>
+     */
+    public static class Builder {
+        private String mControlId;
+        private Icon mIcon;
+        private CharSequence mTitle = "";
+        private ColorStateList mTintColor;
+        private @Nullable Intent mAppIntent;
+        private @ControlTemplate.TemplateType int mPrimaryType = ControlTemplate.TYPE_NONE;
+
+        /**
+         * @param controlId the identifier for the {@link Control}.
+         * @param icon the icon for the {@link Control}.
+         * @param appIntent the intent linking to the device Activity.
+         */
+        public Builder(@NonNull String controlId,
+                @NonNull Icon icon,
+                @NonNull Intent appIntent) {
+            Preconditions.checkNotNull(controlId);
+            Preconditions.checkNotNull(icon);
+            Preconditions.checkNotNull(appIntent);
+            mControlId = controlId;
+            mIcon = icon;
+            mAppIntent = appIntent;
+        }
+
+        /**
+         * Creates a {@link Builder} using an existing {@link Control} as a base.
+         * @param control base for the builder.
+         */
+        public Builder(@NonNull Control control) {
+            Preconditions.checkNotNull(control);
+            mControlId = control.mControlId;
+            mIcon = control.mIcon;
+            mTitle = control.mTitle;
+            mTintColor = control.mTintColor;
+            mAppIntent = control.mAppIntent;
+            mPrimaryType = control.mPrimaryType;
+        }
+
+        /**
+         * @param controlId the identifier for the {@link Control}.
+         * @return {@code this}
+         */
+        public Builder setControlId(@NonNull String controlId) {
+            Preconditions.checkNotNull(controlId);
+            mControlId = controlId;
+            return this;
+        }
+
+        /**
+         * @param icon the icon for the {@link Control}
+         * @return {@code this}
+         */
+        @NonNull
+        public Builder setIcon(@NonNull Icon icon) {
+            Preconditions.checkNotNull(icon);
+            mIcon = icon;
+            return this;
+        }
+
+        /**
+         * @param title the user facing name of the {@link Control}
+         * @return {@code this}
+         */
+        @NonNull
+        public Builder setTitle(@NonNull CharSequence title) {
+            Preconditions.checkNotNull(title);
+            mTitle = title;
+            return this;
+        }
+
+        /**
+         * @param tint colors for tinting parts of the {@link Control} UI. Passing {@code null} will
+         *             default to using the current color accent.
+         * @return {@code this}
+         */
+        @NonNull
+        public Builder setTint(@Nullable ColorStateList tint) {
+            mTintColor = tint;
+            return this;
+        }
+
+        /**
+         * @param appIntent an {@link Intent} linking to an Activity for the {@link Control}
+         * @return {@code this}
+         */
+        @NonNull
+        public Builder setAppIntent(@NonNull Intent appIntent) {
+            Preconditions.checkNotNull(appIntent);
+            mAppIntent = appIntent;
+            return this;
+        }
+
+        /**
+         * @param type type to use as default in the {@link Control}
+         * @return {@code this}
+         */
+        @NonNull
+        public Builder setPrimaryType(@ControlTemplate.TemplateType int type) {
+            mPrimaryType = type;
+            return this;
+        }
+
+        /**
+         * Build a {@link Control}
+         * @return a valid {@link Control}
+         */
+        @NonNull
+        public Control build() {
+            return new Control(mControlId, mIcon, mTitle, mTintColor, mAppIntent, mPrimaryType);
+        }
+    }
+}
diff --git a/core/java/android/service/controls/ControlAction.aidl b/core/java/android/service/controls/ControlAction.aidl
new file mode 100644
index 0000000..e1a5276
--- /dev/null
+++ b/core/java/android/service/controls/ControlAction.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+parcelable ControlAction;
\ No newline at end of file
diff --git a/core/java/android/service/controls/ControlAction.java b/core/java/android/service/controls/ControlAction.java
new file mode 100644
index 0000000..8b75955
--- /dev/null
+++ b/core/java/android/service/controls/ControlAction.java
@@ -0,0 +1,189 @@
+/*
+ * 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;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * An abstract action that is executed from a {@link ControlTemplate}.
+ *
+ * The action may have a value to authenticate the input, when the provider has requested it to
+ * complete the action.
+ * @hide
+ */
+public abstract class ControlAction implements Parcelable {
+
+    /**
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            TYPE_BOOLEAN,
+            TYPE_FLOAT
+    })
+    public @interface ActionType {};
+
+    /**
+     * The identifier of {@link BooleanAction}.
+     */
+    public static final @ActionType int TYPE_BOOLEAN = 0;
+
+    /**
+     * The identifier of {@link FloatAction}.
+     */
+    public static final @ActionType int TYPE_FLOAT = 1;
+
+    /**
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            RESPONSE_OK,
+            RESPONSE_FAIL,
+            RESPONSE_CHALLENGE_ACK,
+            RESPONSE_CHALLENGE_PIN,
+            RESPONSE_CHALLENGE_PASSPHRASE
+    })
+    public @interface ResponseResult {};
+
+    /**
+     * Response code for {@link IControlsProviderCallback#onControlActionResponse} 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 = 0;
+    /**
+     * Response code for {@link IControlsProviderCallback#onControlActionResponse} indicating that
+     * the action has failed.
+     */
+    public static final @ResponseResult int RESPONSE_FAIL = 1;
+    /**
+     * Response code for {@link IControlsProviderCallback#onControlActionResponse} indicating that
+     * in order for the action to be performed, acknowledgment from the user is required.
+     */
+    public static final @ResponseResult int RESPONSE_CHALLENGE_ACK = 2;
+    /**
+     * Response code for {@link IControlsProviderCallback#onControlActionResponse} indicating that
+     * in order for the action to be performed, a PIN is required.
+     */
+    public static final @ResponseResult int RESPONSE_CHALLENGE_PIN = 3;
+    /**
+     * Response code for {@link IControlsProviderCallback#onControlActionResponse} indicating that
+     * in order for the action to be performed, an alphanumeric passphrase is required.
+     */
+    public static final @ResponseResult int RESPONSE_CHALLENGE_PASSPHRASE = 4;
+
+    /**
+     * The {@link ActionType} associated with this class.
+     */
+    public abstract @ActionType int getActionType();
+
+    private final @NonNull String mTemplateId;
+    private final @Nullable String mChallengeValue;
+
+    private ControlAction() {
+        mTemplateId = "";
+        mChallengeValue = null;
+    }
+
+    /**
+     * @hide
+     */
+    ControlAction(@NonNull String templateId, @Nullable String challengeValue) {
+        Preconditions.checkNotNull(templateId);
+        mTemplateId = templateId;
+        mChallengeValue = challengeValue;
+    }
+
+    /**
+     * @hide
+     */
+    ControlAction(Parcel in) {
+        mTemplateId = in.readString();
+        if (in.readByte() == 1) {
+            mChallengeValue = in.readString();
+        } else {
+            mChallengeValue = null;
+        }
+    }
+
+    /**
+     * The identifier of the {@link ControlTemplate} that originated this action
+     */
+    @NonNull
+    public String getTemplateId() {
+        return mTemplateId;
+    }
+
+    /**
+     * The challenge value used to authenticate certain actions, if available.
+     */
+    @Nullable
+    public String getChallengeValue() {
+        return mChallengeValue;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(getActionType());
+        dest.writeString(mTemplateId);
+        if (mChallengeValue != null) {
+            dest.writeByte((byte) 1);
+            dest.writeString(mChallengeValue);
+        } else {
+            dest.writeByte((byte) 0);
+        }
+    }
+
+    public static final @NonNull Creator<ControlAction> CREATOR = new Creator<ControlAction>() {
+        @Override
+        public ControlAction createFromParcel(Parcel source) {
+            int type = source.readInt();
+            return createActionFromType(type, source);
+        }
+
+        @Override
+        public ControlAction[] newArray(int size) {
+            return new ControlAction[size];
+        }
+    };
+
+    private static ControlAction createActionFromType(@ActionType int type, Parcel source) {
+        switch(type) {
+            case TYPE_BOOLEAN:
+                return BooleanAction.CREATOR.createFromParcel(source);
+            case TYPE_FLOAT:
+                return FloatAction.CREATOR.createFromParcel(source);
+            default:
+                return null;
+        }
+    }
+
+}
diff --git a/core/java/android/service/controls/ControlButton.aidl b/core/java/android/service/controls/ControlButton.aidl
new file mode 100644
index 0000000..6a7262d
--- /dev/null
+++ b/core/java/android/service/controls/ControlButton.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+parcelable ControlButton;
\ No newline at end of file
diff --git a/core/java/android/service/controls/ControlButton.java b/core/java/android/service/controls/ControlButton.java
new file mode 100644
index 0000000..fed3115
--- /dev/null
+++ b/core/java/android/service/controls/ControlButton.java
@@ -0,0 +1,103 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.graphics.drawable.Icon;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Button element for {@link ControlTemplate}.
+ * @hide
+ */
+public class ControlButton implements Parcelable {
+
+    private final boolean mActive;
+    private final @NonNull Icon mIcon;
+    private final @NonNull CharSequence mContentDescription;
+
+    /**
+     * @param active true if the button should be rendered as active.
+     * @param icon icon to display in the button.
+     * @param contentDescription content description for the button.
+     */
+    public ControlButton(boolean active, @NonNull Icon icon,
+            @NonNull CharSequence contentDescription) {
+        Preconditions.checkNotNull(icon);
+        Preconditions.checkNotNull(contentDescription);
+        mActive = active;
+        mIcon = icon;
+        mContentDescription = contentDescription;
+    }
+
+    /**
+     * Whether the button should be rendered in its active state.
+     */
+    public boolean isActive() {
+        return mActive;
+    }
+
+    /**
+     * The icon for this button.
+     */
+    @NonNull
+    public Icon getIcon() {
+        return mIcon;
+    }
+
+    /**
+     * The content description for this button.
+     */
+    @NonNull
+    public CharSequence getContentDescription() {
+        return mContentDescription;
+    }
+
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeByte(mActive ? (byte) 1 : (byte) 0);
+        mIcon.writeToParcel(dest, flags);
+        dest.writeCharSequence(mContentDescription);
+    }
+
+    ControlButton(Parcel in) {
+        mActive = in.readByte() != 0;
+        mIcon = Icon.CREATOR.createFromParcel(in);
+        mContentDescription = in.readCharSequence();
+    }
+
+    public static final Creator<ControlButton> CREATOR = new Creator<ControlButton>() {
+        @Override
+        public ControlButton createFromParcel(Parcel source) {
+            return new ControlButton(source);
+        }
+
+        @Override
+        public ControlButton[] newArray(int size) {
+            return new ControlButton[size];
+        }
+    };
+}
diff --git a/core/java/android/service/controls/ControlState.aidl b/core/java/android/service/controls/ControlState.aidl
new file mode 100644
index 0000000..520d85b
--- /dev/null
+++ b/core/java/android/service/controls/ControlState.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+parcelable ControlState;
\ No newline at end of file
diff --git a/core/java/android/service/controls/ControlState.java b/core/java/android/service/controls/ControlState.java
new file mode 100644
index 0000000..804aef7
--- /dev/null
+++ b/core/java/android/service/controls/ControlState.java
@@ -0,0 +1,318 @@
+/*
+ * 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;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.ColorStateList;
+import android.graphics.drawable.Icon;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Current state for a {@link Control}.
+ *
+ * Collects information to render the current state of a {@link Control} as well as possible action
+ * that can be performed on it. Some of the information may temporarily override the defaults
+ * provided by the corresponding {@link Control}, while this state is being displayed.
+ *
+ * Additionally, this can be used to modify information related to the corresponding
+ * {@link Control}.
+ * @hide
+ */
+public final class ControlState implements Parcelable {
+
+    /**
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            STATUS_OK,
+            STATUS_NOT_FOUND,
+            STATUS_ERROR,
+            STATUS_DISABLED,
+    })
+    public @interface Status {};
+
+    /**
+     * The device corresponding to the {@link Control} is responding correctly.
+     */
+    public static final int STATUS_OK = 0;
+
+    /**
+     * The device corresponding to the {@link Control} cannot be found or was removed.
+     */
+    public static final int STATUS_NOT_FOUND = 1;
+
+    /**
+     * The device corresponding to the {@link Control} is in an error state.
+     */
+    public static final int STATUS_ERROR = 2;
+
+    /**
+     * The {@link Control} is currently disabled.
+     */
+    public static final int STATUS_DISABLED = 3;
+
+    private final @NonNull Control mControl;
+    private final @Status int mStatus;
+    private final @NonNull ControlTemplate mControlTemplate;
+    private final @NonNull CharSequence mStatusText;
+    private final @Nullable Icon mOverrideIcon;
+    private final @Nullable ColorStateList mOverrideTint;
+
+    /**
+     * @param control the {@link Control} this state should be applied to. Can be used to
+     *                       update information about the {@link Control}
+     * @param status the current status of the {@link Control}.
+     * @param controlTemplate the template to be used to render the {@link Control}.
+     * @param statusText the text describing the current status.
+     * @param overrideIcon the icon to temporarily override the one provided in
+     *                     {@link Control#getIcon()}. Pass {@code null} to use the icon in
+     *                     {@link Control#getIcon()}.
+     * @param overrideTint the colors to temporarily override those provided in
+     *                            {@link Control#getTint()}. Pass {@code null} to use the colors in
+     *                            {@link Control#getTint()}.
+     */
+    public ControlState(@NonNull Control control,
+            int status,
+            @NonNull ControlTemplate controlTemplate,
+            @NonNull CharSequence statusText,
+            @Nullable Icon overrideIcon,
+            @Nullable ColorStateList overrideTint) {
+        Preconditions.checkNotNull(control);
+        Preconditions.checkNotNull(controlTemplate);
+        Preconditions.checkNotNull(statusText);
+
+        mControl = control;
+        mStatus = status;
+        mControlTemplate = controlTemplate;
+        mOverrideIcon = overrideIcon;
+        mStatusText = statusText;
+        mOverrideTint = overrideTint;
+    }
+
+    ControlState(Parcel in) {
+        mControl = Control.CREATOR.createFromParcel(in);
+        mStatus = in.readInt();
+        mControlTemplate = ControlTemplate.CREATOR.createFromParcel(in);
+        mStatusText = in.readCharSequence();
+        if (in.readByte() == 1) {
+            mOverrideIcon = Icon.CREATOR.createFromParcel(in);
+        } else {
+            mOverrideIcon = null;
+        }
+        if (in.readByte() == 1) {
+            mOverrideTint = ColorStateList.CREATOR.createFromParcel(in);
+        } else {
+            mOverrideTint = null;
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Status
+    public int getStatus() {
+        return mStatus;
+    }
+
+    @NonNull
+    public ControlTemplate getControlTemplate() {
+        return mControlTemplate;
+    }
+
+    @Nullable
+    public Icon getOverrideIcon() {
+        return mOverrideIcon;
+    }
+
+    @NonNull
+    public CharSequence getStatusText() {
+        return mStatusText;
+    }
+
+    @Nullable
+    public ColorStateList getOverrideTint() {
+        return mOverrideTint;
+    }
+
+    @NonNull
+    public Control getControl() {
+        return mControl;
+    }
+
+    @NonNull
+    public String getControlId() {
+        return mControl.getControlId();
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        mControl.writeToParcel(dest, flags);
+        dest.writeInt(mStatus);
+        mControlTemplate.writeToParcel(dest, flags);
+        dest.writeCharSequence(mStatusText);
+        if (mOverrideIcon != null) {
+            dest.writeByte((byte) 1);
+            mOverrideIcon.writeToParcel(dest, flags);
+        } else {
+            dest.writeByte((byte) 0);
+        }
+        if (mOverrideTint != null) {
+            dest.writeByte((byte) 1);
+            mOverrideTint.writeToParcel(dest, flags);
+        } else {
+            dest.writeByte((byte) 0);
+        }
+    }
+
+    public static final Creator<ControlState> CREATOR = new Creator<ControlState>() {
+        @Override
+        public ControlState createFromParcel(Parcel source) {
+            return new ControlState(source);
+        }
+
+        @Override
+        public ControlState[] newArray(int size) {
+            return new ControlState[size];
+        }
+    };
+
+    /**
+     * Builder class for {@link ControlState}.
+     *
+     * This class facilitates the creation of {@link ControlState}. It provides the following
+     * defaults for non-optional parameters:
+     * <ul>
+     *     <li> Status: {@link ControlState#STATUS_OK}
+     *     <li> Control template: {@link ControlTemplate#NO_TEMPLATE}
+     *     <li> Status text: {@code ""}
+     * </ul>
+     */
+    public static class Builder {
+        private @NonNull Control mControl;
+        private @Status int mStatus = STATUS_OK;
+        private @NonNull ControlTemplate mControlTemplate = ControlTemplate.NO_TEMPLATE;
+        private @NonNull CharSequence mStatusText = "";
+        private @Nullable Icon mOverrideIcon;
+        private @Nullable ColorStateList mOverrideTint;
+
+        /**
+         * @param control the {@link Control} that the resulting {@link ControlState} refers to.
+         */
+        public Builder(@NonNull Control control) {
+            Preconditions.checkNotNull(control);
+            mControl = control;
+        }
+
+        /**
+         * Creates a {@link Builder} using an existing {@link ControlState} as a base.
+         * @param controlState base for the builder.
+         */
+        public Builder(@NonNull ControlState controlState) {
+            Preconditions.checkNotNull(controlState);
+            mControl = controlState.mControl;
+            mControlTemplate = controlState.mControlTemplate;
+            mOverrideIcon = controlState.mOverrideIcon;
+            mStatusText = controlState.mStatusText;
+            mOverrideTint = controlState.mOverrideTint;
+        }
+
+
+        /**
+         * @param control the updated {@link Control} information.
+         * @return {@code this}
+         */
+        @NonNull
+        public Builder setControl(@NonNull Control control) {
+            mControl = control;
+            return this;
+        }
+
+        /**
+         * @param status the current status of the {@link Control}
+         * @return {@code this}
+         */
+        @NonNull
+        public Builder setStatus(@Status int status) {
+            mStatus = status;
+            return this;
+        }
+
+        /**
+         * @param controlTemplate the template to use when rendering the {@code Control}.
+         * @return {@code this}
+         */
+        @NonNull
+        public Builder setControlTemplate(@NonNull ControlTemplate controlTemplate) {
+            Preconditions.checkNotNull(controlTemplate);
+            mControlTemplate = controlTemplate;
+            return this;
+        }
+
+        /**
+         * @param statusText the user-visible description of the status.
+         * @return {@code this}
+         */
+        @NonNull
+        public Builder setStatusText(@NonNull CharSequence statusText) {
+            Preconditions.checkNotNull(statusText);
+            mStatusText = statusText;
+            return this;
+        }
+
+        /**
+         * @param overrideIcon the icon to override the one defined in the corresponding
+         *                            {@code Control}. Pass {@code null} to remove the override.
+         * @return {@code this}
+         */
+        @NonNull
+        public Builder setOverrideIcon(@Nullable Icon overrideIcon) {
+            mOverrideIcon = overrideIcon;
+            return this;
+        }
+
+        /**
+         * @param overrideTint the colors to override the ones defined in the corresponding
+         *                            {@code Control}. Pass {@code null} to remove the override.
+         * @return {@code this}
+         */
+        @NonNull
+        public Builder setOverrideTint(@Nullable ColorStateList overrideTint) {
+            mOverrideTint = overrideTint;
+            return this;
+        }
+
+        /**
+         * @return a new {@link ControlState}
+         */
+        public ControlState build() {
+            return new ControlState(mControl, mStatus, mControlTemplate, mStatusText,
+                    mOverrideIcon, mOverrideTint);
+        }
+    }
+}
+
diff --git a/core/java/android/service/controls/ControlTemplate.aidl b/core/java/android/service/controls/ControlTemplate.aidl
new file mode 100644
index 0000000..ecb948c
--- /dev/null
+++ b/core/java/android/service/controls/ControlTemplate.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+parcelable ControlTemplate;
\ No newline at end of file
diff --git a/core/java/android/service/controls/ControlTemplate.java b/core/java/android/service/controls/ControlTemplate.java
new file mode 100644
index 0000000..e559862
--- /dev/null
+++ b/core/java/android/service/controls/ControlTemplate.java
@@ -0,0 +1,167 @@
+/*
+ * 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;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * An abstract input template for a {@link Control}.
+ *
+ * Specifies what layout is presented to the user when a {@link ControlState} is assigned to a
+ * particular {@link Control}.
+ * <p>
+ * Some instances of {@link Control} can originate actions (via user interaction) to modify its
+ * associated state. The actions available to a given {@link Control} in a particular
+ * {@link ControlState} are determined by its {@link ControlTemplate}.
+ * @see ControlAction
+ * @hide
+ */
+public abstract class ControlTemplate implements Parcelable {
+
+    /**
+     * Singleton representing a {@link Control} with no input.
+     */
+    public static final ControlTemplate NO_TEMPLATE = new ControlTemplate("") {
+        @Override
+        public int getTemplateType() {
+            return TYPE_NONE;
+        }
+    };
+
+    /**
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            TYPE_NONE,
+            TYPE_TOGGLE,
+            TYPE_RANGE,
+            TYPE_THUMBNAIL,
+            TYPE_DISCRETE_TOGGLE,
+            TYPE_COORD_RANGE
+    })
+    public @interface TemplateType {}
+
+    /**
+     * Type identifier of {@link ControlTemplate#NO_TEMPLATE}.
+     */
+    public static final int TYPE_NONE = 0;
+
+    /**
+     * Type identifier of {@link ToggleTemplate}.
+     */
+    public static final int TYPE_TOGGLE = 1;
+
+    /**
+     * Type identifier of {@link RangeTemplate}.
+     */
+    public static final int TYPE_RANGE = 2;
+
+    /**
+     * Type identifier of {@link ThumbnailTemplate}.
+     */
+    public static final int TYPE_THUMBNAIL = 3;
+
+    /**
+     * Type identifier of {@link DiscreteToggleTemplate}.
+     */
+    public static final int TYPE_DISCRETE_TOGGLE = 4;
+
+    /**
+     * @hide
+     */
+    public static final int TYPE_COORD_RANGE = 5;
+
+    private @NonNull final String mTemplateId;
+
+    /**
+     * @return the identifier for this object.
+     */
+    public String getTemplateId() {
+        return mTemplateId;
+    }
+
+    /**
+     * The {@link TemplateType} associated with this class.
+     */
+    public abstract @TemplateType int getTemplateType();
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(getTemplateType());
+        dest.writeString(mTemplateId);
+    }
+
+    private ControlTemplate() {
+        mTemplateId = "";
+    }
+
+    ControlTemplate(Parcel in) {
+        mTemplateId = in.readString();
+    }
+
+    /**
+     * @hide
+     */
+    ControlTemplate(@NonNull String templateId) {
+        Preconditions.checkNotNull(templateId);
+        mTemplateId = templateId;
+    }
+
+    public static final Creator<ControlTemplate> CREATOR = new Creator<ControlTemplate>() {
+        @Override
+        public ControlTemplate createFromParcel(Parcel source) {
+            int type = source.readInt();
+            return createTemplateFromType(type, source);
+        }
+
+        @Override
+        public ControlTemplate[] newArray(int size) {
+            return new ControlTemplate[size];
+        }
+    };
+
+    private static ControlTemplate createTemplateFromType(@TemplateType int type, Parcel source) {
+        switch(type) {
+            case TYPE_TOGGLE:
+                return ToggleTemplate.CREATOR.createFromParcel(source);
+            case TYPE_RANGE:
+                return RangeTemplate.CREATOR.createFromParcel(source);
+            case TYPE_THUMBNAIL:
+                return ThumbnailTemplate.CREATOR.createFromParcel(source);
+            case TYPE_DISCRETE_TOGGLE:
+                return DiscreteToggleTemplate.CREATOR.createFromParcel(source);
+            case TYPE_NONE:
+                return NO_TEMPLATE;
+            default:
+                return null;
+        }
+    }
+}
diff --git a/core/java/android/service/controls/DiscreteToggleTemplate.java b/core/java/android/service/controls/DiscreteToggleTemplate.java
new file mode 100644
index 0000000..5167af4
--- /dev/null
+++ b/core/java/android/service/controls/DiscreteToggleTemplate.java
@@ -0,0 +1,110 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * A template for a {@link Control} with two discrete inputs.
+ *
+ * The two inputs represent a <i>Negative</i> input and a <i>Positive</i> input.
+ * <p>
+ * When one of the buttons is actioned, a {@link BooleanAction} will be sent.
+ * {@link BooleanAction#getNewState} will be {@code false} if the button was
+ * {@link DiscreteToggleTemplate#getNegativeButton} and {@code true} if the button was
+ * {@link DiscreteToggleTemplate#getPositiveButton}.
+ * @hide
+ */
+public class DiscreteToggleTemplate extends ControlTemplate {
+
+    private final @NonNull ControlButton mNegativeButton;
+    private final @NonNull ControlButton mPositiveButton;
+
+    /**
+     * @param templateId the identifier for this template object
+     * @param negativeButton a {@ControlButton} for the <i>Negative</i> input
+     * @param positiveButton a {@ControlButton} for the <i>Positive</i> input
+     */
+    public DiscreteToggleTemplate(@NonNull String templateId,
+            @NonNull ControlButton negativeButton,
+            @NonNull ControlButton positiveButton) {
+        super(templateId);
+        Preconditions.checkNotNull(negativeButton);
+        Preconditions.checkNotNull(positiveButton);
+        mNegativeButton = negativeButton;
+        mPositiveButton = positiveButton;
+    }
+
+    DiscreteToggleTemplate(Parcel in) {
+        super(in);
+        this.mNegativeButton = ControlButton.CREATOR.createFromParcel(in);
+        this.mPositiveButton = ControlButton.CREATOR.createFromParcel(in);
+    }
+
+    /**
+     * The {@link ControlButton} associated with the <i>Negative</i> action.
+     */
+    @NonNull
+    public ControlButton getNegativeButton() {
+        return mNegativeButton;
+    }
+
+    /**
+     * The {@link ControlButton} associated with the <i>Positive</i> action.
+     */
+    @NonNull
+    public ControlButton getPositiveButton() {
+        return mPositiveButton;
+    }
+
+    /**
+     * @return {@link ControlTemplate#TYPE_DISCRETE_TOGGLE}
+     */
+    @Override
+    public int getTemplateType() {
+        return TYPE_DISCRETE_TOGGLE;
+    }
+
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        mNegativeButton.writeToParcel(dest, flags);
+        mPositiveButton.writeToParcel(dest, flags);
+    }
+
+    public static final Creator<DiscreteToggleTemplate> CREATOR =
+            new Creator<DiscreteToggleTemplate>() {
+                @Override
+                public DiscreteToggleTemplate createFromParcel(Parcel source) {
+                    return new DiscreteToggleTemplate(source);
+                }
+
+                @Override
+                public DiscreteToggleTemplate[] newArray(int size) {
+                    return new DiscreteToggleTemplate[size];
+                }
+            };
+}
diff --git a/core/java/android/service/controls/FloatAction.aidl b/core/java/android/service/controls/FloatAction.aidl
new file mode 100644
index 0000000..dbc0f72
--- /dev/null
+++ b/core/java/android/service/controls/FloatAction.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+parcelable FloatAction;
\ No newline at end of file
diff --git a/core/java/android/service/controls/FloatAction.java b/core/java/android/service/controls/FloatAction.java
new file mode 100644
index 0000000..fe6db10
--- /dev/null
+++ b/core/java/android/service/controls/FloatAction.java
@@ -0,0 +1,90 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+
+/**
+ * Action sent by a {@link RangeTemplate}.
+ * @hide
+ */
+public final class FloatAction extends ControlAction {
+
+    private final float mNewValue;
+
+    /**
+     * @param templateId the identifier of the {@link RangeTemplate} that produced this action.
+     * @param newValue new value for the state displayed by the {@link RangeTemplate}.
+     */
+    public FloatAction(@NonNull String templateId, float newValue) {
+        this(templateId, newValue, null);
+    }
+
+    /**
+     * @param templateId the identifier of the {@link RangeTemplate} that originated this action.
+     * @param newValue new value for the state of the {@link RangeTemplate}.
+     * @param challengeValue a value sent by the user along with the action to authenticate. {@code}
+     *                       null is sent when no authentication is needed or has not been
+     *                       requested.
+     */
+
+    public FloatAction(@NonNull String templateId, float newValue,
+            @Nullable String challengeValue) {
+        super(templateId, challengeValue);
+        mNewValue = newValue;
+    }
+
+    public FloatAction(Parcel in) {
+        super(in);
+        mNewValue = in.readFloat();
+    }
+
+    /**
+     * The new value set for the range in the corresponding {@link RangeTemplate}.
+     */
+    public float getNewValue() {
+        return mNewValue;
+    }
+
+    /**
+     * @return {@link ControlAction#TYPE_FLOAT}
+     */
+    @Override
+    public int getActionType() {
+        return TYPE_FLOAT;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeFloat(mNewValue);
+    }
+
+    public static final @NonNull Creator<FloatAction> CREATOR = new Creator<FloatAction>() {
+        @Override
+        public FloatAction createFromParcel(Parcel source) {
+            return new FloatAction(source);
+        }
+
+        @Override
+        public FloatAction[] newArray(int size) {
+            return new FloatAction[size];
+        }
+    };
+}
diff --git a/core/java/android/service/controls/IControlsProvider.aidl b/core/java/android/service/controls/IControlsProvider.aidl
new file mode 100644
index 0000000..f778653
--- /dev/null
+++ b/core/java/android/service/controls/IControlsProvider.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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;
+
+import android.service.controls.ControlAction;
+
+/** @hide */
+oneway interface IControlsProvider {
+    void load();
+
+    void subscribe(in List<String> controlIds);
+
+    void unsubscribe();
+
+    void onAction(in String controlId, in ControlAction action);
+}
\ No newline at end of file
diff --git a/core/java/android/service/controls/IControlsProviderCallback.aidl b/core/java/android/service/controls/IControlsProviderCallback.aidl
new file mode 100644
index 0000000..3dbb68c
--- /dev/null
+++ b/core/java/android/service/controls/IControlsProviderCallback.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+import android.service.controls.Control;
+import android.service.controls.ControlState;
+
+/** @hide */
+oneway interface IControlsProviderCallback {
+    void onLoad(in List<Control> controls);
+
+    void onRefreshState(in List<ControlState> controlStates);
+
+    void onControlActionResponse(in String controlId, int response);
+}
\ No newline at end of file
diff --git a/core/java/android/service/controls/RangeTemplate.aidl b/core/java/android/service/controls/RangeTemplate.aidl
new file mode 100644
index 0000000..a3d1ca0
--- /dev/null
+++ b/core/java/android/service/controls/RangeTemplate.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+parcelable RangeTemplate;
\ No newline at end of file
diff --git a/core/java/android/service/controls/RangeTemplate.java b/core/java/android/service/controls/RangeTemplate.java
new file mode 100644
index 0000000..70bf2dd
--- /dev/null
+++ b/core/java/android/service/controls/RangeTemplate.java
@@ -0,0 +1,190 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+
+import com.android.internal.util.Preconditions;
+
+import java.security.InvalidParameterException;
+
+/**
+ * A template for a {@link Control} with inputs in a "continuous" range of values.
+ *
+ * @see FloatAction
+ * @hide
+ */
+public final class RangeTemplate extends ControlTemplate {
+
+    private final float mMinValue;
+    private final float mMaxValue;
+    private final float mCurrentValue;
+    private final float mStepValue;
+    private final @NonNull CharSequence mFormatString;
+
+    /**
+     * Construct a new {@link RangeTemplate}.
+     *
+     * The range must be valid, meaning:
+     * <ul>
+     *     <li> {@code minValue} < {@code maxValue}
+     *     <li> {@code minValue} < {@code currentValue}
+     *     <li> {@code currentValue} < {@code maxValue}
+     *     <li> 0 < {@code stepValue}
+     * </ul>
+     * <p>
+     * The current value of the Control will be formatted accordingly.
+     *
+     * @param templateId the identifier for this template object
+     * @param minValue minimum value for the input
+     * @param maxValue maximum value for the input
+     * @param currentValue the current value of the {@link ControlState} containing this object.
+     * @param stepValue minimum value of increments/decrements when interacting with this control.
+     * @param formatString a formatting string as per {@link String#format} used to display the
+     *                    {@code currentValue}. If {@code null} is passed, the "%.1f" is used.
+     * @throws InvalidParameterException if the parameters passed do not make a valid range.
+     */
+    public RangeTemplate(@NonNull String templateId,
+            float minValue,
+            float maxValue,
+            float currentValue,
+            float stepValue,
+            @Nullable CharSequence formatString) {
+        super(templateId);
+        Preconditions.checkNotNull(formatString);
+        mMinValue = minValue;
+        mMaxValue = maxValue;
+        mCurrentValue = currentValue;
+        mStepValue = stepValue;
+        if (formatString != null) {
+            mFormatString = formatString;
+        } else {
+            mFormatString = "%.1f";
+        }
+        validate();
+    }
+
+    /**
+     * Construct a new {@link RangeTemplate} from a {@link Parcel}.
+     *
+     * @throws InvalidParameterException if the parameters passed do not make a valid range
+     * @see RangeTemplate#RangeTemplate(String, float, float, float, float, CharSequence)
+     * @hide
+     */
+    RangeTemplate(Parcel in) {
+        super(in);
+        mMinValue = in.readFloat();
+        mMaxValue = in.readFloat();
+        mCurrentValue = in.readFloat();
+        mStepValue = in.readFloat();
+        mFormatString = in.readCharSequence();
+        validate();
+    }
+
+    /**
+     * The minimum value for this range.
+     */
+    public float getMinValue() {
+        return mMinValue;
+    }
+
+    /**
+     * The maximum value for this range.
+     */
+    public float getMaxValue() {
+        return mMaxValue;
+    }
+
+    /**
+     * The current value for this range.
+     */
+    public float getCurrentValue() {
+        return mCurrentValue;
+    }
+
+    /**
+     * The value of the smallest increment or decrement that can be performed on this range.
+     */
+    public float getStepValue() {
+        return mStepValue;
+    }
+
+    /**
+     * Formatter for generating a user visible {@link String} representing the value
+     *         returned by {@link RangeTemplate#getCurrentValue}.
+     * @return a formatting string as specified in {@link String#format}
+     */
+    @NonNull
+    public CharSequence getFormatString() {
+        return mFormatString;
+    }
+
+    /**
+     * @return {@link ControlTemplate#TYPE_RANGE}
+     */
+    @Override
+    public int getTemplateType() {
+        return TYPE_RANGE;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeFloat(mMinValue);
+        dest.writeFloat(mMaxValue);
+        dest.writeFloat(mCurrentValue);
+        dest.writeFloat(mStepValue);
+        dest.writeCharSequence(mFormatString);
+    }
+
+    /**
+     * Validate constructor parameters
+     *
+     * @throws InvalidParameterException if the parameters passed do not make a valid range
+     */
+    private void validate() {
+        if (Float.compare(mMinValue, mMaxValue) > 0) {
+            throw new InvalidParameterException(
+                    String.format("minValue=%f > maxValue=%f", mMinValue, mMaxValue));
+        }
+        if (Float.compare(mMinValue, mCurrentValue) > 0) {
+            throw new InvalidParameterException(
+                    String.format("minValue=%f > currentValue=%f", mMinValue, mCurrentValue));
+        }
+        if (Float.compare(mCurrentValue, mMaxValue) > 0) {
+            throw new InvalidParameterException(
+                    String.format("currentValue=%f > maxValue=%f", mCurrentValue, mMaxValue));
+        }
+        if (mStepValue <= 0) {
+            throw new InvalidParameterException(String.format("stepValue=%f <= 0", mStepValue));
+        }
+    }
+
+    public static final Creator<RangeTemplate> CREATOR = new Creator<RangeTemplate>() {
+        @Override
+        public RangeTemplate createFromParcel(Parcel source) {
+            return new RangeTemplate(source);
+        }
+
+        @Override
+        public RangeTemplate[] newArray(int size) {
+            return new RangeTemplate[size];
+        }
+    };
+}
diff --git a/core/java/android/service/controls/ThumbnailTemplate.aidl b/core/java/android/service/controls/ThumbnailTemplate.aidl
new file mode 100644
index 0000000..fe8c7fe
--- /dev/null
+++ b/core/java/android/service/controls/ThumbnailTemplate.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+parcelable ThumbnailTemplate;
\ No newline at end of file
diff --git a/core/java/android/service/controls/ThumbnailTemplate.java b/core/java/android/service/controls/ThumbnailTemplate.java
new file mode 100644
index 0000000..796d2de
--- /dev/null
+++ b/core/java/android/service/controls/ThumbnailTemplate.java
@@ -0,0 +1,95 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.graphics.drawable.Icon;
+import android.os.Parcel;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * A template for a {@link Control} that displays an image.
+ * @hide
+ */
+public final class ThumbnailTemplate extends ControlTemplate {
+
+    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;
+    }
+
+    ThumbnailTemplate(Parcel in) {
+        super(in);
+        mThumbnail = Icon.CREATOR.createFromParcel(in);
+        mContentDescription = in.readCharSequence();
+    }
+
+    /**
+     * 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_THUMBNAIL;
+    }
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        mThumbnail.writeToParcel(dest, flags);
+        dest.writeCharSequence(mContentDescription);
+    }
+
+    public static final Creator<ThumbnailTemplate> CREATOR = new Creator<ThumbnailTemplate>() {
+        @Override
+        public ThumbnailTemplate createFromParcel(Parcel source) {
+            return new ThumbnailTemplate(source);
+        }
+
+        @Override
+        public ThumbnailTemplate[] newArray(int size) {
+            return new ThumbnailTemplate[size];
+        }
+    };
+}
diff --git a/core/java/android/service/controls/ToggleTemplate.aidl b/core/java/android/service/controls/ToggleTemplate.aidl
new file mode 100644
index 0000000..1c823d9
--- /dev/null
+++ b/core/java/android/service/controls/ToggleTemplate.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+parcelable ToggleTemplate;
\ No newline at end of file
diff --git a/core/java/android/service/controls/ToggleTemplate.java b/core/java/android/service/controls/ToggleTemplate.java
new file mode 100644
index 0000000..3766bd1
--- /dev/null
+++ b/core/java/android/service/controls/ToggleTemplate.java
@@ -0,0 +1,86 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * A template for a {@link Control} with a single button that can be toggled between two states.
+ *
+ * The states for the toggle correspond to the states in {@link ControlButton#isActive()}.
+ * An action on this template will originate a {@link BooleanAction} to change that state.
+ *
+ * @see BooleanAction
+ * @hide
+ */
+public final class ToggleTemplate extends ControlTemplate {
+
+    private final @NonNull ControlButton mButton;
+
+    /**
+     * @param templateId the identifier for this template object
+     * @param button a {@ControlButton} that can show the current state and toggle it
+     */
+    public ToggleTemplate(@NonNull String templateId, @NonNull ControlButton button) {
+        super(templateId);
+        Preconditions.checkNotNull(button);
+        mButton = button;
+    }
+
+    ToggleTemplate(Parcel in) {
+        super(in);
+        mButton = ControlButton.CREATOR.createFromParcel(in);
+    }
+
+    /**
+     * The button provided to this object in {@link ToggleTemplate#ToggleTemplate}
+     */
+    @NonNull
+    public ControlButton getButton() {
+        return mButton;
+    }
+
+    /**
+     * @return {@link ControlTemplate#TYPE_TOGGLE}
+     */
+    @Override
+    public int getTemplateType() {
+        return TYPE_TOGGLE;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        mButton.writeToParcel(dest, flags);
+    }
+
+    public static final Creator<ToggleTemplate> CREATOR = new Creator<ToggleTemplate>() {
+        @Override
+        public ToggleTemplate createFromParcel(Parcel source) {
+            return new ToggleTemplate(source);
+        }
+
+        @Override
+        public ToggleTemplate[] newArray(int size) {
+            return new ToggleTemplate[size];
+        }
+    };
+
+}
diff --git a/core/java/android/service/incremental/IIncrementalDataLoaderService.aidl b/core/java/android/service/incremental/IIncrementalDataLoaderService.aidl
deleted file mode 100644
index 723fc59..0000000
--- a/core/java/android/service/incremental/IIncrementalDataLoaderService.aidl
+++ /dev/null
@@ -1,34 +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.incremental;
-
-import android.os.incremental.IncrementalDataLoaderParamsParcel;
-import android.os.incremental.IncrementalFileSystemControlParcel;
-import android.service.incremental.IIncrementalDataLoaderStatusListener;
-
-/** @hide */
-oneway interface IIncrementalDataLoaderService {
-   void createDataLoader(in int storageId,
-                 in IncrementalFileSystemControlParcel control,
-                 in IncrementalDataLoaderParamsParcel params,
-                 in IIncrementalDataLoaderStatusListener listener,
-                 in boolean start);
-   void startDataLoader(in int storageId);
-   void stopDataLoader(in int storageId);
-   void destroyDataLoader(in int storageId);
-   void onFileCreated(in int storageId, in long inode, in byte[] metadata);
-}
diff --git a/core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl b/core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl
deleted file mode 100644
index f04242d..0000000
--- a/core/java/android/service/incremental/IIncrementalDataLoaderStatusListener.aidl
+++ /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.service.incremental;
-
-/**
- * Callbacks from DataLoaderService to IncrementalService to report data loader status.
- * @hide
- */
-oneway interface IIncrementalDataLoaderStatusListener {
-    /** Data loader status */
-    const int DATA_LOADER_READY = 0;
-    const int DATA_LOADER_NOT_READY = 1;
-    const int DATA_LOADER_RUNNING = 2;
-    const int DATA_LOADER_STOPPED = 3;
-    const int DATA_LOADER_SLOW_CONNECTION = 4;
-    const int DATA_LOADER_NO_CONNECTION = 5;
-    const int DATA_LOADER_CONNECTION_OK = 6;
-
-    /** Data loader status callback */
-    void onStatusChanged(in int storageId, in int status);
-}
-
diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
index e506509..cf57e25 100644
--- a/core/java/android/service/notification/Condition.java
+++ b/core/java/android/service/notification/Condition.java
@@ -151,7 +151,7 @@
     }
 
     /** @hide */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
 
         // id is guaranteed not to be null.
diff --git a/core/java/android/service/notification/IConditionProvider.aidl b/core/java/android/service/notification/IConditionProvider.aidl
index 3f3c6b8..dd3904f 100644
--- a/core/java/android/service/notification/IConditionProvider.aidl
+++ b/core/java/android/service/notification/IConditionProvider.aidl
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2014, The Android Open Source Project
+ * 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.
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 1f2c872..dedc3b7 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -1739,7 +1739,7 @@
 
         /** @hide */
         // TODO: add configuration activity
-        public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        public void dumpDebug(ProtoOutputStream proto, long fieldId) {
             final long token = proto.start(fieldId);
 
             proto.write(ZenRuleProto.ID, id);
@@ -1753,13 +1753,13 @@
                 proto.write(ZenRuleProto.CONDITION_ID, conditionId.toString());
             }
             if (condition != null) {
-                condition.writeToProto(proto, ZenRuleProto.CONDITION);
+                condition.dumpDebug(proto, ZenRuleProto.CONDITION);
             }
             if (component != null) {
-                component.writeToProto(proto, ZenRuleProto.COMPONENT);
+                component.dumpDebug(proto, ZenRuleProto.COMPONENT);
             }
             if (zenPolicy != null) {
-                zenPolicy.writeToProto(proto, ZenRuleProto.ZEN_POLICY);
+                zenPolicy.dumpDebug(proto, ZenRuleProto.ZEN_POLICY);
             }
             proto.write(ZenRuleProto.MODIFIED, modified);
             proto.end(token);
diff --git a/core/java/android/service/notification/ZenPolicy.java b/core/java/android/service/notification/ZenPolicy.java
index 9694998..6e2faa9 100644
--- a/core/java/android/service/notification/ZenPolicy.java
+++ b/core/java/android/service/notification/ZenPolicy.java
@@ -973,7 +973,7 @@
     /**
      * @hide
      */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
 
         proto.write(ZenPolicyProto.REMINDERS, getPriorityCategoryReminders());
diff --git a/core/java/android/telephony/CellBroadcastIntents.java b/core/java/android/telephony/CellBroadcastIntents.java
new file mode 100644
index 0000000..4474f3e
--- /dev/null
+++ b/core/java/android/telephony/CellBroadcastIntents.java
@@ -0,0 +1,96 @@
+/*
+ * 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.telephony;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.util.Log;
+
+/**
+ * A static helper class used to send Intents with prepopulated flags.
+ * <p>
+ * This is intended to be used by the CellBroadcastService and will throw a security exception if
+ * used from a UID besides the network stack UID.
+ *
+ * @hide
+ */
+@SystemApi
+public class CellBroadcastIntents {
+    private static final String LOG_TAG = "CellBroadcastIntents";
+
+    /**
+     * @hide
+     */
+    private CellBroadcastIntents() {
+    }
+
+    /**
+     * Returns an intent which can be received by background BroadcastReceivers. This is only
+     * intended to be used by the CellBroadcastService and will throw a security exception if called
+     * from another UID.
+     *
+     * @param context            The context from which to send the broadcast
+     * @param user               The user from which to send the broadcast
+     * @param intent             The Intent to broadcast; all receivers matching this Intent will
+     *                           receive the broadcast.
+     * @param receiverPermission String naming a permissions that a receiver must hold in order to
+     *                           receive your broadcast. If null, no permission is required.
+     * @param receiverAppOp      The app op associated with the broadcast. If null, no appOp is
+     *                           required. If both receiverAppOp and receiverPermission are
+     *                           non-null, a receiver must have both of them to receive the
+     *                           broadcast
+     * @param resultReceiver     Your own BroadcastReceiver to treat as the final receiver of the
+     *                           broadcast.
+     * @param scheduler          A custom Handler with which to schedule the resultReceiver
+     *                           callback; if null it will be scheduled in the Context's main
+     *                           thread.
+     * @param initialCode        An initial value for the result code.  Often Activity.RESULT_OK.
+     * @param initialData        An initial value for the result data.  Often null.
+     * @param initialExtras      An initial value for the result extras.  Often null.
+     */
+    public static void sendOrderedBroadcastForBackgroundReceivers(@NonNull Context context,
+            @Nullable UserHandle user, @NonNull Intent intent, @Nullable String receiverPermission,
+            @Nullable String receiverAppOp, @Nullable BroadcastReceiver resultReceiver,
+            @Nullable Handler scheduler, int initialCode, @Nullable String initialData,
+            @Nullable Bundle initialExtras) {
+        Log.d(LOG_TAG, "sendOrderedBroadcastForBackgroundReceivers intent=" + intent.getAction());
+        int status = context.checkCallingOrSelfPermission(
+                "android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS");
+        if (status == PackageManager.PERMISSION_DENIED) {
+            throw new SecurityException(
+                    "Caller does not have permission to send broadcast for background receivers");
+        }
+        intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+        if (user != null) {
+            context.createContextAsUser(user, 0).sendOrderedBroadcast(intent, receiverPermission,
+                    receiverAppOp, resultReceiver, scheduler, initialCode, initialData,
+                    initialExtras);
+        } else {
+            context.sendOrderedBroadcast(intent, receiverPermission,
+                    receiverAppOp, resultReceiver, scheduler, initialCode, initialData,
+                    initialExtras);
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/DataConnectionRealTimeInfo.aidl b/core/java/android/telephony/DataConnectionRealTimeInfo.aidl
similarity index 100%
rename from telephony/java/android/telephony/DataConnectionRealTimeInfo.aidl
rename to core/java/android/telephony/DataConnectionRealTimeInfo.aidl
diff --git a/telephony/java/android/telephony/DataConnectionRealTimeInfo.java b/core/java/android/telephony/DataConnectionRealTimeInfo.java
similarity index 100%
rename from telephony/java/android/telephony/DataConnectionRealTimeInfo.java
rename to core/java/android/telephony/DataConnectionRealTimeInfo.java
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index a65c8fd..716a522 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -286,14 +286,6 @@
     public static final int LISTEN_USER_MOBILE_DATA_STATE                  = 0x00080000;
 
     /**
-     *  Listen for changes to the physical channel configuration.
-     *
-     *  @see #onPhysicalChannelConfigurationChanged
-     *  @hide
-     */
-    public static final int LISTEN_PHYSICAL_CHANNEL_CONFIGURATION          = 0x00100000;
-
-    /**
      *  Listen for changes to the phone capability.
      *
      *  @see #onPhoneCapabilityChanged
@@ -831,24 +823,6 @@
     }
 
     /**
-     * Callback invoked when the current physical channel configuration has changed on the
-     * registered subscription.
-     * Note, the registration subId comes from {@link TelephonyManager} object which registers
-     * PhoneStateListener by {@link TelephonyManager#listen(PhoneStateListener, int)}.
-     * If this TelephonyManager object was created with
-     * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
-     * subId. Otherwise, this callback applies to
-     * {@link SubscriptionManager#getDefaultSubscriptionId()}.
-     *
-     * @param configs List of the current {@link PhysicalChannelConfig}s
-     * @hide
-     */
-    public void onPhysicalChannelConfigurationChanged(
-            @NonNull List<PhysicalChannelConfig> configs) {
-        // default implementation empty
-    }
-
-    /**
      * Callback invoked when the current emergency number list has changed on the registered
      * subscription.
      * Note, the registration subId comes from {@link TelephonyManager} object which registers
@@ -1194,15 +1168,6 @@
                     () -> mExecutor.execute(() -> psl.onCarrierNetworkChange(active)));
         }
 
-        public void onPhysicalChannelConfigurationChanged(List<PhysicalChannelConfig> configs) {
-            PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
-            if (psl == null) return;
-
-            Binder.withCleanCallingIdentity(
-                    () -> mExecutor.execute(
-                            () -> psl.onPhysicalChannelConfigurationChanged(configs)));
-        }
-
         public void onEmergencyNumberListChanged(Map emergencyNumberList) {
             PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
             if (psl == null) return;
diff --git a/telephony/java/android/telephony/SubscriptionPlan.aidl b/core/java/android/telephony/SubscriptionPlan.aidl
similarity index 100%
rename from telephony/java/android/telephony/SubscriptionPlan.aidl
rename to core/java/android/telephony/SubscriptionPlan.aidl
diff --git a/telephony/java/android/telephony/SubscriptionPlan.java b/core/java/android/telephony/SubscriptionPlan.java
similarity index 100%
rename from telephony/java/android/telephony/SubscriptionPlan.java
rename to core/java/android/telephony/SubscriptionPlan.java
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index f66a679..9d7b57b 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -455,6 +455,19 @@
     }
 
     /**
+     * Sim activation type: voice
+     * @see #notifyVoiceActivationStateChanged
+     * @hide
+     */
+    public static final int SIM_ACTIVATION_TYPE_VOICE = 0;
+    /**
+     * Sim activation type: data
+     * @see #notifyDataActivationStateChanged
+     * @hide
+     */
+    public static final int SIM_ACTIVATION_TYPE_DATA = 1;
+
+    /**
      * Notify data activation state changed on certain subscription.
      * @see TelephonyManager#getDataActivationState()
      *
@@ -469,7 +482,7 @@
         @SimActivationState int activationState) {
         try {
             sRegistry.notifySimActivationStateChangedForPhoneId(slotIndex, subId,
-                TelephonyManager.SIM_ACTIVATION_TYPE_DATA, activationState);
+                    SIM_ACTIVATION_TYPE_DATA, activationState);
         } catch (RemoteException ex) {
             // system process is dead
         }
@@ -490,7 +503,7 @@
         @SimActivationState int activationState) {
         try {
             sRegistry.notifySimActivationStateChangedForPhoneId(slotIndex, subId,
-                TelephonyManager.SIM_ACTIVATION_TYPE_VOICE, activationState);
+                    SIM_ACTIVATION_TYPE_VOICE, activationState);
         } catch (RemoteException ex) {
             // system process is dead
         }
diff --git a/core/java/android/text/AlteredCharSequence.java b/core/java/android/text/AlteredCharSequence.java
index 4cc71fd..971a47d 100644
--- a/core/java/android/text/AlteredCharSequence.java
+++ b/core/java/android/text/AlteredCharSequence.java
@@ -16,12 +16,14 @@
 
 package android.text;
 
-// XXX should this really be in the public API at all?
 /**
  * An AlteredCharSequence is a CharSequence that is largely mirrored from
  * another CharSequence, except that a specified range of characters are
  * mirrored from a different char array instead.
+ *
+ * @deprecated The functionality this class offers is easily implemented outside the framework.
  */
+@Deprecated
 public class AlteredCharSequence
 implements CharSequence, GetChars
 {
diff --git a/core/java/android/text/LoginFilter.java b/core/java/android/text/LoginFilter.java
index e2d1596..0e4eec44 100644
--- a/core/java/android/text/LoginFilter.java
+++ b/core/java/android/text/LoginFilter.java
@@ -19,7 +19,10 @@
 /**
  * Abstract class for filtering login-related text (user names and passwords)
  * 
+ * @deprecated Password requirements should not be hardcoded in clients. This class also does not
+ * handle non-BMP characters.
  */
+@Deprecated
 public abstract class LoginFilter implements InputFilter {
     private boolean mAppendInvalid;  // whether to append or ignore invalid characters
     /**
@@ -130,7 +133,9 @@
      * account creation. It prevents the user from entering user names with characters other than 
      * [a-zA-Z0-9.]. 
      * 
+     * @deprecated Do not encode assumptions about Google account names into client applications.
      */
+    @Deprecated
     public static class UsernameFilterGMail extends LoginFilter {
         
         public UsernameFilterGMail() {
@@ -190,8 +195,12 @@
     /**
      * This filter is compatible with GMail passwords which restricts characters to 
      * the Latin-1 (ISO8859-1) char set.
-     * 
+     *
+     * @deprecated Do not handle a user's Google password. Refer to
+     *   <a href="https://support.google.com/accounts/answer/32040">Google Help</a> for
+     *   password restriction information.
      */
+    @Deprecated
     public static class PasswordFilterGMail extends LoginFilter {
         
         public PasswordFilterGMail() {
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 7e09740..236e5ae 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -41,6 +41,7 @@
     public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
     public static final String DYNAMIC_SYSTEM = "settings_dynamic_system";
     public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
+    public static final String SETTINGS_FUSE_FLAG = "settings_fuse";
 
     private static final Map<String, String> DEFAULT_FLAGS;
 
@@ -48,6 +49,7 @@
         DEFAULT_FLAGS = new HashMap<>();
         DEFAULT_FLAGS.put("settings_audio_switcher", "true");
         DEFAULT_FLAGS.put("settings_systemui_theme", "true");
+        DEFAULT_FLAGS.put(SETTINGS_FUSE_FLAG, "false");
         DEFAULT_FLAGS.put(DYNAMIC_SYSTEM, "false");
         DEFAULT_FLAGS.put(SEAMLESS_TRANSFER, "false");
         DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
diff --git a/core/java/android/util/LocalLog.java b/core/java/android/util/LocalLog.java
index 3a1df3e..6a6bccf 100644
--- a/core/java/android/util/LocalLog.java
+++ b/core/java/android/util/LocalLog.java
@@ -17,9 +17,11 @@
 package android.util;
 
 import android.annotation.UnsupportedAppUsage;
+import android.os.SystemClock;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.time.Instant;
 import java.time.LocalDateTime;
 import java.util.ArrayDeque;
 import java.util.Deque;
@@ -33,10 +35,22 @@
     private final Deque<String> mLog;
     private final int mMaxLines;
 
+    /**
+     * {@code true} to use log timestamps expressed in local date/time, {@code false} to use log
+     * timestamped expressed with the elapsed realtime clock and UTC system clock. {@code false} is
+     * useful when logging behavior that modifies device time zone or system clock.
+     */
+    private final boolean mUseLocalTimestamps;
+
     @UnsupportedAppUsage
     public LocalLog(int maxLines) {
+        this(maxLines, true /* useLocalTimestamps */);
+    }
+
+    public LocalLog(int maxLines, boolean useLocalTimestamps) {
         mMaxLines = Math.max(0, maxLines);
         mLog = new ArrayDeque<>(mMaxLines);
+        mUseLocalTimestamps = useLocalTimestamps;
     }
 
     @UnsupportedAppUsage
@@ -44,7 +58,14 @@
         if (mMaxLines <= 0) {
             return;
         }
-        append(String.format("%s - %s", LocalDateTime.now(), msg));
+        final String logLine;
+        if (mUseLocalTimestamps) {
+            logLine = String.format("%s - %s", LocalDateTime.now(), msg);
+        } else {
+            logLine = String.format(
+                    "%s / %s - %s", SystemClock.elapsedRealtime(), Instant.now(), msg);
+        }
+        append(logLine);
     }
 
     private synchronized void append(String logLine) {
diff --git a/core/java/android/util/StatsEvent.java b/core/java/android/util/StatsEvent.java
index d7ec30c..7e71640 100644
--- a/core/java/android/util/StatsEvent.java
+++ b/core/java/android/util/StatsEvent.java
@@ -20,8 +20,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
 import android.os.SystemClock;
 
 import com.android.internal.annotations.GuardedBy;
@@ -44,7 +42,7 @@
  * </pre>
  * @hide
  **/
-public final class StatsEvent implements Parcelable {
+public final class StatsEvent {
     // Type Ids.
     /**
      * @hide
@@ -177,7 +175,7 @@
      * @hide
      **/
     @VisibleForTesting
-    public static final int ERROR_ATTRIBUTION_UIDS_TAGS_SIZES_NOT_EQUAL = 0x400;
+    public static final int ERROR_ATTRIBUTION_UIDS_TAGS_SIZES_NOT_EQUAL = 0x1000;
 
     // Size limits.
 
@@ -265,39 +263,6 @@
     }
 
     /**
-     * Boilerplate for Parcel.
-     */
-    public static final @NonNull Parcelable.Creator<StatsEvent> CREATOR =
-            new Parcelable.Creator<StatsEvent>() {
-                public StatsEvent createFromParcel(Parcel in) {
-                    // Purposefully leaving this method not implemented.
-                    throw new RuntimeException("Not implemented");
-                }
-
-                public StatsEvent[] newArray(int size) {
-                    // Purposefully leaving this method not implemented.
-                    throw new RuntimeException("Not implemented");
-                }
-            };
-
-    /**
-     * Boilerplate for Parcel.
-     */
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(mAtomId);
-        out.writeInt(getNumBytes());
-        out.writeByteArray(getBytes());
-    }
-
-    /**
-     * Boilerplate for Parcel.
-     */
-    public int describeContents() {
-        return 0;
-    }
-
-
-    /**
      * Builder for constructing a StatsEvent object.
      *
      * <p>This class defines and encapsulates the socket encoding for the buffer.
@@ -628,9 +593,9 @@
             if (0 == mErrorMask) {
                 mBuffer.putByte(POS_NUM_ELEMENTS, (byte) mNumElements);
             } else {
-                mBuffer.putByte(0, TYPE_ERRORS);
-                mBuffer.putByte(POS_NUM_ELEMENTS, (byte) 3);
+                mPos += mBuffer.putByte(mPos, TYPE_ERRORS);
                 mPos += mBuffer.putInt(mPos, mErrorMask);
+                mBuffer.putByte(POS_NUM_ELEMENTS, (byte) 3);
                 size = mPos;
             }
 
diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java
index f7077bb..8cb5b05 100644
--- a/core/java/android/util/StatsLog.java
+++ b/core/java/android/util/StatsLog.java
@@ -179,6 +179,8 @@
      * @param rollbackType          state of the rollback.
      * @param packageName           package name being rolled back.
      * @param packageVersionCode    version of the package being rolled back.
+     * @param rollbackReason        reason the package is being rolled back.
+     * @param failingPackageName    the package name causing the failure.
      *
      * @return True if the log request was sent to statsd.
      *
@@ -186,7 +188,7 @@
      */
     @RequiresPermission(allOf = {DUMP, PACKAGE_USAGE_STATS})
     public static boolean logWatchdogRollbackOccurred(int rollbackType, String packageName,
-            long packageVersionCode) {
+            long packageVersionCode, int rollbackReason, String failingPackageName) {
         synchronized (sLogLock) {
             try {
                 IStatsManager service = getIStatsManagerLocked();
@@ -198,7 +200,7 @@
                 }
 
                 service.sendWatchdogRollbackOccurredAtom(rollbackType, packageName,
-                        packageVersionCode);
+                        packageVersionCode, rollbackReason, failingPackageName);
                 return true;
             } catch (RemoteException e) {
                 sService = null;
@@ -224,12 +226,35 @@
     /**
      * Write an event to stats log using the raw format.
      *
-     * @param buffer    The encoded buffer of data to write..
+     * @param buffer    The encoded buffer of data to write.
      * @param size      The number of bytes from the buffer to write.
      * @hide
      */
+    // TODO(b/144935988): Mark deprecated.
     @SystemApi
-    public static native void writeRaw(@NonNull byte[] buffer, int size);
+    public static void writeRaw(@NonNull byte[] buffer, int size) {
+        // TODO(b/144935988): make this no-op once clients have migrated to StatsEvent.
+        writeImpl(buffer, size, 0);
+    }
+
+    /**
+     * Write an event to stats log using the raw format.
+     *
+     * @param buffer    The encoded buffer of data to write.
+     * @param size      The number of bytes from the buffer to write.
+     * @param atomId    The id of the atom to which the event belongs.
+     */
+    private static native void writeImpl(@NonNull byte[] buffer, int size, int atomId);
+
+    /**
+     * Write an event to stats log using the raw format encapsulated in StatsEvent.
+     *
+     * @param statsEvent    The StatsEvent object containing the encoded buffer of data to write.
+     * @hide
+     */
+    public static void write(@NonNull final StatsEvent statsEvent) {
+        writeImpl(statsEvent.getBytes(), statsEvent.getNumBytes(), statsEvent.getAtomId());
+    }
 
     private static void enforceDumpCallingPermission(Context context) {
         context.enforceCallingPermission(android.Manifest.permission.DUMP, "Need DUMP permission.");
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 03e68b0..ba25093 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -1525,5 +1525,14 @@
         public int describeContents() {
             return 0;
         }
+
+        @Override
+        public String toString() {
+            return "HdrCapabilities{"
+                    + "mSupportedHdrTypes=" + Arrays.toString(mSupportedHdrTypes)
+                    + ", mMaxLuminance=" + mMaxLuminance
+                    + ", mMaxAverageLuminance=" + mMaxAverageLuminance
+                    + ", mMinLuminance=" + mMinLuminance + '}';
+        }
     }
 }
diff --git a/core/java/android/view/DisplayAddress.java b/core/java/android/view/DisplayAddress.java
index c8b7e25e..e0d9a4d 100644
--- a/core/java/android/view/DisplayAddress.java
+++ b/core/java/android/view/DisplayAddress.java
@@ -41,6 +41,18 @@
     }
 
     /**
+     * Creates an address for a physical display given its port and model.
+     *
+     * @param port A port in the range [0, 255] interpreted as signed.
+     * @param model A positive integer, or {@code null} if the model cannot be identified.
+     * @return The {@link Physical} address.
+     */
+    @NonNull
+    public static Physical fromPortAndModel(byte port, Long model) {
+        return new Physical(port, model);
+    }
+
+    /**
      * Creates an address for a network display given its MAC address.
      *
      * @param macAddress A MAC address in colon notation.
@@ -64,12 +76,23 @@
     public static final class Physical extends DisplayAddress {
         private static final long UNKNOWN_MODEL = 0;
         private static final int MODEL_SHIFT = 8;
-        private static final int PORT_MASK = 0xFF;
 
         private final long mPhysicalDisplayId;
 
         /**
+         * Stable display ID combining port and model.
+         *
+         * @return An ID in the range [0, 2^64) interpreted as signed.
+         * @see SurfaceControl#getPhysicalDisplayIds
+         */
+        public long getPhysicalDisplayId() {
+            return mPhysicalDisplayId;
+        }
+
+        /**
          * Physical port to which the display is connected.
+         *
+         * @return A port in the range [0, 255] interpreted as signed.
          */
         public byte getPort() {
             return (byte) mPhysicalDisplayId;
@@ -78,7 +101,7 @@
         /**
          * Model identifier unique across manufacturers.
          *
-         * @return The model ID, or {@code null} if the model cannot be identified.
+         * @return A positive integer, or {@code null} if the model cannot be identified.
          */
         @Nullable
         public Long getModel() {
@@ -95,7 +118,7 @@
         @Override
         public String toString() {
             final StringBuilder builder = new StringBuilder("{")
-                    .append("port=").append(getPort() & PORT_MASK);
+                    .append("port=").append(Byte.toUnsignedInt(getPort()));
 
             final Long model = getModel();
             if (model != null) {
@@ -119,6 +142,11 @@
             mPhysicalDisplayId = physicalDisplayId;
         }
 
+        private Physical(byte port, Long model) {
+            mPhysicalDisplayId = Byte.toUnsignedLong(port)
+                    | (model == null ? UNKNOWN_MODEL : (model << MODEL_SHIFT));
+        }
+
         public static final @NonNull Parcelable.Creator<Physical> CREATOR =
                 new Parcelable.Creator<Physical>() {
                     @Override
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index 797c128..411508f 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -500,13 +500,13 @@
     /**
      * @hide
      */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
-        mSafeInsets.writeToProto(proto, INSETS);
-        mBounds.getRect(BOUNDS_POSITION_LEFT).writeToProto(proto, BOUND_LEFT);
-        mBounds.getRect(BOUNDS_POSITION_TOP).writeToProto(proto, BOUND_TOP);
-        mBounds.getRect(BOUNDS_POSITION_RIGHT).writeToProto(proto, BOUND_RIGHT);
-        mBounds.getRect(BOUNDS_POSITION_BOTTOM).writeToProto(proto, BOUND_BOTTOM);
+        mSafeInsets.dumpDebug(proto, INSETS);
+        mBounds.getRect(BOUNDS_POSITION_LEFT).dumpDebug(proto, BOUND_LEFT);
+        mBounds.getRect(BOUNDS_POSITION_TOP).dumpDebug(proto, BOUND_TOP);
+        mBounds.getRect(BOUNDS_POSITION_RIGHT).dumpDebug(proto, BOUND_RIGHT);
+        mBounds.getRect(BOUNDS_POSITION_BOTTOM).dumpDebug(proto, BOUND_BOTTOM);
         proto.end(token);
     }
 
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 38baccb..04e82c7 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -651,7 +651,7 @@
      * @param protoOutputStream Stream to write the Rect object to.
      * @param fieldId           Field Id of the DisplayInfoProto as defined in the parent message
      */
-    public void writeToProto(ProtoOutputStream protoOutputStream, long fieldId) {
+    public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId) {
         final long token = protoOutputStream.start(fieldId);
         protoOutputStream.write(LOGICAL_WIDTH, logicalWidth);
         protoOutputStream.write(LOGICAL_HEIGHT, logicalHeight);
diff --git a/core/java/android/view/IPinnedStackListener.aidl b/core/java/android/view/IPinnedStackListener.aidl
index f4bee57..d01c933 100644
--- a/core/java/android/view/IPinnedStackListener.aidl
+++ b/core/java/android/view/IPinnedStackListener.aidl
@@ -67,20 +67,20 @@
     void onActionsChanged(in ParceledListSlice actions);
 
     /**
-     * Called by the window manager to notify the listener to save the reentry fraction,
+     * Called by the window manager to notify the listener to save the reentry fraction and size,
      * typically when an Activity leaves PiP (picture-in-picture) mode to fullscreen.
      * {@param componentName} represents the application component of PiP window
      * while {@param bounds} is the current PiP bounds used to calculate the
-     * reentry snap fraction.
+     * reentry snap fraction and size.
      */
-    void onSaveReentrySnapFraction(in ComponentName componentName, in Rect bounds);
+    void onSaveReentryBounds(in ComponentName componentName, in Rect bounds);
 
     /**
-     * Called by the window manager to notify the listener to reset saved reentry fraction,
+     * Called by the window manager to notify the listener to reset saved reentry fraction and size,
      * typically when an Activity enters PiP (picture-in-picture) mode from fullscreen.
      * {@param componentName} represents the application component of PiP window.
      */
-    void onResetReentrySnapFraction(in ComponentName componentName);
+    void onResetReentryBounds(in ComponentName componentName);
 
     /**
      * Called when the window manager has detected change on DisplayInfo,  or
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 258b1ae..b829c9f 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -66,6 +66,22 @@
 interface IWindowManager
 {
     /**
+     * No overridden behavior is provided in terms of fixing rotation to user rotation. Use
+     * other flags to derive the default behavior, such as {@link WindowManagerService#mIsPc}
+     * and {@link WindowManagerService#mForceDesktopModeOnExternalDisplays}.
+     */
+    const int FIXED_TO_USER_ROTATION_DEFAULT = 0;
+    /**
+     * Don't fix display rotation to {@link DisplayRotation#mUserRotation} only. Always allow
+     * other factors to play a role in deciding display rotation.
+     */
+    const int FIXED_TO_USER_ROTATION_DISABLED = 1;
+    /**
+     * Only use {@link DisplayRotation#mUserRotation} as the display rotation.
+     */
+    const int FIXED_TO_USER_ROTATION_ENABLED = 2;
+
+    /**
      * ===== NOTICE =====
      * The first three methods must remain the first three methods. Scripts
      * and tools rely on their transaction number to work properly.
@@ -273,6 +289,11 @@
     boolean isDisplayRotationFrozen(int displayId);
 
     /**
+    *  Sets if display rotation is fixed to user specified value for given displayId.
+    */
+    void setFixedToUserRotation(int displayId, int fixedToUserRotation);
+
+    /**
      * Screenshot the current wallpaper layer, including the whole screen.
      */
     Bitmap screenshotWallpaper();
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 3c93bb7..bc70d63 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -467,6 +467,10 @@
         }
     }
 
+    boolean isAnimating() {
+        return mAnimationDirection != DIRECTION_NONE;
+    }
+
     private InsetsSourceConsumer createConsumerOfType(int type) {
         if (type == ITYPE_IME) {
             return new ImeInsetsSourceConsumer(mState, Transaction::new, this);
@@ -514,6 +518,7 @@
                 } else {
                     hideDirectly(types);
                 }
+                mAnimationDirection = show ? DIRECTION_SHOW : DIRECTION_HIDE;
                 mAnimator = ObjectAnimator.ofObject(
                         controller,
                         new InsetsProperty(),
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index b1caf18..c6d9898 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -167,7 +167,8 @@
     }
 
     private void applyHiddenToControl() {
-        if (mSourceControl == null || mSourceControl.getLeash() == null) {
+        if (mSourceControl == null || mSourceControl.getLeash() == null
+                || mController.isAnimating()) {
             return;
         }
 
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index ae3e1d0..b873482 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -234,23 +234,23 @@
         pw.print(prefix); pw.print("leash="); pw.println(leash);
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(TASK_ID, taskId);
         proto.write(MODE, mode);
-        leash.writeToProto(proto, LEASH);
+        leash.dumpDebug(proto, LEASH);
         proto.write(IS_TRANSLUCENT, isTranslucent);
-        clipRect.writeToProto(proto, CLIP_RECT);
-        contentInsets.writeToProto(proto, CONTENT_INSETS);
+        clipRect.dumpDebug(proto, CLIP_RECT);
+        contentInsets.dumpDebug(proto, CONTENT_INSETS);
         proto.write(PREFIX_ORDER_INDEX, prefixOrderIndex);
-        position.writeToProto(proto, POSITION);
-        sourceContainerBounds.writeToProto(proto, SOURCE_CONTAINER_BOUNDS);
-        windowConfiguration.writeToProto(proto, WINDOW_CONFIGURATION);
+        position.dumpDebug(proto, POSITION);
+        sourceContainerBounds.dumpDebug(proto, SOURCE_CONTAINER_BOUNDS);
+        windowConfiguration.dumpDebug(proto, WINDOW_CONFIGURATION);
         if (startLeash != null) {
-            startLeash.writeToProto(proto, START_LEASH);
+            startLeash.dumpDebug(proto, START_LEASH);
         }
         if (startBounds != null) {
-            startBounds.writeToProto(proto, START_BOUNDS);
+            startBounds.dumpDebug(proto, START_BOUNDS);
         }
         proto.end(token);
     }
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 6458737..87628da 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -161,6 +161,8 @@
     private static native boolean nativeSetAllowedDisplayConfigs(IBinder displayToken,
                                                                  int[] allowedConfigs);
     private static native int[] nativeGetAllowedDisplayConfigs(IBinder displayToken);
+    private static native boolean nativeSetDesiredDisplayConfigSpecs(IBinder displayToken,
+            SurfaceControl.DesiredDisplayConfigSpecs desiredDisplayConfigSpecs);
     private static native int[] nativeGetDisplayColorModes(IBinder displayToken);
     private static native SurfaceControl.DisplayPrimaries nativeGetDisplayNativePrimaries(
             IBinder displayToken);
@@ -440,6 +442,12 @@
     public static final int METADATA_TASK_ID = 3;
 
     /**
+     * Accessibility ID to allow association between surfaces and accessibility tree.
+     * @hide
+     */
+    public static final int METADATA_ACCESSIBILITY_ID = 4;
+
+    /**
      * A wrapper around GraphicBuffer that contains extra information about how to
      * interpret the screenshot GraphicBuffer.
      * @hide
@@ -893,7 +901,7 @@
      * @param fieldId Field Id of the SurfaceControl as defined in the parent message.
      * @hide
      */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(HASH_CODE, System.identityHashCode(this));
         proto.write(NAME, mName);
@@ -1490,6 +1498,50 @@
     }
 
     /**
+     * Contains information about desired display configuration.
+     *
+     * @hide
+     */
+    public static final class DesiredDisplayConfigSpecs {
+        /**
+         * @hide
+         */
+        public int mDefaultModeId;
+
+        /**
+         * @hide
+         */
+        public float mMinRefreshRate;
+
+        /**
+         * @hide
+         */
+        public float mMaxRefreshRate;
+
+        /**
+         * @hide
+         */
+        public DesiredDisplayConfigSpecs(
+                int defaultModeId, float minRefreshRate, float maxRefreshRate) {
+            mDefaultModeId = defaultModeId;
+            mMinRefreshRate = minRefreshRate;
+            mMaxRefreshRate = maxRefreshRate;
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public static boolean setDesiredDisplayConfigSpecs(IBinder displayToken,
+            SurfaceControl.DesiredDisplayConfigSpecs desiredDisplayConfigSpecs) {
+        if (displayToken == null) {
+            throw new IllegalArgumentException("displayToken must not be null");
+        }
+
+        return nativeSetDesiredDisplayConfigSpecs(displayToken, desiredDisplayConfigSpecs);
+    }
+
+    /**
      * @hide
      */
     public static int[] getDisplayColorModes(IBinder displayToken) {
@@ -1863,7 +1915,9 @@
      *
      * @param layer            The root layer to capture.
      * @param sourceCrop       The portion of the root surface to capture; caller may pass in 'new
-     *                         Rect()' or null if no cropping is desired.
+     *                         Rect()' or null if no cropping is desired. If the root layer does not
+     *                         have a buffer or a crop set, then a non-empty source crop must be
+     *                         specified.
      * @param frameScale       The desired scale of the returned buffer; the raw
      *                         screen will be scaled up/down.
      *
@@ -1880,7 +1934,9 @@
      *
      * @param layer            The root layer to capture.
      * @param sourceCrop       The portion of the root surface to capture; caller may pass in 'new
-     *                         Rect()' or null if no cropping is desired.
+     *                         Rect()' or null if no cropping is desired. If the root layer does not
+     *                         have a buffer or a crop set, then a non-empty source crop must be
+     *                         specified.
      * @param frameScale       The desired scale of the returned buffer; the raw
      *                         screen will be scaled up/down.
      * @param format           The desired pixel format of the returned buffer.
@@ -2601,6 +2657,7 @@
          * @hide
          */
         public Transaction setMetadata(SurfaceControl sc, int key, Parcel data) {
+            sc.checkNotReleased();
             nativeSetMetadata(mNativeObject, sc.mNativeObject, key, data);
             return this;
         }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index afa661e..3171306 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1646,7 +1646,7 @@
                 mBlastSurfaceControl, width, height);
 
         }
-        mBlastBufferQueue.update(mSurfaceControl, width, height);
+        mBlastBufferQueue.update(mBlastSurfaceControl, width, height);
 
         mTransaction.show(mBlastSurfaceControl)
             .reparent(mBlastSurfaceControl, mSurfaceControl)
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index c62e69c..d40f832 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1181,7 +1181,8 @@
          * a soft input method, so it will be Z-ordered and positioned
          * independently of any active input method (typically this means it
          * gets Z-ordered on top of the input method, so it can use the full
-         * screen for its content and cover the input method if needed.) */
+         * screen for its content and cover the input method if needed.  You
+         * can use {@link #FLAG_ALT_FOCUSABLE_IM} to modify this behavior. */
         public static final int FLAG_NOT_FOCUSABLE      = 0x00000008;
 
         /** Window flag: this window can never receive touch events. */
@@ -1287,11 +1288,14 @@
          * set for you by Window as described in {@link Window#setFlags}.*/
         public static final int FLAG_LAYOUT_INSET_DECOR = 0x00010000;
 
-        /** Window flag: When set, input method can't interact with the focusable window
-         * and can be placed to use more space and cover the input method.
-         * Note: When combined with {@link #FLAG_NOT_FOCUSABLE}, this flag has no
-         * effect since input method cannot interact with windows having {@link #FLAG_NOT_FOCUSABLE}
-         * flag set.
+        /** Window flag: invert the state of {@link #FLAG_NOT_FOCUSABLE} with
+         * respect to how this window interacts with the current method.  That
+         * is, if FLAG_NOT_FOCUSABLE is set and this flag is set, then the
+         * window will behave as if it needs to interact with the input method
+         * and thus be placed behind/away from it; if FLAG_NOT_FOCUSABLE is
+         * not set and this flag is set, then the window will behave as if it
+         * doesn't need to interact with the input method and can be placed
+         * to use more space and cover the input method.
          */
         public static final int FLAG_ALT_FOCUSABLE_IM = 0x00020000;
 
@@ -1989,12 +1993,16 @@
          *
          * @param flags The current window manager flags.
          *
-         * @return Returns {@code true} if such a window should be behind/interact
-         * with an input method, (@code false} if not.
+         * @return Returns true if such a window should be behind/interact
+         * with an input method, false if not.
          */
         public static boolean mayUseInputMethod(int flags) {
-            return (flags & FLAG_NOT_FOCUSABLE) != FLAG_NOT_FOCUSABLE
-                    && (flags & FLAG_ALT_FOCUSABLE_IM) != FLAG_ALT_FOCUSABLE_IM;
+            switch (flags&(FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM)) {
+                case 0:
+                case FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM:
+                    return true;
+            }
+            return false;
         }
 
         /**
@@ -3251,7 +3259,7 @@
         /**
          * @hide
          */
-        public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        public void dumpDebug(ProtoOutputStream proto, long fieldId) {
             final long token = proto.start(fieldId);
             proto.write(TYPE, type);
             proto.write(X, x);
diff --git a/core/java/android/view/WindowlessViewRoot.java b/core/java/android/view/WindowlessViewRoot.java
index addf8e2..68f2bde 100644
--- a/core/java/android/view/WindowlessViewRoot.java
+++ b/core/java/android/view/WindowlessViewRoot.java
@@ -32,6 +32,14 @@
 public class WindowlessViewRoot {
     private ViewRootImpl mViewRoot;
     private WindowlessWindowManager mWm;
+
+    /** @hide */
+    public WindowlessViewRoot(@NonNull Context c, @NonNull Display d,
+            @NonNull WindowlessWindowManager wwm) {
+        mWm = wwm;
+        mViewRoot = new ViewRootImpl(c, d, mWm);
+    }
+
     public WindowlessViewRoot(@NonNull Context c, @NonNull Display d,
             @NonNull SurfaceControl rootSurface,
             @Nullable IBinder hostInputToken) {
@@ -55,4 +63,12 @@
     public void dispose() {
         mViewRoot.dispatchDetachedFromWindow();
     }
+
+    /**
+     * Tell this viewroot to clean itself up.
+     * @hide
+     */
+    public void die() {
+        mViewRoot.die(false /* immediate */);
+    }
 }
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index cf39979..2ba0975 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -34,7 +34,7 @@
 * By parcelling the root surface, the app can offer another app content for embedding.
 * @hide
 */
-class WindowlessWindowManager implements IWindowSession {
+public class WindowlessWindowManager implements IWindowSession {
     private final static String TAG = "WindowlessWindowManager";
 
     private class State {
@@ -45,6 +45,7 @@
             mParams.copyFrom(p);
         }
     };
+
     /**
      * Used to store SurfaceControl we've built for clients to
      * reconfigure them if relayout is called.
@@ -67,13 +68,18 @@
     private int mForceHeight = -1;
     private int mForceWidth = -1;
 
-    WindowlessWindowManager(Configuration c, SurfaceControl rootSurface, IBinder hostInputToken) {
+    public WindowlessWindowManager(Configuration c, SurfaceControl rootSurface,
+            IBinder hostInputToken) {
         mRootSurface = rootSurface;
         mConfiguration = new Configuration(c);
         mRealWm = WindowManagerGlobal.getWindowSession();
         mHostInputToken = hostInputToken;
     }
 
+    protected void setConfiguration(Configuration configuration) {
+        mConfiguration.setTo(configuration);
+    }
+
     /**
      * Utility API.
      */
@@ -125,6 +131,17 @@
     @Override
     public void remove(android.view.IWindow window) throws RemoteException {
         mRealWm.remove(window);
+        State state;
+        synchronized (this) {
+            state = mStateForWindow.remove(window.asBinder());
+        }
+        if (state == null) {
+            throw new IllegalArgumentException(
+                    "Invalid window token (never added or removed already)");
+        }
+        try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) {
+            t.remove(state.mSurfaceControl).apply();
+        }
     }
 
     private boolean isOpaque(WindowManager.LayoutParams attrs) {
@@ -165,10 +182,14 @@
         int height = surfaceInsets != null ?
                 attrs.height + surfaceInsets.top + surfaceInsets.bottom : attrs.height;
 
-        t.show(sc)
-            .setBufferSize(sc, width, height)
-            .setOpaque(sc, isOpaque(attrs))
-            .apply();
+        t.setBufferSize(sc, width, height)
+            .setOpaque(sc, isOpaque(attrs));
+        if (viewFlags == View.VISIBLE) {
+            t.show(sc);
+        } else {
+            t.hide(sc);
+        }
+        t.apply();
         outSurfaceControl.copyFrom(sc);
         outFrame.set(0, 0, attrs.width, attrs.height);
 
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 32b0f41..34654ed 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -17,6 +17,7 @@
 package android.view.accessibility;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
@@ -796,10 +797,32 @@
 
     private ArrayList<AccessibilityRecord> mRecords;
 
-    /*
-     * Hide constructor from clients.
+    /**
+     * Creates a new {@link AccessibilityEvent}.
      */
-    private AccessibilityEvent() {
+    public AccessibilityEvent() {
+        if (DEBUG_ORIGIN) originStackTrace = Thread.currentThread().getStackTrace();
+    }
+
+
+    /**
+     * Creates a new {@link AccessibilityEvent} with the given <code>eventType</code>.
+     *
+     * @param eventType The event type.
+     */
+    public AccessibilityEvent(int eventType) {
+        mEventType = eventType;
+        if (DEBUG_ORIGIN) originStackTrace = Thread.currentThread().getStackTrace();
+    }
+
+    /**
+     * Copy constructor. Creates a new {@link AccessibilityEvent}, and this instance is initialized
+     * from the given <code>event</code>.
+     *
+     * @param event The other event.
+     */
+    public AccessibilityEvent(@NonNull AccessibilityEvent event) {
+        init(event);
     }
 
     /**
@@ -816,6 +839,15 @@
         mWindowChangeTypes = event.mWindowChangeTypes;
         mEventTime = event.mEventTime;
         mPackageName = event.mPackageName;
+        if (event.mRecords != null) {
+            final int recordCount = event.mRecords.size();
+            mRecords = new ArrayList<>(recordCount);
+            for (int i = 0; i < recordCount; i++) {
+                final AccessibilityRecord record = event.mRecords.get(i);
+                final AccessibilityRecord recordClone = new AccessibilityRecord(record);
+                mRecords.add(recordClone);
+            }
+        }
         if (DEBUG_ORIGIN) originStackTrace = event.originStackTrace;
     }
 
@@ -1109,6 +1141,9 @@
      * Returns a cached instance if such is available or a new one is
      * instantiated with its type property set.
      *
+     * <p>In most situations object pooling is not beneficial. Create a new instance using the
+     * constructor {@link #AccessibilityEvent(int)} instead.
+     *
      * @param eventType The event type.
      * @return An instance.
      */
@@ -1123,23 +1158,15 @@
      * created. The returned instance is initialized from the given
      * <code>event</code>.
      *
+     * <p>In most situations object pooling is not beneficial. Create a new instance using the
+     * constructor {@link #AccessibilityEvent(AccessibilityEvent)} instead.
+     *
      * @param event The other event.
      * @return An instance.
      */
     public static AccessibilityEvent obtain(AccessibilityEvent event) {
         AccessibilityEvent eventClone = AccessibilityEvent.obtain();
         eventClone.init(event);
-
-        if (event.mRecords != null) {
-            final int recordCount = event.mRecords.size();
-            eventClone.mRecords = new ArrayList<AccessibilityRecord>(recordCount);
-            for (int i = 0; i < recordCount; i++) {
-                final AccessibilityRecord record = event.mRecords.get(i);
-                final AccessibilityRecord recordClone = AccessibilityRecord.obtain(record);
-                eventClone.mRecords.add(recordClone);
-            }
-        }
-
         return eventClone;
     }
 
@@ -1147,6 +1174,9 @@
      * Returns a cached instance if such is available or a new one is
      * instantiated.
      *
+     * <p>In most situations object pooling is not beneficial. Create a new instance using the
+     * constructor {@link #AccessibilityEvent()} instead.
+     *
      * @return An instance.
      */
     public static AccessibilityEvent obtain() {
@@ -1162,6 +1192,8 @@
      *   <b>Note: You must not touch the object after calling this function.</b>
      * </p>
      *
+     * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
+     *
      * @throws IllegalStateException If the event is already recycled.
      */
     @Override
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index a389555..f2f84cd 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -529,6 +529,20 @@
     public static final String ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN =
             "android.view.accessibility.action.ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN";
 
+    /**
+     * Argument to represent the duration in milliseconds to press and hold a node.
+     * <p>
+     * <strong>Type:</strong> int<br>
+     * <strong>Actions:</strong>
+     * <ul>
+     *     <li>{@link AccessibilityAction#ACTION_PRESS_AND_HOLD}</li>
+     * </ul>
+     *
+     * @see AccessibilityAction#ACTION_PRESS_AND_HOLD
+     */
+    public static final String ACTION_ARGUMENT_PRESS_HOLD_DURATION_MILLIS_INT =
+            "android.view.accessibility.action.ARGUMENT_PRESS_HOLD_DURATION_MILLIS_INT";
+
     // Focus types
 
     /**
@@ -775,15 +789,38 @@
     private TouchDelegateInfo mTouchDelegateInfo;
 
     /**
-     * Hide constructor from clients.
+     * Creates a new {@link AccessibilityNodeInfo}.
      */
-    private AccessibilityNodeInfo() {
-        /* do nothing */
+    public AccessibilityNodeInfo() {
     }
 
-    /** @hide */
-    AccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        init(info);
+    /**
+     * Creates a new {@link AccessibilityNodeInfo} with the given <code>source</code>.
+     *
+     * @param source The source view.
+     */
+    public AccessibilityNodeInfo(@NonNull View source) {
+        setSource(source);
+    }
+
+    /**
+     * Creates a new {@link AccessibilityNodeInfo} with the given <code>source</code>.
+     *
+     * @param root The root of the virtual subtree.
+     * @param virtualDescendantId The id of the virtual descendant.
+     */
+    public AccessibilityNodeInfo(@NonNull View root, int virtualDescendantId) {
+        setSource(root, virtualDescendantId);
+    }
+
+    /**
+     * Copy constructor. Creates a new {@link AccessibilityNodeInfo}, and this new instance is
+     * initialized from the given <code>info</code>.
+     *
+     * @param info The other info.
+     */
+    public AccessibilityNodeInfo(@NonNull AccessibilityNodeInfo info) {
+        init(info, false /* usePoolingInfo */);
     }
 
     /**
@@ -911,7 +948,7 @@
         // when it is obtained. Enforce sealing again before we init to fail when a node has been
         // recycled during a refresh to catch such errors earlier.
         enforceSealed();
-        init(refreshedInfo);
+        init(refreshedInfo, true /* usePoolingInfo */);
         refreshedInfo.recycle();
         return true;
     }
@@ -3299,6 +3336,9 @@
      * Returns a cached instance if such is available otherwise a new one
      * and sets the source.
      *
+     * <p>In most situations object pooling is not beneficial. Create a new instance using the
+     * constructor {@link #AccessibilityNodeInfo(View)} instead.
+     *
      * @param source The source view.
      * @return An instance.
      *
@@ -3314,6 +3354,9 @@
      * Returns a cached instance if such is available otherwise a new one
      * and sets the source.
      *
+     * <p>In most situations object pooling is not beneficial. Create a new instance using the
+     * constructor {@link #AccessibilityNodeInfo(View, int)} instead.
+     *
      * @param root The root of the virtual subtree.
      * @param virtualDescendantId The id of the virtual descendant.
      * @return An instance.
@@ -3329,6 +3372,9 @@
     /**
      * Returns a cached instance if such is available otherwise a new one.
      *
+     * <p>In most situations object pooling is not beneficial. Create a new instance using the
+     * constructor {@link #AccessibilityNodeInfo()} instead.
+     *
      * @return An instance.
      */
     public static AccessibilityNodeInfo obtain() {
@@ -3344,12 +3390,15 @@
      * create. The returned instance is initialized from the given
      * <code>info</code>.
      *
+     * <p>In most situations object pooling is not beneficial. Create a new instance using the
+     * constructor {@link #AccessibilityNodeInfo(AccessibilityNodeInfo)} instead.
+     *
      * @param info The other info.
      * @return An instance.
      */
     public static AccessibilityNodeInfo obtain(AccessibilityNodeInfo info) {
         AccessibilityNodeInfo infoClone = AccessibilityNodeInfo.obtain();
-        infoClone.init(info);
+        infoClone.init(info, true /* usePoolingInfo */);
         return infoClone;
     }
 
@@ -3358,6 +3407,8 @@
      * <p>
      * <strong>Note:</strong> You must not touch the object after calling this function.
      *
+     * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
+     *
      * @throws IllegalStateException If the info is already recycled.
      */
     public void recycle() {
@@ -3647,8 +3698,9 @@
      * Initializes this instance from another one.
      *
      * @param other The other instance.
+     * @param usePoolingInfos whether using pooled object internally or not
      */
-    private void init(AccessibilityNodeInfo other) {
+    private void init(AccessibilityNodeInfo other, boolean usePoolingInfos) {
         mSealed = other.mSealed;
         mSourceNodeId = other.mSourceNodeId;
         mParentNodeId = other.mParentNodeId;
@@ -3707,6 +3759,18 @@
 
         mExtras = other.mExtras != null ? new Bundle(other.mExtras) : null;
 
+        if (usePoolingInfos) {
+            initPoolingInfos(other);
+        } else {
+            initCopyInfos(other);
+        }
+
+        final TouchDelegateInfo otherInfo = other.mTouchDelegateInfo;
+        mTouchDelegateInfo = (otherInfo != null)
+                ? new TouchDelegateInfo(otherInfo.mTargetMap, true) : null;
+    }
+
+    private void initPoolingInfos(AccessibilityNodeInfo other) {
         if (mRangeInfo != null) mRangeInfo.recycle();
         mRangeInfo = (other.mRangeInfo != null)
                 ? RangeInfo.obtain(other.mRangeInfo) : null;
@@ -3716,10 +3780,20 @@
         if (mCollectionItemInfo != null) mCollectionItemInfo.recycle();
         mCollectionItemInfo =  (other.mCollectionItemInfo != null)
                 ? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null;
+    }
 
-        final TouchDelegateInfo otherInfo = other.mTouchDelegateInfo;
-        mTouchDelegateInfo = (otherInfo != null)
-                ? new TouchDelegateInfo(otherInfo.mTargetMap, true) : null;
+    private void initCopyInfos(AccessibilityNodeInfo other) {
+        RangeInfo ri = other.mRangeInfo;
+        mRangeInfo = (ri == null) ? null
+                : new RangeInfo(ri.mType, ri.mMin, ri.mMax, ri.mCurrent);
+        CollectionInfo ci = other.mCollectionInfo;
+        mCollectionInfo = (ci == null) ? null
+                : new CollectionInfo(ci.mRowCount, ci.mColumnCount,
+                                     ci.mHierarchical, ci.mSelectionMode);
+        CollectionItemInfo cii = other.mCollectionItemInfo;
+        mCollectionItemInfo = (cii == null)  ? null
+                : new CollectionItemInfo(cii.mRowIndex, cii.mRowSpan, cii.mColumnIndex,
+                                         cii.mColumnSpan, cii.mHeading, cii.mSelected);
     }
 
     /**
@@ -3854,7 +3928,7 @@
      * Clears the state of this instance.
      */
     private void clear() {
-        init(DEFAULT);
+        init(DEFAULT, true /* usePoolingInfo */);
     }
 
     private static boolean isDefaultStandardAction(AccessibilityAction action) {
@@ -3975,6 +4049,8 @@
                 return "ACTION_SHOW_TOOLTIP";
             case R.id.accessibilityActionHideTooltip:
                 return "ACTION_HIDE_TOOLTIP";
+            case R.id.accessibilityActionPressAndHold:
+                return "ACTION_PRESS_AND_HOLD";
             default:
                 return "ACTION_UNKNOWN";
         }
@@ -4566,6 +4642,31 @@
         public static final AccessibilityAction ACTION_HIDE_TOOLTIP =
                 new AccessibilityAction(R.id.accessibilityActionHideTooltip);
 
+        /**
+         * Action that presses and holds a node.
+         * <p>
+         * This action is for nodes that have distinct behavior that depends on how long a press is
+         * held. Nodes having a single action for long press should use {@link #ACTION_LONG_CLICK}
+         *  instead of this action, and nodes should not expose both actions.
+         * <p>
+         * Use {@link #ACTION_ARGUMENT_PRESS_HOLD_DURATION_MILLIS_INT} to specify how long the
+         * node is pressed. To ensure reasonable behavior, the first value of this argument should
+         * be 0 and the others should greater than 0 and less than 10,000. UIs requested to hold for
+         * times outside of this range should ignore the action.
+         * <p>
+         * The total time the element is held could be specified by an accessibility user up-front,
+         * or may depend on what happens on the UI as the user continues to request the hold.
+         * <p>
+         *   <strong>Note:</strong> The time between dispatching the action and it arriving in the
+         *     UI process is not guaranteed. It is possible on a busy system for the time to expire
+         *     unexpectedly. For the case of holding down a key for a repeating action, a delayed
+         *     arrival should be benign. Please do not use this sort of action in cases where such
+         *     delays will lead to unexpected UI behavior.
+         * <p>
+         */
+        @NonNull public static final AccessibilityAction ACTION_PRESS_AND_HOLD =
+                new AccessibilityAction(R.id.accessibilityActionPressAndHold);
+
         private final int mActionId;
         private final CharSequence mLabel;
 
@@ -4709,6 +4810,10 @@
         /**
          * Obtains a pooled instance that is a clone of another one.
          *
+         * <p>In most situations object pooling is not beneficial. Create a new instance using the
+         * constructor {@link AccessibilityNodeInfo.RangeInfo#AccessibilityNodeInfo.RangeInfo(int,
+         * float, float, float)} instead.
+         *
          * @param other The instance to clone.
          *
          * @hide
@@ -4720,6 +4825,10 @@
         /**
          * Obtains a pooled instance.
          *
+         * <p>In most situations object pooling is not beneficial. Create a new instance using the
+         * constructor {@link AccessibilityNodeInfo.RangeInfo#AccessibilityNodeInfo.RangeInfo(int,
+         * float, float, float)} instead.
+         *
          * @param type The type of the range.
          * @param min The minimum value. Use {@code Float.NEGATIVE_INFINITY} if the range has no
          *            minimum.
@@ -4750,7 +4859,7 @@
          *            maximum.
          * @param current The current value.
          */
-        private RangeInfo(int type, float min, float max, float current) {
+        public RangeInfo(int type, float min, float max, float current) {
             mType = type;
             mMin = min;
             mMax = max;
@@ -4799,6 +4908,8 @@
 
         /**
          * Recycles this instance.
+         *
+         * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
          */
         void recycle() {
             clear();
@@ -4849,6 +4960,10 @@
         /**
          * Obtains a pooled instance that is a clone of another one.
          *
+         * <p>In most situations object pooling is not beneficial. Create a new instance using the
+         * constructor {@link
+         * AccessibilityNodeInfo.CollectionInfo#AccessibilityNodeInfo.CollectionInfo} instead.
+         *
          * @param other The instance to clone.
          * @hide
          */
@@ -4860,6 +4975,11 @@
         /**
          * Obtains a pooled instance.
          *
+         * <p>In most situations object pooling is not beneficial. Create a new instance using the
+         * constructor {@link
+         * AccessibilityNodeInfo.CollectionInfo#AccessibilityNodeInfo.CollectionInfo(int, int,
+         * boolean)} instead.
+         *
          * @param rowCount The number of rows, or -1 if count is unknown.
          * @param columnCount The number of columns, or -1 if count is unknown.
          * @param hierarchical Whether the collection is hierarchical.
@@ -4872,6 +4992,11 @@
         /**
          * Obtains a pooled instance.
          *
+         * <p>In most situations object pooling is not beneficial. Create a new instance using the
+         * constructor {@link
+         * AccessibilityNodeInfo.CollectionInfo#AccessibilityNodeInfo.CollectionInfo(int, int,
+         * boolean, int)} instead.
+         *
          * @param rowCount The number of rows.
          * @param columnCount The number of columns.
          * @param hierarchical Whether the collection is hierarchical.
@@ -4902,9 +5027,20 @@
          * @param rowCount The number of rows.
          * @param columnCount The number of columns.
          * @param hierarchical Whether the collection is hierarchical.
+         */
+        public CollectionInfo(int rowCount, int columnCount, boolean hierarchical) {
+            this(rowCount, columnCount, hierarchical, SELECTION_MODE_NONE);
+        }
+
+        /**
+         * Creates a new instance.
+         *
+         * @param rowCount The number of rows.
+         * @param columnCount The number of columns.
+         * @param hierarchical Whether the collection is hierarchical.
          * @param selectionMode The collection's selection mode.
          */
-        private CollectionInfo(int rowCount, int columnCount, boolean hierarchical,
+        public CollectionInfo(int rowCount, int columnCount, boolean hierarchical,
                 int selectionMode) {
             mRowCount = rowCount;
             mColumnCount = columnCount;
@@ -4955,6 +5091,8 @@
 
         /**
          * Recycles this instance.
+         *
+         * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
          */
         void recycle() {
             clear();
@@ -4991,6 +5129,11 @@
         /**
          * Obtains a pooled instance that is a clone of another one.
          *
+         * <p>In most situations object pooling is not beneficial. Create a new instance using the
+         * constructor {@link
+         * AccessibilityNodeInfo.CollectionItemInfo#AccessibilityNodeInfo.CollectionItemInfo}
+         * instead.
+         *
          * @param other The instance to clone.
          * @hide
          */
@@ -5002,6 +5145,11 @@
         /**
          * Obtains a pooled instance.
          *
+         * <p>In most situations object pooling is not beneficial. Create a new instance using the
+         * constructor {@link
+         * AccessibilityNodeInfo.CollectionItemInfo#AccessibilityNodeInfo.CollectionItemInfo(int,
+         * int, int, int, boolean)} instead.
+         *
          * @param rowIndex The row index at which the item is located.
          * @param rowSpan The number of rows the item spans.
          * @param columnIndex The column index at which the item is located.
@@ -5017,6 +5165,11 @@
         /**
          * Obtains a pooled instance.
          *
+         * <p>In most situations object pooling is not beneficial. Creates a new instance using the
+         * constructor {@link
+         * AccessibilityNodeInfo.CollectionItemInfo#AccessibilityNodeInfo.CollectionItemInfo(int,
+         * int, int, int, boolean, boolean)} instead.
+         *
          * @param rowIndex The row index at which the item is located.
          * @param rowSpan The number of rows the item spans.
          * @param columnIndex The column index at which the item is located.
@@ -5058,7 +5211,22 @@
          * @param columnSpan The number of columns the item spans.
          * @param heading Whether the item is a heading.
          */
-        private CollectionItemInfo(int rowIndex, int rowSpan, int columnIndex, int columnSpan,
+        public CollectionItemInfo(int rowIndex, int rowSpan, int columnIndex, int columnSpan,
+                boolean heading) {
+            this(rowIndex, rowSpan, columnIndex, columnSpan, heading, false);
+        }
+
+        /**
+         * Creates a new instance.
+         *
+         * @param rowIndex The row index at which the item is located.
+         * @param rowSpan The number of rows the item spans.
+         * @param columnIndex The column index at which the item is located.
+         * @param columnSpan The number of columns the item spans.
+         * @param heading Whether the item is a heading.
+         * @param selected Whether the item is selected.
+         */
+        public CollectionItemInfo(int rowIndex, int rowSpan, int columnIndex, int columnSpan,
                 boolean heading, boolean selected) {
             mRowIndex = rowIndex;
             mRowSpan = rowSpan;
@@ -5126,6 +5294,8 @@
 
         /**
          * Recycles this instance.
+         *
+         * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
          */
         void recycle() {
             clear();
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index d7d7e21..4f6c9ef 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -18,6 +18,7 @@
 
 import static com.android.internal.util.CollectionUtils.isEmpty;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcelable;
@@ -113,10 +114,20 @@
 
     int mConnectionId = UNDEFINED;
 
-    /*
-     * Hide constructor.
+    /**
+     * Creates a new {@link AccessibilityRecord}.
      */
-    AccessibilityRecord() {
+    public AccessibilityRecord() {
+    }
+
+    /**
+     * Copy constructor. Creates a new {@link AccessibilityRecord}, and this instance is initialized
+     * with data from the given <code>record</code>.
+     *
+     * @param record The other record.
+     */
+    public AccessibilityRecord(@NonNull AccessibilityRecord record) {
+        init(record);
     }
 
     /**
@@ -790,6 +801,9 @@
      * instantiated. The instance is initialized with data from the
      * given record.
      *
+     * <p>In most situations object pooling is not beneficial. Create a new instance using the
+     * constructor {@link #AccessibilityRecord(AccessibilityRecord)} instead.
+     *
      * @return An instance.
      */
     public static AccessibilityRecord obtain(AccessibilityRecord record) {
@@ -802,6 +816,9 @@
      * Returns a cached instance if such is available or a new one is
      * instantiated.
      *
+     * <p>In most situations object pooling is not beneficial. Create a new instance using the
+     * constructor {@link #AccessibilityRecord()} instead.
+     *
      * @return An instance.
      */
     public static AccessibilityRecord obtain() {
@@ -823,6 +840,8 @@
      * <p>
      * <strong>Note:</strong> You must not touch the object after calling this function.
      *
+     * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
+     *
      * @throws IllegalStateException If the record is already recycled.
      */
     public void recycle() {
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index 5fa8a6e..2cc6e9a 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -119,12 +119,19 @@
 
     private int mConnectionId = UNDEFINED_WINDOW_ID;
 
-    private AccessibilityWindowInfo() {
-        /* do nothing - hide constructor */
+    /**
+     * Creates a new {@link AccessibilityWindowInfo}.
+     */
+    public AccessibilityWindowInfo() {
     }
 
-    /** @hide */
-    AccessibilityWindowInfo(AccessibilityWindowInfo info) {
+    /**
+     * Copy constructor. Creates a new {@link AccessibilityWindowInfo}, and this new instance is
+     * initialized from given <code>info</code>.
+     *
+     * @param info The other info.
+     */
+    public AccessibilityWindowInfo(@NonNull AccessibilityWindowInfo info) {
         init(info);
     }
 
@@ -469,6 +476,9 @@
      * Returns a cached instance if such is available or a new one is
      * created.
      *
+     * <p>In most situations object pooling is not beneficial. Create a new instance using the
+     * constructor {@link #AccessibilityWindowInfo()} instead.
+     *
      * @return An instance.
      */
     public static AccessibilityWindowInfo obtain() {
@@ -487,6 +497,9 @@
      * created. The returned instance is initialized from the given
      * <code>info</code>.
      *
+     * <p>In most situations object pooling is not beneficial. Create a new instance using the
+     * constructor {@link #AccessibilityWindowInfo(AccessibilityWindowInfo)} instead.
+     *
      * @param info The other info.
      * @return An instance.
      */
@@ -514,6 +527,8 @@
      * <strong>Note:</strong> You must not touch the object after calling this function.
      * </p>
      *
+     * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
+     *
      * @throws IllegalStateException If the info is already recycled.
      */
     public void recycle() {
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 54446e1..9c04b39 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -47,6 +47,7 @@
 import android.service.autofill.AutofillService;
 import android.service.autofill.FillEventHistory;
 import android.service.autofill.UserData;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.DebugUtils;
@@ -61,6 +62,7 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeProvider;
 import android.view.accessibility.AccessibilityWindowInfo;
+import android.widget.EditText;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.MetricsLogger;
@@ -1073,6 +1075,8 @@
                 } else if (sVerbose) {
                     Log.v(TAG, "Ignoring visibility change on " + id + ": no tracked views");
                 }
+            } else if (!virtual && isVisible) {
+                startAutofillIfNeededLocked(view);
             }
         }
     }
@@ -1238,9 +1242,11 @@
                 return;
             }
             if (!mEnabled || !isActiveLocked()) {
-                if (sVerbose) {
-                    Log.v(TAG, "notifyValueChanged(" + view.getAutofillId()
-                            + "): ignoring on state " + getStateAsStringLocked());
+                if (!startAutofillIfNeededLocked(view)) {
+                    if (sVerbose) {
+                        Log.v(TAG, "notifyValueChanged(" + view.getAutofillId()
+                                + "): ignoring on state " + getStateAsStringLocked());
+                    }
                 }
                 return;
             }
@@ -1879,6 +1885,37 @@
         }
     }
 
+    @GuardedBy("mLock")
+    private boolean startAutofillIfNeededLocked(View view) {
+        if (mState == STATE_UNKNOWN
+                && mSessionId == NO_SESSION
+                && view instanceof EditText
+                && !TextUtils.isEmpty(((EditText) view).getText())
+                && !view.isFocused()
+                && view.isImportantForAutofill()
+                && view.isLaidOut()
+                && view.isVisibleToUser()) {
+
+            ensureServiceClientAddedIfNeededLocked();
+
+            if (sVerbose) {
+                Log.v(TAG, "startAutofillIfNeededLocked(): enabled=" + mEnabled);
+            }
+            if (mEnabled && !isClientDisablingEnterExitEvent()) {
+                final AutofillId id = view.getAutofillId();
+                final AutofillValue value = view.getAutofillValue();
+                // Starts new session.
+                startSessionLocked(id, /* bounds= */ null, /* value= */ null, /* flags= */ 0);
+                // Updates value.
+                updateSessionLocked(id, /* bounds= */ null, value, ACTION_VALUE_CHANGED,
+                        /* flags= */ 0);
+                addEnteredIdLocked(id);
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Registers a {@link AutofillCallback} to receive autofill events.
      *
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 2af7ac7..4b47927 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -125,7 +125,7 @@
          *
          * @param webview the WebView to transport
          */
-        public synchronized void setWebView(WebView webview) {
+        public synchronized void setWebView(@Nullable WebView webview) {
             mWebview = webview;
         }
 
@@ -134,6 +134,7 @@
          *
          * @return the transported WebView object
          */
+        @Nullable
         public synchronized WebView getWebView() {
             return mWebview;
         }
@@ -309,7 +310,7 @@
      *
      * @param context an Activity Context to access application assets
      */
-    public WebView(Context context) {
+    public WebView(@NonNull Context context) {
         this(context, null);
     }
 
@@ -319,7 +320,7 @@
      * @param context an Activity Context to access application assets
      * @param attrs an AttributeSet passed to our parent
      */
-    public WebView(Context context, AttributeSet attrs) {
+    public WebView(@NonNull Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, com.android.internal.R.attr.webViewStyle);
     }
 
@@ -332,7 +333,7 @@
      *        reference to a style resource that supplies default values for
      *        the view. Can be 0 to not look for defaults.
      */
-    public WebView(Context context, AttributeSet attrs, int defStyleAttr) {
+    public WebView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
@@ -349,7 +350,8 @@
      *        defStyleAttr is 0 or can not be found in the theme. Can be 0
      *        to not look for defaults.
      */
-    public WebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public WebView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
         this(context, attrs, defStyleAttr, defStyleRes, null, false);
     }
 
@@ -370,7 +372,7 @@
      * and {@link WebStorage} for fine-grained control of privacy data.
      */
     @Deprecated
-    public WebView(Context context, AttributeSet attrs, int defStyleAttr,
+    public WebView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
             boolean privateBrowsing) {
         this(context, attrs, defStyleAttr, 0, null, privateBrowsing);
     }
@@ -395,8 +397,8 @@
      *       be added synchronously, before a subsequent loadUrl call takes effect.
      */
     @UnsupportedAppUsage
-    protected WebView(Context context, AttributeSet attrs, int defStyleAttr,
-            Map<String, Object> javaScriptInterfaces, boolean privateBrowsing) {
+    protected WebView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+            @Nullable Map<String, Object> javaScriptInterfaces, boolean privateBrowsing) {
         this(context, attrs, defStyleAttr, 0, javaScriptInterfaces, privateBrowsing);
     }
 
@@ -405,8 +407,9 @@
      */
     @SuppressWarnings("deprecation")  // for super() call into deprecated base class constructor.
     @UnsupportedAppUsage
-    protected WebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes,
-            Map<String, Object> javaScriptInterfaces, boolean privateBrowsing) {
+    protected WebView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+            int defStyleRes, @Nullable Map<String, Object> javaScriptInterfaces,
+            boolean privateBrowsing) {
         super(context, attrs, defStyleAttr, defStyleRes);
 
         // WebView is important by default, unless app developer overrode attribute.
@@ -642,7 +645,7 @@
      *         method fails.
      */
     @Nullable
-    public WebBackForwardList saveState(Bundle outState) {
+    public WebBackForwardList saveState(@NonNull Bundle outState) {
         checkThread();
         return mProvider.saveState(outState);
     }
@@ -695,7 +698,7 @@
      * @return the restored back/forward list or {@code null} if restoreState failed
      */
     @Nullable
-    public WebBackForwardList restoreState(Bundle inState) {
+    public WebBackForwardList restoreState(@NonNull Bundle inState) {
         checkThread();
         return mProvider.restoreState(inState);
     }
@@ -713,7 +716,7 @@
      *            controlling caching, accept types or the User-Agent, their
      *            values may be overridden by this WebView's defaults.
      */
-    public void loadUrl(String url, Map<String, String> additionalHttpHeaders) {
+    public void loadUrl(@NonNull String url, @NonNull Map<String, String> additionalHttpHeaders) {
         checkThread();
         mProvider.loadUrl(url, additionalHttpHeaders);
     }
@@ -725,7 +728,7 @@
      *
      * @param url the URL of the resource to load
      */
-    public void loadUrl(String url) {
+    public void loadUrl(@NonNull String url) {
         checkThread();
         mProvider.loadUrl(url);
     }
@@ -739,7 +742,7 @@
      * @param postData the data will be passed to "POST" request, which must be
      *     be "application/x-www-form-urlencoded" encoded.
      */
-    public void postUrl(String url, byte[] postData) {
+    public void postUrl(@NonNull String url, @NonNull byte[] postData) {
         checkThread();
         if (URLUtil.isNetworkUrl(url)) {
             mProvider.postUrl(url, postData);
@@ -803,7 +806,8 @@
      * @param mimeType the MIME type of the data, e.g. 'text/html'.
      * @param encoding the encoding of the data
      */
-    public void loadData(String data, @Nullable String mimeType, @Nullable String encoding) {
+    public void loadData(@NonNull String data, @Nullable String mimeType,
+            @Nullable String encoding) {
         checkThread();
         mProvider.loadData(data, mimeType, encoding);
     }
@@ -850,7 +854,7 @@
      * @param historyUrl the URL to use as the history entry. If {@code null} defaults
      *                   to 'about:blank'. If non-null, this must be a valid URL.
      */
-    public void loadDataWithBaseURL(@Nullable String baseUrl, String data,
+    public void loadDataWithBaseURL(@Nullable String baseUrl, @NonNull String data,
             @Nullable String mimeType, @Nullable String encoding, @Nullable String historyUrl) {
         checkThread();
         mProvider.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl);
@@ -873,7 +877,8 @@
      *                       completes with the result of the execution (if any).
      *                       May be {@code null} if no notification of the result is required.
      */
-    public void evaluateJavascript(String script, @Nullable ValueCallback<String> resultCallback) {
+    public void evaluateJavascript(@NonNull String script, @Nullable ValueCallback<String>
+            resultCallback) {
         checkThread();
         mProvider.evaluateJavaScript(script, resultCallback);
     }
@@ -883,7 +888,7 @@
      *
      * @param filename the filename where the archive should be placed
      */
-    public void saveWebArchive(String filename) {
+    public void saveWebArchive(@NonNull String filename) {
         checkThread();
         mProvider.saveWebArchive(filename);
     }
@@ -900,8 +905,8 @@
      *                 under which the file was saved, or {@code null} if saving the
      *                 file failed.
      */
-    public void saveWebArchive(String basename, boolean autoname, @Nullable ValueCallback<String>
-            callback) {
+    public void saveWebArchive(@NonNull String basename, boolean autoname,
+            @Nullable ValueCallback<String> callback) {
         checkThread();
         mProvider.saveWebArchive(basename, autoname, callback);
     }
@@ -1064,7 +1069,7 @@
      *                  requests with callbacks.
      * @param callback  The callback to be invoked.
      */
-    public void postVisualStateCallback(long requestId, VisualStateCallback callback) {
+    public void postVisualStateCallback(long requestId, @NonNull VisualStateCallback callback) {
         checkThread();
         mProvider.insertVisualStateCallback(requestId, callback);
     }
@@ -1131,7 +1136,8 @@
      * @param documentName  The user-facing name of the printed document. See
      *                      {@link android.print.PrintDocumentInfo}
      */
-    public PrintDocumentAdapter createPrintDocumentAdapter(String documentName) {
+    @NonNull
+    public PrintDocumentAdapter createPrintDocumentAdapter(@NonNull String documentName) {
         checkThread();
         return mProvider.createPrintDocumentAdapter(documentName);
     }
@@ -1203,6 +1209,7 @@
      * and the email is set in the "extra" field of HitTestResult. Otherwise,
      * HitTestResult type is set to UNKNOWN_TYPE.
      */
+    @NonNull
     public HitTestResult getHitTestResult() {
         checkThread();
         return mProvider.getHitTestResult();
@@ -1233,7 +1240,7 @@
      * @param msg the message to be dispatched with the result of the request
      *            as the data member with "url" as key. The result can be {@code null}.
      */
-    public void requestImageRef(Message msg) {
+    public void requestImageRef(@NonNull Message msg) {
         checkThread();
         mProvider.requestImageRef(msg);
     }
@@ -1243,10 +1250,11 @@
      * passed to WebViewClient.onPageStarted because although the load for
      * that URL has begun, the current page may not have changed.
      *
-     * @return the URL for the current page
+     * @return the URL for the current page or {@code null} if no page has been loaded
      */
     @InspectableProperty(hasAttributeId = false)
     @ViewDebug.ExportedProperty(category = "webview")
+    @Nullable
     public String getUrl() {
         checkThread();
         return mProvider.getUrl();
@@ -1259,10 +1267,12 @@
      * Also, there may have been redirects resulting in a different URL to that
      * originally requested.
      *
-     * @return the URL that was originally requested for the current page
+     * @return the URL that was originally requested for the current page or
+     * {@code null} if no page has been loaded
      */
     @InspectableProperty(hasAttributeId = false)
     @ViewDebug.ExportedProperty(category = "webview")
+    @Nullable
     public String getOriginalUrl() {
         checkThread();
         return mProvider.getOriginalUrl();
@@ -1272,10 +1282,11 @@
      * Gets the title for the current page. This is the title of the current page
      * until WebViewClient.onReceivedTitle is called.
      *
-     * @return the title for the current page
+     * @return the title for the current page or {@code null} if no page has been loaded
      */
     @InspectableProperty(hasAttributeId = false)
     @ViewDebug.ExportedProperty(category = "webview")
+    @Nullable
     public String getTitle() {
         checkThread();
         return mProvider.getTitle();
@@ -1285,9 +1296,11 @@
      * Gets the favicon for the current page. This is the favicon of the current
      * page until WebViewClient.onReceivedIcon is called.
      *
-     * @return the favicon for the current page
+     * @return the favicon for the current page or {@code null} if the page doesn't
+     * have one or if no page has been loaded
      */
     @InspectableProperty(hasAttributeId = false)
+    @Nullable
     public Bitmap getFavicon() {
         checkThread();
         return mProvider.getFavicon();
@@ -1523,6 +1536,7 @@
      * different objects. The object returned from this method will not be
      * updated to reflect any new state.
      */
+    @NonNull
     public WebBackForwardList copyBackForwardList() {
         checkThread();
         return mProvider.copyBackForwardList();
@@ -1535,7 +1549,7 @@
      *
      * @param listener an implementation of {@link FindListener}
      */
-    public void setFindListener(FindListener listener) {
+    public void setFindListener(@Nullable FindListener listener) {
         checkThread();
         setupFindListenerIfNeeded();
         mFindListener.mUserFindListener = listener;
@@ -1580,7 +1594,7 @@
      * @param find the string to find.
      * @see #setFindListener
      */
-    public void findAllAsync(String find) {
+    public void findAllAsync(@NonNull String find) {
         checkThread();
         mProvider.findAllAsync(find);
     }
@@ -1682,7 +1696,7 @@
      *
      * @param response the message that will be dispatched with the result
      */
-    public void documentHasImages(Message response) {
+    public void documentHasImages(@NonNull Message response) {
         checkThread();
         mProvider.documentHasImages(response);
     }
@@ -1694,7 +1708,7 @@
      * @param client an implementation of WebViewClient
      * @see #getWebViewClient
      */
-    public void setWebViewClient(WebViewClient client) {
+    public void setWebViewClient(@NonNull WebViewClient client) {
         checkThread();
         mProvider.setWebViewClient(client);
     }
@@ -1705,6 +1719,7 @@
      * @return the WebViewClient, or a default client if not yet set
      * @see #setWebViewClient
      */
+    @NonNull
     public WebViewClient getWebViewClient() {
         checkThread();
         return mProvider.getWebViewClient();
@@ -1798,7 +1813,7 @@
      *
      * @param listener an implementation of DownloadListener
      */
-    public void setDownloadListener(DownloadListener listener) {
+    public void setDownloadListener(@Nullable DownloadListener listener) {
         checkThread();
         mProvider.setDownloadListener(listener);
     }
@@ -1811,7 +1826,7 @@
      * @param client an implementation of WebChromeClient
      * @see #getWebChromeClient
      */
-    public void setWebChromeClient(WebChromeClient client) {
+    public void setWebChromeClient(@Nullable WebChromeClient client) {
         checkThread();
         mProvider.setWebChromeClient(client);
     }
@@ -1898,7 +1913,7 @@
      *               context. {@code null} values are ignored.
      * @param name the name used to expose the object in JavaScript
      */
-    public void addJavascriptInterface(Object object, String name) {
+    public void addJavascriptInterface(@NonNull Object object, @NonNull String name) {
         checkThread();
         mProvider.addJavascriptInterface(object, name);
     }
@@ -1926,6 +1941,7 @@
      *
      * @return the two message ports that form the message channel.
      */
+    @NonNull
     public WebMessagePort[] createWebMessageChannel() {
         checkThread();
         return mProvider.createWebMessageChannel();
@@ -1950,7 +1966,7 @@
      * @param message the WebMessage
      * @param targetOrigin the target origin.
      */
-    public void postWebMessage(WebMessage message, Uri targetOrigin) {
+    public void postWebMessage(@NonNull WebMessage message, @NonNull Uri targetOrigin) {
         checkThread();
         mProvider.postMessageToMainFrame(message, targetOrigin);
     }
@@ -1962,6 +1978,7 @@
      * @return a WebSettings object that can be used to control this WebView's
      *         settings
      */
+    @NonNull
     public WebSettings getSettings() {
         checkThread();
         return mProvider.getSettings();
@@ -2026,7 +2043,7 @@
      *                               in the current process.
      * @throws IllegalArgumentException if the suffix contains a path separator.
      */
-    public static void setDataDirectorySuffix(String suffix) {
+    public static void setDataDirectorySuffix(@NonNull String suffix) {
         WebViewFactory.setDataDirectorySuffix(suffix);
     }
 
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 187ab46..eb0d9bf 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -152,6 +152,9 @@
     // handles.
     private static final boolean FLAG_USE_MAGNIFIER = true;
 
+    private static final int DELAY_BEFORE_HANDLE_FADES_OUT = 4000;
+    private static final int RECENT_CUT_COPY_DURATION_MS = 15 * 1000; // 15 seconds in millis
+
     static final int BLINK = 500;
     private static final int DRAG_SHADOW_MAX_TEXT_LENGTH = 20;
     private static final float LINE_SLOP_MULTIPLIER_FOR_HANDLEVIEWS = 0.5f;
@@ -326,8 +329,6 @@
     // Global listener that detects changes in the global position of the TextView
     private PositionListener mPositionListener;
 
-    private float mLastDownPositionX, mLastDownPositionY;
-    private float mLastUpPositionX, mLastUpPositionY;
     private float mContextMenuAnchorX, mContextMenuAnchorY;
     Callback mCustomSelectionActionModeCallback;
     Callback mCustomInsertionActionModeCallback;
@@ -336,18 +337,11 @@
     @UnsupportedAppUsage
     boolean mCreatedWithASelection;
 
-    // Indicates the current tap state (first tap, double tap, or triple click).
-    private int mTapState = TAP_STATE_INITIAL;
-    private long mLastTouchUpTime = 0;
-    private static final int TAP_STATE_INITIAL = 0;
-    private static final int TAP_STATE_FIRST_TAP = 1;
-    private static final int TAP_STATE_DOUBLE_TAP = 2;
-    // Only for mouse input.
-    private static final int TAP_STATE_TRIPLE_CLICK = 3;
-
     // The button state as of the last time #onTouchEvent is called.
     private int mLastButtonState;
 
+    private final EditorTouchState mTouchState = new EditorTouchState();
+
     private Runnable mInsertionActionModeRunnable;
 
     // The span controller helps monitoring the changes to which the Editor needs to react:
@@ -1193,10 +1187,10 @@
             logCursor("performLongClick", "handled=%s", handled);
         }
         // Long press in empty space moves cursor and starts the insertion action mode.
-        if (!handled && !isPositionOnText(mLastDownPositionX, mLastDownPositionY)
+        if (!handled && !isPositionOnText(mTouchState.getLastDownX(), mTouchState.getLastDownY())
                 && mInsertionControllerEnabled) {
-            final int offset = mTextView.getOffsetForPosition(mLastDownPositionX,
-                    mLastDownPositionY);
+            final int offset = mTextView.getOffsetForPosition(mTouchState.getLastDownX(),
+                    mTouchState.getLastDownY());
             Selection.setSelection((Spannable) mTextView.getText(), offset);
             getInsertionController().show();
             mIsInsertionActionModeStartPending = true;
@@ -1240,11 +1234,11 @@
     }
 
     float getLastUpPositionX() {
-        return mLastUpPositionX;
+        return mTouchState.getLastUpX();
     }
 
     float getLastUpPositionY() {
-        return mLastUpPositionY;
+        return mTouchState.getLastUpY();
     }
 
     private long getLastTouchOffsets() {
@@ -1279,6 +1273,9 @@
                 // Has to be done before onTakeFocus, which can be overloaded.
                 final int lastTapPosition = getLastTapPosition();
                 if (lastTapPosition >= 0) {
+                    if (TextView.DEBUG_CURSOR) {
+                        logCursor("onFocusChanged", "setting cursor position: %d", lastTapPosition);
+                    }
                     Selection.setSelection((Spannable) mTextView.getText(), lastTapPosition);
                 }
 
@@ -1443,39 +1440,6 @@
         }
     }
 
-    private void updateTapState(MotionEvent event) {
-        final int action = event.getActionMasked();
-        if (action == MotionEvent.ACTION_DOWN) {
-            final boolean isMouse = event.isFromSource(InputDevice.SOURCE_MOUSE);
-            // Detect double tap and triple click.
-            if (((mTapState == TAP_STATE_FIRST_TAP)
-                    || ((mTapState == TAP_STATE_DOUBLE_TAP) && isMouse))
-                            && (SystemClock.uptimeMillis() - mLastTouchUpTime)
-                                    <= ViewConfiguration.getDoubleTapTimeout()) {
-                if (mTapState == TAP_STATE_FIRST_TAP) {
-                    mTapState = TAP_STATE_DOUBLE_TAP;
-                } else {
-                    mTapState = TAP_STATE_TRIPLE_CLICK;
-                }
-                if (TextView.DEBUG_CURSOR) {
-                    logCursor("updateTapState", "ACTION_DOWN: %s tap detected",
-                            (mTapState == TAP_STATE_DOUBLE_TAP ? "double" : "triple"));
-                }
-            } else {
-                mTapState = TAP_STATE_FIRST_TAP;
-                if (TextView.DEBUG_CURSOR) {
-                    logCursor("updateTapState", "ACTION_DOWN: first tap detected");
-                }
-            }
-        }
-        if (action == MotionEvent.ACTION_UP) {
-            mLastTouchUpTime = SystemClock.uptimeMillis();
-            if (TextView.DEBUG_CURSOR) {
-                logCursor("updateTapState", "ACTION_UP");
-            }
-        }
-    }
-
     private boolean shouldFilterOutTouchEvent(MotionEvent event) {
         if (!event.isFromSource(InputDevice.SOURCE_MOUSE)) {
             return false;
@@ -1503,7 +1467,8 @@
             }
             return;
         }
-        updateTapState(event);
+        ViewConfiguration viewConfiguration = ViewConfiguration.get(mTextView.getContext());
+        mTouchState.update(event, viewConfiguration);
         updateFloatingToolbarVisibility(event);
 
         if (hasSelectionController()) {
@@ -1515,15 +1480,7 @@
             mShowSuggestionRunnable = null;
         }
 
-        if (event.getActionMasked() == MotionEvent.ACTION_UP) {
-            mLastUpPositionX = event.getX();
-            mLastUpPositionY = event.getY();
-        }
-
         if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
-            mLastDownPositionX = event.getX();
-            mLastDownPositionY = event.getY();
-
             // Reset this state; it will be re-set if super.onTouchEvent
             // causes focus to move to the view.
             mTouchFocusSelected = false;
@@ -5067,7 +5024,10 @@
         public boolean onTouchEvent(MotionEvent ev) {
             if (TextView.DEBUG_CURSOR) {
                 logCursor(this.getClass().getSimpleName() + ": HandleView: onTouchEvent",
-                        MotionEvent.actionToString(ev.getActionMasked()));
+                        "%d: %s (%f,%f)",
+                        ev.getSequenceNumber(),
+                        MotionEvent.actionToString(ev.getActionMasked()),
+                        ev.getX(), ev.getY());
             }
 
             updateFloatingToolbarVisibility(ev);
@@ -5145,56 +5105,14 @@
     }
 
     private class InsertionHandleView extends HandleView {
-        private static final int DELAY_BEFORE_HANDLE_FADES_OUT = 4000;
-        private static final int RECENT_CUT_COPY_DURATION = 15 * 1000; // seconds
-
         // Used to detect taps on the insertion handle, which will affect the insertion action mode
-        private float mDownPositionX, mDownPositionY;
+        private float mLastDownRawX, mLastDownRawY;
         private Runnable mHider;
 
         public InsertionHandleView(Drawable drawable) {
             super(drawable, drawable, com.android.internal.R.id.insertion_handle);
         }
 
-        @Override
-        public void show() {
-            super.show();
-
-            final long durationSinceCutOrCopy =
-                    SystemClock.uptimeMillis() - TextView.sLastCutCopyOrTextChangedTime;
-
-            // Cancel the single tap delayed runnable.
-            if (mInsertionActionModeRunnable != null
-                    && ((mTapState == TAP_STATE_DOUBLE_TAP)
-                            || (mTapState == TAP_STATE_TRIPLE_CLICK)
-                            || isCursorInsideEasyCorrectionSpan())) {
-                mTextView.removeCallbacks(mInsertionActionModeRunnable);
-            }
-
-            // Prepare and schedule the single tap runnable to run exactly after the double tap
-            // timeout has passed.
-            if ((mTapState != TAP_STATE_DOUBLE_TAP) && (mTapState != TAP_STATE_TRIPLE_CLICK)
-                    && !isCursorInsideEasyCorrectionSpan()
-                    && (durationSinceCutOrCopy < RECENT_CUT_COPY_DURATION)) {
-                if (mTextActionMode == null) {
-                    if (mInsertionActionModeRunnable == null) {
-                        mInsertionActionModeRunnable = new Runnable() {
-                            @Override
-                            public void run() {
-                                startInsertionActionMode();
-                            }
-                        };
-                    }
-                    mTextView.postDelayed(
-                            mInsertionActionModeRunnable,
-                            ViewConfiguration.getDoubleTapTimeout() + 1);
-                }
-
-            }
-
-            hideAfterDelay();
-        }
-
         private void hideAfterDelay() {
             if (mHider == null) {
                 mHider = new Runnable() {
@@ -5250,8 +5168,8 @@
 
             switch (ev.getActionMasked()) {
                 case MotionEvent.ACTION_DOWN:
-                    mDownPositionX = ev.getRawX();
-                    mDownPositionY = ev.getRawY();
+                    mLastDownRawX = ev.getRawX();
+                    mLastDownRawY = ev.getRawY();
                     updateMagnifier(ev);
                     break;
 
@@ -5261,8 +5179,8 @@
 
                 case MotionEvent.ACTION_UP:
                     if (!offsetHasBeenChanged()) {
-                        final float deltaX = mDownPositionX - ev.getRawX();
-                        final float deltaY = mDownPositionY - ev.getRawY();
+                        final float deltaX = mLastDownRawX - ev.getRawX();
+                        final float deltaY = mLastDownRawY - ev.getRawY();
                         final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
 
                         final ViewConfiguration viewConfiguration = ViewConfiguration.get(
@@ -5804,6 +5722,37 @@
         public void show() {
             getHandle().show();
 
+            final long durationSinceCutOrCopy =
+                    SystemClock.uptimeMillis() - TextView.sLastCutCopyOrTextChangedTime;
+
+            // Cancel the single tap delayed runnable.
+            if (mInsertionActionModeRunnable != null
+                    && (mTouchState.isMultiTap() || isCursorInsideEasyCorrectionSpan())) {
+                mTextView.removeCallbacks(mInsertionActionModeRunnable);
+            }
+
+            // Prepare and schedule the single tap runnable to run exactly after the double tap
+            // timeout has passed.
+            if (!mTouchState.isMultiTap()
+                    && !isCursorInsideEasyCorrectionSpan()
+                    && (durationSinceCutOrCopy < RECENT_CUT_COPY_DURATION_MS)) {
+                if (mTextActionMode == null) {
+                    if (mInsertionActionModeRunnable == null) {
+                        mInsertionActionModeRunnable = new Runnable() {
+                            @Override
+                            public void run() {
+                                startInsertionActionMode();
+                            }
+                        };
+                    }
+                    mTextView.postDelayed(
+                            mInsertionActionModeRunnable,
+                            ViewConfiguration.getDoubleTapTimeout() + 1);
+                }
+            }
+
+            getHandle().hideAfterDelay();
+
             if (mSelectionModifierCursorController != null) {
                 mSelectionModifierCursorController.hide();
             }
@@ -5870,7 +5819,6 @@
         // The offsets of that last touch down event. Remembered to start selection there.
         private int mMinTouchOffset, mMaxTouchOffset;
 
-        private float mDownPositionX, mDownPositionY;
         private boolean mGestureStayedInTapRegion;
 
         // Where the user first starts the drag motion.
@@ -5940,13 +5888,18 @@
         }
 
         public void enterDrag(int dragAcceleratorMode) {
+            if (TextView.DEBUG_CURSOR) {
+                logCursor("SelectionModifierCursorController: enterDrag",
+                        "starting selection drag: mode=%s", dragAcceleratorMode);
+            }
+
             // Just need to init the handles / hide insertion cursor.
             show();
             mDragAcceleratorMode = dragAcceleratorMode;
             // Start location of selection.
-            mStartOffset = mTextView.getOffsetForPosition(mLastDownPositionX,
-                    mLastDownPositionY);
-            mLineSelectionIsOn = mTextView.getLineAtCoordinate(mLastDownPositionY);
+            mStartOffset = mTextView.getOffsetForPosition(mTouchState.getLastDownX(),
+                    mTouchState.getLastDownY());
+            mLineSelectionIsOn = mTextView.getLineAtCoordinate(mTouchState.getLastDownY());
             // Don't show the handles until user has lifted finger.
             hide();
 
@@ -5974,36 +5927,20 @@
                                 eventX, eventY);
 
                         // Double tap detection
-                        if (mGestureStayedInTapRegion) {
-                            if (mTapState == TAP_STATE_DOUBLE_TAP
-                                    || mTapState == TAP_STATE_TRIPLE_CLICK) {
-                                final float deltaX = eventX - mDownPositionX;
-                                final float deltaY = eventY - mDownPositionY;
-                                final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
-
-                                ViewConfiguration viewConfiguration = ViewConfiguration.get(
-                                        mTextView.getContext());
-                                int doubleTapSlop = viewConfiguration.getScaledDoubleTapSlop();
-                                boolean stayedInArea =
-                                        distanceSquared < doubleTapSlop * doubleTapSlop;
-
-                                if (stayedInArea && (isMouse || isPositionOnText(eventX, eventY))) {
-                                    if (TextView.DEBUG_CURSOR) {
-                                        logCursor("SelectionModifierCursorController: onTouchEvent",
-                                                "ACTION_DOWN: select and start drag");
-                                    }
-                                    if (mTapState == TAP_STATE_DOUBLE_TAP) {
-                                        selectCurrentWordAndStartDrag();
-                                    } else if (mTapState == TAP_STATE_TRIPLE_CLICK) {
-                                        selectCurrentParagraphAndStartDrag();
-                                    }
-                                    mDiscardNextActionUp = true;
-                                }
+                        if (mGestureStayedInTapRegion
+                                && mTouchState.isMultiTapInSameArea()
+                                && (isMouse || isPositionOnText(eventX, eventY))) {
+                            if (TextView.DEBUG_CURSOR) {
+                                logCursor("SelectionModifierCursorController: onTouchEvent",
+                                        "ACTION_DOWN: select and start drag");
                             }
+                            if (mTouchState.isDoubleTap()) {
+                                selectCurrentWordAndStartDrag();
+                            } else if (mTouchState.isTripleClick()) {
+                                selectCurrentParagraphAndStartDrag();
+                            }
+                            mDiscardNextActionUp = true;
                         }
-
-                        mDownPositionX = eventX;
-                        mDownPositionY = eventY;
                         mGestureStayedInTapRegion = true;
                         mHaventMovedEnoughToStartDrag = true;
                     }
@@ -6025,8 +5962,8 @@
                     final int touchSlop = viewConfig.getScaledTouchSlop();
 
                     if (mGestureStayedInTapRegion || mHaventMovedEnoughToStartDrag) {
-                        final float deltaX = eventX - mDownPositionX;
-                        final float deltaY = eventY - mDownPositionY;
+                        final float deltaX = eventX - mTouchState.getLastDownX();
+                        final float deltaY = eventY - mTouchState.getLastDownY();
                         final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
 
                         if (mGestureStayedInTapRegion) {
@@ -7164,7 +7101,7 @@
         }
     }
 
-    private static void logCursor(String location, @Nullable String msgFormat, Object ... msgArgs) {
+    static void logCursor(String location, @Nullable String msgFormat, Object ... msgArgs) {
         if (msgFormat == null) {
             Log.d(TAG, location);
         } else {
diff --git a/core/java/android/widget/EditorTouchState.java b/core/java/android/widget/EditorTouchState.java
new file mode 100644
index 0000000..f880939
--- /dev/null
+++ b/core/java/android/widget/EditorTouchState.java
@@ -0,0 +1,137 @@
+/*
+ * 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.widget;
+
+import static android.widget.Editor.logCursor;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+
+import android.annotation.IntDef;
+import android.view.InputDevice;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Helper class used by {@link Editor} to track state for touch events.
+ *
+ * @hide
+ */
+@VisibleForTesting(visibility = PACKAGE)
+public class EditorTouchState {
+    private float mLastDownX, mLastDownY;
+    private float mLastUpX, mLastUpY;
+    private long mLastUpMillis;
+
+    @IntDef({MultiTapStatus.NONE, MultiTapStatus.FIRST_TAP, MultiTapStatus.DOUBLE_TAP,
+            MultiTapStatus.TRIPLE_CLICK})
+    @Retention(RetentionPolicy.SOURCE)
+    @VisibleForTesting
+    public @interface MultiTapStatus {
+        int NONE = 0;
+        int FIRST_TAP = 1;
+        int DOUBLE_TAP = 2;
+        int TRIPLE_CLICK = 3; // Only for mouse input.
+    }
+    @MultiTapStatus
+    private int mMultiTapStatus = MultiTapStatus.NONE;
+    private boolean mMultiTapInSameArea;
+
+    public float getLastDownX() {
+        return mLastDownX;
+    }
+
+    public float getLastDownY() {
+        return mLastDownY;
+    }
+
+    public float getLastUpX() {
+        return mLastUpX;
+    }
+
+    public float getLastUpY() {
+        return mLastUpY;
+    }
+
+    public boolean isDoubleTap() {
+        return mMultiTapStatus == MultiTapStatus.DOUBLE_TAP;
+    }
+
+    public boolean isTripleClick() {
+        return mMultiTapStatus == MultiTapStatus.TRIPLE_CLICK;
+    }
+
+    public boolean isMultiTap() {
+        return mMultiTapStatus == MultiTapStatus.DOUBLE_TAP
+                || mMultiTapStatus == MultiTapStatus.TRIPLE_CLICK;
+    }
+
+    public boolean isMultiTapInSameArea() {
+        return isMultiTap() && mMultiTapInSameArea;
+    }
+
+    /**
+     * Updates the state based on the new event.
+     */
+    public void update(MotionEvent event, ViewConfiguration viewConfiguration) {
+        final int action = event.getActionMasked();
+        if (action == MotionEvent.ACTION_DOWN) {
+            final boolean isMouse = event.isFromSource(InputDevice.SOURCE_MOUSE);
+            final long millisSinceLastUp = event.getEventTime() - mLastUpMillis;
+            // Detect double tap and triple click.
+            if (millisSinceLastUp <= ViewConfiguration.getDoubleTapTimeout()
+                    && (mMultiTapStatus == MultiTapStatus.FIRST_TAP
+                    || (mMultiTapStatus == MultiTapStatus.DOUBLE_TAP && isMouse))) {
+                if (mMultiTapStatus == MultiTapStatus.FIRST_TAP) {
+                    mMultiTapStatus = MultiTapStatus.DOUBLE_TAP;
+                } else {
+                    mMultiTapStatus = MultiTapStatus.TRIPLE_CLICK;
+                }
+                final float deltaX = event.getX() - mLastDownX;
+                final float deltaY = event.getY() - mLastDownY;
+                final int distanceSquared = (int) ((deltaX * deltaX) + (deltaY * deltaY));
+                int doubleTapSlop = viewConfiguration.getScaledDoubleTapSlop();
+                mMultiTapInSameArea = distanceSquared < doubleTapSlop * doubleTapSlop;
+                if (TextView.DEBUG_CURSOR) {
+                    String status = isDoubleTap() ? "double" : "triple";
+                    String inSameArea = mMultiTapInSameArea ? "in same area" : "not in same area";
+                    logCursor("EditorTouchState", "ACTION_DOWN: %s tap detected, %s",
+                            status, inSameArea);
+                }
+            } else {
+                mMultiTapStatus = MultiTapStatus.FIRST_TAP;
+                mMultiTapInSameArea = false;
+                if (TextView.DEBUG_CURSOR) {
+                    logCursor("EditorTouchState", "ACTION_DOWN: first tap detected");
+                }
+            }
+            mLastDownX = event.getX();
+            mLastDownY = event.getY();
+        } else if (action == MotionEvent.ACTION_UP) {
+            if (TextView.DEBUG_CURSOR) {
+                logCursor("EditorTouchState", "ACTION_UP");
+            }
+            mLastUpX = event.getX();
+            mLastUpY = event.getY();
+            mLastUpMillis = event.getEventTime();
+        }
+    }
+}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index c571737..7cec440 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -3473,18 +3473,10 @@
         return applyAsync(context, parent, executor, listener, null);
     }
 
-    private CancellationSignal startTaskOnExecutor(AsyncApplyTask task, Executor executor) {
-        CancellationSignal cancelSignal = new CancellationSignal();
-        cancelSignal.setOnCancelListener(task);
-
-        task.executeOnExecutor(executor == null ? AsyncTask.THREAD_POOL_EXECUTOR : executor);
-        return cancelSignal;
-    }
-
     /** @hide */
     public CancellationSignal applyAsync(Context context, ViewGroup parent,
             Executor executor, OnViewAppliedListener listener, OnClickHandler handler) {
-        return startTaskOnExecutor(getAsyncApplyTask(context, parent, listener, handler), executor);
+        return getAsyncApplyTask(context, parent, listener, handler).startTaskOnExecutor(executor);
     }
 
     private AsyncApplyTask getAsyncApplyTask(Context context, ViewGroup parent,
@@ -3495,6 +3487,7 @@
 
     private class AsyncApplyTask extends AsyncTask<Void, Void, ViewTree>
             implements CancellationSignal.OnCancelListener {
+        final CancellationSignal mCancelSignal = new CancellationSignal();
         final RemoteViews mRV;
         final ViewGroup mParent;
         final Context mContext;
@@ -3545,6 +3538,7 @@
 
         @Override
         protected void onPostExecute(ViewTree viewTree) {
+            mCancelSignal.setOnCancelListener(null);
             if (mError == null) {
                 if (mListener != null) {
                     mListener.onViewInflated(viewTree.mRoot);
@@ -3581,6 +3575,13 @@
         @Override
         public void onCancel() {
             cancel(true);
+            mCancelSignal.setOnCancelListener(null);
+        }
+
+        private CancellationSignal startTaskOnExecutor(Executor executor) {
+            mCancelSignal.setOnCancelListener(this);
+            executeOnExecutor(executor == null ? AsyncTask.THREAD_POOL_EXECUTOR : executor);
+            return mCancelSignal;
         }
     }
 
@@ -3646,8 +3647,8 @@
             }
         }
 
-        return startTaskOnExecutor(new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(),
-                context, listener, handler, v), executor);
+        return new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(),
+                context, listener, handler, v).startTaskOnExecutor(executor);
     }
 
     private void performApply(View v, ViewGroup parent, OnClickHandler handler) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 90e8ef2..ee169f2 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -10860,7 +10860,10 @@
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         if (DEBUG_CURSOR) {
-            logCursor("onTouchEvent", MotionEvent.actionToString(event.getActionMasked()));
+            logCursor("onTouchEvent", "%d: %s (%f,%f)",
+                    event.getSequenceNumber(),
+                    MotionEvent.actionToString(event.getActionMasked()),
+                    event.getX(), event.getY());
         }
 
         final int action = event.getActionMasked();
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 15b1d75..2f1a15f 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -19,10 +19,10 @@
 import com.android.internal.os.BatteryStatsImpl;
 
 import android.bluetooth.BluetoothActivityEnergyInfo;
-import android.net.wifi.WifiActivityEnergyInfo;
 import android.os.ParcelFileDescriptor;
 import android.os.WorkSource;
 import android.os.connectivity.CellularBatteryStats;
+import android.os.connectivity.WifiActivityEnergyInfo;
 import android.os.connectivity.WifiBatteryStats;
 import android.os.connectivity.GpsBatteryStats;
 import android.os.health.HealthStatsParceler;
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 9e38f38..3c028d7 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -32,6 +32,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.PermissionChecker;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
@@ -657,8 +658,9 @@
     private void setAlwaysButtonEnabled(boolean hasValidSelection, int checkedPos,
             boolean filtered) {
         boolean enabled = false;
+        ResolveInfo ri = null;
         if (hasValidSelection) {
-            ResolveInfo ri = mAdapter.resolveInfoForPosition(checkedPos, filtered);
+            ri = mAdapter.resolveInfoForPosition(checkedPos, filtered);
             if (ri == null) {
                 Log.e(TAG, "Invalid position supplied to setAlwaysButtonEnabled");
                 return;
@@ -676,6 +678,24 @@
                         .getString(R.string.activity_resolver_use_always));
             }
         }
+
+        ActivityInfo activityInfo = ri.activityInfo;
+
+        boolean hasRecordPermission =
+                PermissionChecker.checkPermissionForPreflight(
+                        getApplicationContext(),
+                        android.Manifest.permission.RECORD_AUDIO, -1,
+                        activityInfo.applicationInfo.uid,
+                        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;
+        }
         mAlwaysButton.setEnabled(enabled);
     }
 
@@ -1048,7 +1068,6 @@
         Intent startIntent = getIntent();
         boolean isAudioCaptureDevice =
                 startIntent.getBooleanExtra(EXTRA_IS_AUDIO_CAPTURE_DEVICE, false);
-
         return new ResolverListAdapter(context, payloadIntents, initialIntents, rList,
                 filterLastUsed, createListController(), useLayoutForBrowsables, this,
                 isAudioCaptureDevice);
diff --git a/core/java/com/android/internal/app/procstats/AssociationState.java b/core/java/com/android/internal/app/procstats/AssociationState.java
index 1d4239f..dea3566 100644
--- a/core/java/com/android/internal/app/procstats/AssociationState.java
+++ b/core/java/com/android/internal/app/procstats/AssociationState.java
@@ -945,7 +945,7 @@
         }
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId, long now) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId, long now) {
         final long token = proto.start(fieldId);
 
         proto.write(PackageAssociationProcessStatsProto.COMPONENT_NAME, mName);
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
index 392b8d3..a6bed5b 100644
--- a/core/java/com/android/internal/app/procstats/ProcessState.java
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -1341,7 +1341,7 @@
         return sb.toString();
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId,
+    public void dumpDebug(ProtoOutputStream proto, long fieldId,
             String procName, int uid, long now) {
         final long token = proto.start(fieldId);
         proto.write(ProcessStatsProto.PROCESS, procName);
diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java
index 875cff8..3045410 100644
--- a/core/java/com/android/internal/app/procstats/ProcessStats.java
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.java
@@ -2168,7 +2168,7 @@
     /**
      * Writes to ProtoOutputStream.
      */
-    public void writeToProto(ProtoOutputStream proto, long now, int section) {
+    public void dumpDebug(ProtoOutputStream proto, long now, int section) {
         proto.write(ProcessStatsSectionProto.START_REALTIME_MS, mTimePeriodStartRealtime);
         proto.write(ProcessStatsSectionProto.END_REALTIME_MS,
                 mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime);
@@ -2215,7 +2215,7 @@
                 for (int iu = 0; iu < uids.size(); iu++) {
                     final int uid = uids.keyAt(iu);
                     final ProcessState procState = uids.valueAt(iu);
-                    procState.writeToProto(proto, ProcessStatsSectionProto.PROCESS_STATS, procName,
+                    procState.dumpDebug(proto, ProcessStatsSectionProto.PROCESS_STATS, procName,
                             uid, now);
                 }
             }
@@ -2230,7 +2230,7 @@
                     final LongSparseArray<PackageState> vers = uids.valueAt(iu);
                     for (int iv = 0; iv < vers.size(); iv++) {
                         final PackageState pkgState = vers.valueAt(iv);
-                        pkgState.writeToProto(proto, ProcessStatsSectionProto.PACKAGE_STATS, now,
+                        pkgState.dumpDebug(proto, ProcessStatsSectionProto.PACKAGE_STATS, now,
                                 section);
                     }
                 }
@@ -2283,7 +2283,7 @@
         /**
          * Writes the containing stats into proto, with options to choose smaller sections.
          */
-        public void writeToProto(ProtoOutputStream proto, long fieldId, long now, int section) {
+        public void dumpDebug(ProtoOutputStream proto, long fieldId, long now, int section) {
             final long token = proto.start(fieldId);
 
             proto.write(ProcessStatsPackageProto.PACKAGE, mPackageName);
@@ -2294,7 +2294,7 @@
                 for (int ip = 0; ip < mProcesses.size(); ip++) {
                     final String procName = mProcesses.keyAt(ip);
                     final ProcessState procState = mProcesses.valueAt(ip);
-                    procState.writeToProto(proto, ProcessStatsPackageProto.PROCESS_STATS, procName,
+                    procState.dumpDebug(proto, ProcessStatsPackageProto.PROCESS_STATS, procName,
                             mUid, now);
                 }
             }
@@ -2302,7 +2302,7 @@
             if ((section & ProcessStats.REPORT_PKG_SVC_STATS) != 0) {
                 for (int is = 0; is < mServices.size(); is++) {
                     final ServiceState serviceState = mServices.valueAt(is);
-                    serviceState.writeToProto(proto, ProcessStatsPackageProto.SERVICE_STATS,
+                    serviceState.dumpDebug(proto, ProcessStatsPackageProto.SERVICE_STATS,
                             now);
                 }
             }
@@ -2310,7 +2310,7 @@
             if ((section & ProcessStats.REPORT_PKG_ASC_STATS) != 0) {
                 for (int ia = 0; ia < mAssociations.size(); ia++) {
                     final AssociationState ascState = mAssociations.valueAt(ia);
-                    ascState.writeToProto(proto, ProcessStatsPackageProto.ASSOCIATION_STATS,
+                    ascState.dumpDebug(proto, ProcessStatsPackageProto.ASSOCIATION_STATS,
                             now);
                 }
             }
diff --git a/core/java/com/android/internal/app/procstats/ServiceState.java b/core/java/com/android/internal/app/procstats/ServiceState.java
index 72077c4..bf03050 100644
--- a/core/java/com/android/internal/app/procstats/ServiceState.java
+++ b/core/java/com/android/internal/app/procstats/ServiceState.java
@@ -554,7 +554,7 @@
         pw.println();
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId, long now) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId, long now) {
         final long token = proto.start(fieldId);
         proto.write(PackageServiceStatsProto.SERVICE_NAME, mName);
 
diff --git a/core/java/com/android/internal/compat/CompatibilityChangeInfo.java b/core/java/com/android/internal/compat/CompatibilityChangeInfo.java
index e48e2df..16628d7 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 @Nullable String mDescription;
 
     public long getId() {
         return mChangeId;
@@ -48,12 +49,18 @@
         return mDisabled;
     }
 
+    public String getDescription()  {
+        return mDescription;
+    }
+
     public CompatibilityChangeInfo(
-            Long changeId, String name, int enableAfterTargetSdk, boolean disabled) {
+            Long changeId, String name, int enableAfterTargetSdk, boolean disabled,
+            String description) {
         this.mChangeId = changeId;
         this.mName = name;
         this.mEnableAfterTargetSdk = enableAfterTargetSdk;
         this.mDisabled = disabled;
+        this.mDescription = description;
     }
 
     private CompatibilityChangeInfo(Parcel in) {
@@ -61,6 +68,7 @@
         mName = in.readString();
         mEnableAfterTargetSdk = in.readInt();
         mDisabled = in.readBoolean();
+        mDescription = in.readString();
     }
 
     @Override
@@ -74,6 +82,7 @@
         dest.writeString(mName);
         dest.writeInt(mEnableAfterTargetSdk);
         dest.writeBoolean(mDisabled);
+        dest.writeString(mDescription);
     }
 
     public static final Parcelable.Creator<CompatibilityChangeInfo> CREATOR =
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 58e80c7..9e23c28 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -136,13 +136,6 @@
      */
     public static final String HASH_SALT_MAX_DAYS = "hash_salt_max_days";
 
-    // Flag related to Privacy Indicators
-
-    /**
-     * Whether the Permissions Hub is showing.
-     */
-    public static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled";
-
     // Flags related to Assistant
 
     /**
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index fee8345..f5fae19 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -28,12 +28,11 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.Package;
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.Build;
 import android.os.SELinux;
-import android.os.SystemProperties;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.util.Slog;
@@ -88,11 +87,12 @@
             }
         }
 
-        public static Handle create(Package pkg) throws IOException {
-            return create(pkg.getAllCodePaths(),
-                    (pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0,
-                    (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) != 0,
-                    (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
+        public static Handle create(AndroidPackage pkg) throws IOException {
+            return create(
+                    pkg.makeListAllCodePaths(),
+                    (pkg.getFlags() & ApplicationInfo.FLAG_MULTIARCH) != 0,
+                    (pkg.getFlags() & ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) != 0,
+                    (pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
         }
 
         public static Handle create(PackageLite lite) throws IOException {
@@ -444,6 +444,24 @@
         return sum;
     }
 
+     /**
+     * Configure the native library files managed by Incremental Service. Makes sure Incremental
+     * Service will create native library directories and set up native library binary files in the
+     * same structure as they are in non-incremental installations.
+     *
+     * @param pkg The package to be installed, including all the APK files.
+     * @param handle The pointer to an zip archive.
+     * @param libraryRoot The root directory of the native library files, e.g., lib/
+     * @param abiList The list of ABIs that are supported by the current device.
+     * @param useIsaSubdir Whether or not to set up a sub dir for the ISA.
+     * @return ABI code if installation succeeds or error code if installation fails.
+     */
+    public static int configureNativeBinariesForSupportedAbi(AndroidPackage pkg, Handle handle,
+            File libraryRoot, String[] abiList, boolean useIsaSubdir) {
+        // TODO(b/136132412): Implement this.
+        return -1;
+    }
+
     // We don't care about the other return values for now.
     private static final int BITCODE_PRESENT = 1;
 
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 75a5804..bc44fcf 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -33,7 +33,6 @@
 import android.net.INetworkStatsService;
 import android.net.NetworkStats;
 import android.net.Uri;
-import android.net.wifi.WifiActivityEnergyInfo;
 import android.net.wifi.WifiManager;
 import android.os.BatteryManager;
 import android.os.BatteryStats;
@@ -56,8 +55,10 @@
 import android.os.WorkSource.WorkChain;
 import android.os.connectivity.CellularBatteryStats;
 import android.os.connectivity.GpsBatteryStats;
+import android.os.connectivity.WifiActivityEnergyInfo;
 import android.os.connectivity.WifiBatteryStats;
 import android.provider.Settings;
+import android.telephony.CellSignalStrength;
 import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.ModemActivityInfo;
 import android.telephony.ModemActivityInfo.TransmitPower;
@@ -832,7 +833,7 @@
     int mPhoneSignalStrengthBin = -1;
     int mPhoneSignalStrengthBinRaw = -1;
     final StopwatchTimer[] mPhoneSignalStrengthsTimer =
-            new StopwatchTimer[SignalStrength.NUM_SIGNAL_STRENGTH_BINS];
+            new StopwatchTimer[CellSignalStrength.getNumSignalStrengthLevels()];
 
     StopwatchTimer mPhoneSignalScanningTimer;
 
@@ -1870,6 +1871,7 @@
             mCount = computeCurrentCountLocked();
             mUnpluggedReportedTotalTime = mCurrentReportedTotalTime = 0;
             mUnpluggedReportedCount = mCurrentReportedCount = 0;
+            mTrackingReportedValues = false;
         }
 
         public void setUpdateVersion(int version) {
@@ -5130,7 +5132,7 @@
 
     void stopAllPhoneSignalStrengthTimersLocked(int except) {
         final long elapsedRealtime = mClocks.elapsedRealtime();
-        for (int i = 0; i < SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
+        for (int i = 0; i < CellSignalStrength.getNumSignalStrengthLevels(); i++) {
             if (i == except) {
                 continue;
             }
@@ -5145,7 +5147,7 @@
             // In this case we will always be STATE_OUT_OF_SERVICE, so need
             // to infer that we are scanning from other data.
             if (state == ServiceState.STATE_OUT_OF_SERVICE
-                    && signalBin > SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
+                    && signalBin > CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
                 state = ServiceState.STATE_IN_SERVICE;
             }
         }
@@ -5168,7 +5170,7 @@
             // In this case we will always be STATE_OUT_OF_SERVICE, so need
             // to infer that we are scanning from other data.
             if (state == ServiceState.STATE_OUT_OF_SERVICE
-                    && strengthBin > SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
+                    && strengthBin > CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
                 state = ServiceState.STATE_IN_SERVICE;
             }
         }
@@ -5185,7 +5187,7 @@
         // bin and have the scanning bit set.
         } else if (state == ServiceState.STATE_OUT_OF_SERVICE) {
             scanning = true;
-            strengthBin = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+            strengthBin = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
             if (!mPhoneSignalScanningTimer.isRunningLocked()) {
                 mHistoryCur.states |= HistoryItem.STATE_PHONE_SCANNING_FLAG;
                 newHistory = true;
@@ -9785,7 +9787,7 @@
         mDeviceLightIdlingTimer = new StopwatchTimer(mClocks, null, -15, null, mOnBatteryTimeBase);
         mDeviceIdlingTimer = new StopwatchTimer(mClocks, null, -12, null, mOnBatteryTimeBase);
         mPhoneOnTimer = new StopwatchTimer(mClocks, null, -3, null, mOnBatteryTimeBase);
-        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
+        for (int i = 0; i < CellSignalStrength.getNumSignalStrengthLevels(); i++) {
             mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -200-i, null,
                     mOnBatteryTimeBase);
         }
@@ -10494,7 +10496,7 @@
         mFlashlightOnTimer.reset(false);
         mCameraOnTimer.reset(false);
         mBluetoothScanTimer.reset(false);
-        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
+        for (int i = 0; i < CellSignalStrength.getNumSignalStrengthLevels(); i++) {
             mPhoneSignalStrengthsTimer[i].reset(false);
         }
         mPhoneSignalScanningTimer.reset(false);
@@ -10800,10 +10802,10 @@
                 mHasWifiReporting = true;
 
                 // Measured in mAms
-                final long txTimeMs = info.getControllerTxTimeMillis();
-                final long rxTimeMs = info.getControllerRxTimeMillis();
-                final long scanTimeMs = info.getControllerScanTimeMillis();
-                final long idleTimeMs = info.getControllerIdleTimeMillis();
+                final long txTimeMs = info.getControllerTxDurationMillis();
+                final long rxTimeMs = info.getControllerRxDurationMillis();
+                final long scanTimeMs = info.getControllerScanDurationMillis();
+                final long idleTimeMs = info.getControllerIdleDurationMillis();
                 final long totalTimeMs = txTimeMs + rxTimeMs + idleTimeMs;
 
                 long leftOverRxTimeMs = rxTimeMs;
@@ -10946,13 +10948,14 @@
 
 
                 // Update WiFi controller stats.
-                mWifiActivity.getRxTimeCounter().addCountLocked(info.getControllerRxTimeMillis());
+                mWifiActivity.getRxTimeCounter().addCountLocked(
+                        info.getControllerRxDurationMillis());
                 mWifiActivity.getTxTimeCounters()[0].addCountLocked(
-                        info.getControllerTxTimeMillis());
+                        info.getControllerTxDurationMillis());
                 mWifiActivity.getScanTimeCounter().addCountLocked(
-                    info.getControllerScanTimeMillis());
+                        info.getControllerScanDurationMillis());
                 mWifiActivity.getIdleTimeCounter().addCountLocked(
-                        info.getControllerIdleTimeMillis());
+                        info.getControllerIdleDurationMillis());
 
                 // POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
                 final double opVolt = mPowerProfile.getAveragePower(
@@ -10960,7 +10963,7 @@
                 if (opVolt != 0) {
                     // We store the power drain as mAms.
                     mWifiActivity.getPowerCounter().addCountLocked(
-                            (long) (info.getControllerEnergyUsed() / opVolt));
+                            (long) (info.getControllerEnergyUsedMicroJoules() / opVolt));
                 }
                 // Converting uWs to mAms.
                 // Conversion: (uWs * (1000ms / 1s) * (1mW / 1000uW)) / mV = mAms
@@ -11055,7 +11058,7 @@
                             mPowerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX);
                     List<TransmitPower> txPowerInfo = deltaInfo.getTransmitPowerInfo();
                     for (int i = 0; i < Math.min(txPowerInfo.size(),
-                            SignalStrength.NUM_SIGNAL_STRENGTH_BINS); i++) {
+                            CellSignalStrength.getNumSignalStrengthLevels()); i++) {
                         energyUsed += txPowerInfo.get(i).getTimeInMillis() * mPowerProfile
                             .getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX, i);
                     }
@@ -12606,7 +12609,8 @@
         for (int i = 0; i < timeInRatMs.length; i++) {
            timeInRatMs[i] = getPhoneDataConnectionTime(i, rawRealTime, which) / 1000;
         }
-        long[] timeInRxSignalStrengthLevelMs = new long[SignalStrength.NUM_SIGNAL_STRENGTH_BINS];
+        long[] timeInRxSignalStrengthLevelMs =
+                new long[CellSignalStrength.getNumSignalStrengthLevels()];
         for (int i = 0; i < timeInRxSignalStrengthLevelMs.length; i++) {
            timeInRxSignalStrengthLevelMs[i]
                = getPhoneSignalStrengthTime(i, rawRealTime, which) / 1000;
@@ -13614,7 +13618,7 @@
         mDeviceLightIdlingTimer.readSummaryFromParcelLocked(in);
         mDeviceIdlingTimer.readSummaryFromParcelLocked(in);
         mPhoneOnTimer.readSummaryFromParcelLocked(in);
-        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
+        for (int i = 0; i < CellSignalStrength.getNumSignalStrengthLevels(); i++) {
             mPhoneSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
         }
         mPhoneSignalScanningTimer.readSummaryFromParcelLocked(in);
@@ -14099,7 +14103,7 @@
         mDeviceLightIdlingTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         mDeviceIdlingTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
-        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
+        for (int i = 0; i < CellSignalStrength.getNumSignalStrengthLevels(); i++) {
             mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         }
         mPhoneSignalScanningTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
@@ -14577,7 +14581,7 @@
                 mOnBatteryTimeBase, in);
         mDeviceIdlingTimer = new StopwatchTimer(mClocks, null, -12, null, mOnBatteryTimeBase, in);
         mPhoneOnTimer = new StopwatchTimer(mClocks, null, -3, null, mOnBatteryTimeBase, in);
-        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
+        for (int i = 0; i < CellSignalStrength.getNumSignalStrengthLevels(); i++) {
             mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(mClocks, null, -200-i,
                     null, mOnBatteryTimeBase, in);
         }
@@ -14796,7 +14800,7 @@
         mDeviceLightIdlingTimer.writeToParcel(out, uSecRealtime);
         mDeviceIdlingTimer.writeToParcel(out, uSecRealtime);
         mPhoneOnTimer.writeToParcel(out, uSecRealtime);
-        for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
+        for (int i = 0; i < CellSignalStrength.getNumSignalStrengthLevels(); i++) {
             mPhoneSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
         }
         mPhoneSignalScanningTimer.writeToParcel(out, uSecRealtime);
@@ -14987,7 +14991,7 @@
             mDeviceIdlingTimer.logState(pr, "  ");
             pr.println("*** Phone timer:");
             mPhoneOnTimer.logState(pr, "  ");
-            for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
+            for (int i = 0; i < CellSignalStrength.getNumSignalStrengthLevels(); i++) {
                 pr.println("*** Phone signal strength #" + i + ":");
                 mPhoneSignalStrengthsTimer[i].logState(pr, "  ");
             }
diff --git a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
index 9e8f06d..7c77d28 100644
--- a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
+++ b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
@@ -16,14 +16,14 @@
 package com.android.internal.os;
 
 import android.os.BatteryStats;
-import android.telephony.SignalStrength;
+import android.telephony.CellSignalStrength;
 import android.util.Log;
 
 public class MobileRadioPowerCalculator extends PowerCalculator {
     private static final String TAG = "MobileRadioPowerController";
     private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
     private final double mPowerRadioOn;
-    private final double[] mPowerBins = new double[SignalStrength.NUM_SIGNAL_STRENGTH_BINS];
+    private final double[] mPowerBins = new double[CellSignalStrength.getNumSignalStrengthLevels()];
     private final double mPowerScan;
     private BatteryStats mStats;
     private long mTotalAppMobileActiveMs = 0;
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 8338d78..0faf962 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -506,7 +506,7 @@
     /**
      * Dump power constants into PowerProfileProto
      */
-    public void writeToProto(ProtoOutputStream proto) {
+    public void dumpDebug(ProtoOutputStream proto) {
         // cpu.suspend
         writePowerConstantToProto(proto, POWER_CPU_SUSPEND, PowerProfileProto.CPU_SUSPEND);
 
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index fd3cd42..a211871 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -30,8 +30,10 @@
 import android.os.Trace;
 import android.util.Log;
 import android.util.Slog;
+
 import com.android.internal.logging.AndroidConfig;
 import com.android.server.NetworkManagementSocketTagger;
+
 import dalvik.system.RuntimeHooks;
 import dalvik.system.VMRuntime;
 
@@ -374,9 +376,6 @@
         // leftover running threads to crash before the process actually exits.
         nativeSetExitWithoutCleanup(true);
 
-        // We want to be fairly aggressive about heap utilization, to avoid
-        // holding on to a lot of memory that isn't needed.
-        VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
         VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
 
         final Arguments args = new Arguments(argv);
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 865ec27..9ee79ea 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -254,18 +254,6 @@
 
         InputStream is;
         try {
-            // If we are profiling the boot image, avoid preloading classes.
-            // Can't use device_config since we are the zygote.
-            String prop = SystemProperties.get(
-                    "persist.device_config.runtime_native_boot.profilebootclasspath", "");
-            // Might be empty if the property is unset since the default is "".
-            if (prop.length() == 0) {
-                prop = SystemProperties.get("dalvik.vm.profilebootclasspath", "");
-            }
-            if ("true".equals(prop)) {
-                return;
-            }
-
             is = new FileInputStream(PRELOADED_CLASSES);
         } catch (FileNotFoundException e) {
             Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
@@ -345,6 +333,22 @@
             runtime.preloadDexCaches();
             Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
 
+            // If we are profiling the boot image, reset the Jit counters after preloading the
+            // classes. We want to preload for performance, and we can use method counters to
+            // infer what clases are used after calling resetJitCounters, for profile purposes.
+            // Can't use device_config since we are the zygote.
+            String prop = SystemProperties.get(
+                    "persist.device_config.runtime_native_boot.profilebootclasspath", "");
+            // Might be empty if the property is unset since the default is "".
+            if (prop.length() == 0) {
+                prop = SystemProperties.get("dalvik.vm.profilebootclasspath", "");
+            }
+            if ("true".equals(prop)) {
+                Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ResetJitCounters");
+                runtime.resetJitCounters();
+                Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
+            }
+
             // Bring back root. We'll need it later if we're in the zygote.
             if (droppedPriviliges) {
                 try {
diff --git a/core/java/com/android/internal/policy/PipSnapAlgorithm.java b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
index 1afc67b..e3623c5 100644
--- a/core/java/com/android/internal/policy/PipSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
@@ -360,6 +360,28 @@
     }
 
     /**
+     * @return the adjusted size so that it conforms to the given aspectRatio, ensuring that the
+     * minimum edge is at least minEdgeSize.
+     */
+    public Size getSizeForAspectRatio(Size size, float aspectRatio, float minEdgeSize) {
+        final int smallestSize = Math.min(size.getWidth(), size.getHeight());
+        final int minSize = (int) Math.max(minEdgeSize, smallestSize);
+
+        final int width;
+        final int height;
+        if (aspectRatio <= 1) {
+            // Portrait, width is the minimum size.
+            width = minSize;
+            height = Math.round(width / aspectRatio);
+        } else {
+            // Landscape, height is the minimum size
+            height = minSize;
+            width = Math.round(height * aspectRatio);
+        }
+        return new Size(width, height);
+    }
+
+    /**
      * @return the closest point in {@param points} to the given {@param x} and {@param y}.
      */
     private Point findClosestPoint(int x, int y, Point[] points) {
diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 084a3cc..01f5743 100644
--- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -21,7 +21,6 @@
 import android.telephony.CellInfo;
 import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.PhoneCapability;
-import android.telephony.PhysicalChannelConfig;
 import android.telephony.PreciseCallState;
 import android.telephony.PreciseDataConnectionState;
 import android.telephony.ServiceState;
@@ -44,7 +43,6 @@
     void onDataConnectionStateChanged(int state, int networkType);
     void onDataActivity(int direction);
     void onSignalStrengthsChanged(in SignalStrength signalStrength);
-    void onPhysicalChannelConfigurationChanged(in List<PhysicalChannelConfig> configs);
     void onOtaspChanged(in int otaspMode);
     void onCellInfoChanged(in List<CellInfo> cellInfo);
     void onPreciseCallStateChanged(in PreciseCallState callState);
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 9ae0ba5..2f34aa0 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -24,7 +24,6 @@
 import android.telephony.CellInfo;
 import android.telephony.ims.ImsReasonInfo;
 import android.telephony.PhoneCapability;
-import android.telephony.PhysicalChannelConfig;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.emergency.EmergencyNumber;
@@ -78,8 +77,6 @@
     void notifyOtaspChanged(in int subId, in int otaspMode);
     @UnsupportedAppUsage
     void notifyCellInfo(in List<CellInfo> cellInfo);
-    void notifyPhysicalChannelConfigurationForSubscriber(in int phoneId, in int subId,
-            in List<PhysicalChannelConfig> configs);
     void notifyPreciseCallState(int phoneId, int subId, int ringingCallState,
             int foregroundCallState, int backgroundCallState);
     void notifyDisconnectCause(int phoneId, int subId, int disconnectCause,
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 821022f..bc80197 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -600,6 +600,14 @@
         return cur;
     }
 
+    public static @NonNull <T> ArrayList<T> add(@Nullable ArrayList<T> cur, int index, T val) {
+        if (cur == null) {
+            cur = new ArrayList<>();
+        }
+        cur.add(index, val);
+        return cur;
+    }
+
     public static @Nullable <T> ArrayList<T> remove(@Nullable ArrayList<T> cur, T val) {
         if (cur == null) {
             return null;
diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java
index b0888f2..121ae1a 100644
--- a/core/java/com/android/internal/util/AsyncChannel.java
+++ b/core/java/com/android/internal/util/AsyncChannel.java
@@ -29,7 +29,7 @@
 import android.os.Message;
 import android.os.Messenger;
 import android.os.RemoteException;
-import android.util.Slog;
+import android.util.Log;
 
 import java.util.Stack;
 
@@ -841,7 +841,7 @@
                     msg.replyTo = sm.mMessenger;
                     synchronized (sm.mHandler.mLockObject) {
                         if (sm.mHandler.mResultMsg != null) {
-                            Slog.wtf(TAG, "mResultMsg should be null here");
+                            Log.wtf(TAG, "mResultMsg should be null here");
                             sm.mHandler.mResultMsg = null;
                         }
                         dstMessenger.send(msg);
@@ -851,9 +851,9 @@
                     }
                 }
             } catch (InterruptedException e) {
-                Slog.e(TAG, "error in sendMessageSynchronously", e);
+                Log.e(TAG, "error in sendMessageSynchronously", e);
             } catch (RemoteException e) {
-                Slog.e(TAG, "error in sendMessageSynchronously", e);
+                Log.e(TAG, "error in sendMessageSynchronously", e);
             }
             sm.recycle();
             return resultMsg;
@@ -939,7 +939,7 @@
      * @param s
      */
     private static void log(String s) {
-        Slog.d(TAG, s);
+        Log.d(TAG, s);
     }
 
     private final class DeathMonitor implements IBinder.DeathRecipient {
diff --git a/core/java/com/android/internal/util/AsyncService.java b/core/java/com/android/internal/util/AsyncService.java
index e39a2bf..58e4a60 100644
--- a/core/java/com/android/internal/util/AsyncService.java
+++ b/core/java/com/android/internal/util/AsyncService.java
@@ -22,7 +22,7 @@
 import android.os.IBinder;
 import android.os.Message;
 import android.os.Messenger;
-import android.util.Slog;
+import android.util.Log;
 
 /**
  * A service that receives Intents and IBinder transactions
@@ -92,7 +92,7 @@
      */
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
-        if (DBG) Slog.d(TAG, "onStartCommand");
+        if (DBG) Log.d(TAG, "onStartCommand");
 
         Message msg = mHandler.obtainMessage();
         msg.what = CMD_ASYNC_SERVICE_ON_START_INTENT;
@@ -111,7 +111,7 @@
      */
     @Override
     public void onDestroy() {
-        if (DBG) Slog.d(TAG, "onDestroy");
+        if (DBG) Log.d(TAG, "onDestroy");
 
         Message msg = mHandler.obtainMessage();
         msg.what = CMD_ASYNC_SERVICE_DESTROY;
diff --git a/core/java/com/android/internal/util/BitUtils.java b/core/java/com/android/internal/util/BitUtils.java
index b4bab80..154ea52 100644
--- a/core/java/com/android/internal/util/BitUtils.java
+++ b/core/java/com/android/internal/util/BitUtils.java
@@ -68,9 +68,9 @@
         int[] result = new int[size];
         int index = 0;
         int bitPos = 0;
-        while (val > 0) {
+        while (val != 0) {
             if ((val & 1) == 1) result[index++] = bitPos;
-            val = val >> 1;
+            val = val >>> 1;
             bitPos++;
         }
         return result;
@@ -79,7 +79,7 @@
     public static long packBits(int[] bits) {
         long packed = 0;
         for (int b : bits) {
-            packed |= (1 << b);
+            packed |= (1L << b);
         }
         return packed;
     }
diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java
index 4165f20..4dac542 100644
--- a/core/java/com/android/internal/util/CollectionUtils.java
+++ b/core/java/com/android/internal/util/CollectionUtils.java
@@ -308,6 +308,17 @@
     }
 
     /**
+     * @see #add(List, Object)
+     */
+    public static @NonNull <K, V> Map<K, V> add(@Nullable Map<K, V> map, K key, V value) {
+        if (map == null || map == Collections.emptyMap()) {
+            map = new ArrayMap<>();
+        }
+        map.put(key, value);
+        return map;
+    }
+
+    /**
      * Similar to {@link List#remove}, but with support for list values of {@code null} and
      * {@link Collections#emptyList}
      */
diff --git a/core/java/com/android/internal/util/LocalLog.java b/core/java/com/android/internal/util/LocalLog.java
index 8edb739..3916691 100644
--- a/core/java/com/android/internal/util/LocalLog.java
+++ b/core/java/com/android/internal/util/LocalLog.java
@@ -65,7 +65,7 @@
         }
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
 
         synchronized (mLines) {
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index 731b93c..3fff5c2 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -102,6 +102,24 @@
     }
 
     /**
+     * Ensures that an string reference passed as a parameter to the calling method is not empty.
+     *
+     * @param string an string reference
+     * @param messageTemplate a printf-style message template to use if the check fails; will be
+     *     converted to a string using {@link String#format(String, Object...)}
+     * @param messageArgs arguments for {@code messageTemplate}
+     * @return the string reference that was validated
+     * @throws IllegalArgumentException if {@code string} is empty
+     */
+    public static @NonNull <T extends CharSequence> T checkStringNotEmpty(
+            final T string, final String messageTemplate, final Object... messageArgs) {
+        if (TextUtils.isEmpty(string)) {
+            throw new IllegalArgumentException(String.format(messageTemplate, messageArgs));
+        }
+        return string;
+    }
+
+    /**
      * Ensures that an object reference passed as a parameter to the calling
      * method is not null.
      *
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 57bfcac..2ac2975 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -36,6 +36,8 @@
 
 import dalvik.annotation.compat.UnsupportedAppUsage;
 
+import java.io.IOException;
+
 public class BaseIWindow extends IWindow.Stub {
 
     @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.P)
@@ -101,6 +103,13 @@
 
     @Override
     public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
+        if (out != null) {
+            try {
+                out.closeWithError("Unsupported command " + command);
+            } catch (IOException e) {
+                // Ignore
+            }
+        }
     }
 
     @Override
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 897b982..13cc98b 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -43,7 +43,7 @@
     long getLong(in String key, in long defaultValue, in int userId);
     @UnsupportedAppUsage
     String getString(in String key, in String defaultValue, in int userId);
-    boolean setLockCredential(in LockscreenCredential credential, in LockscreenCredential savedCredential, int userId, boolean allowUntrustedChange);
+    boolean setLockCredential(in LockscreenCredential credential, in LockscreenCredential savedCredential, int userId);
     void resetKeyStore(int userId);
     VerifyCredentialResponse checkCredential(in LockscreenCredential credential, int userId,
             in ICheckCredentialProgressCallback progressCallback);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index b534213..cff39f1 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -636,35 +636,16 @@
      *
      * @param newCredential The new credential to save
      * @param savedCredential The current credential
-     * @param userId the user whose lockscreen credential is to be changed
+     * @param userHandle the user whose lockscreen credential is to be changed
      *
      * @return whether this method saved the new password successfully or not. This flow will fail
      * and return false if the given credential is wrong.
      * @throws RuntimeException if password change encountered an unrecoverable error.
+     * @throws UnsupportedOperationException secure lockscreen is not supported on this device.
+     * @throws IllegalArgumentException if new credential is too short.
      */
     public boolean setLockCredential(@NonNull LockscreenCredential newCredential,
-            @NonNull LockscreenCredential savedCredential, int userId) {
-        return setLockCredential(newCredential, savedCredential, userId, false);
-    }
-
-    /**
-     * Save a new lockscreen credential.
-     * <p> This method will fail (returning {@code false}) if the previously saved pattern provided
-     * is incorrect and allowUntrustedChange is false, or if the lockscreen verification is still
-     * being throttled.
-     * @param newCredential The new credential to save
-     * @param savedCredential The current credential
-     * @param userHandle the user whose lockscreen credential is to be changed
-     * @param allowUntrustedChange whether we want to allow saving a new pattern if the existing
-     * credentialt being provided is incorrect.
-     *
-     * @return whether this method saved the new password successfully or not. This flow will fail
-     * and return false if the given credential is wrong and allowUntrustedChange is false.
-     * @throws RuntimeException if password change encountered an unrecoverable error.
-     */
-    public boolean setLockCredential(@NonNull LockscreenCredential newCredential,
-            @NonNull LockscreenCredential savedCredential, int userHandle,
-            boolean allowUntrustedChange) {
+            @NonNull LockscreenCredential savedCredential, int userHandle) {
         if (!hasSecureLockScreen()) {
             throw new UnsupportedOperationException(
                     "This operation requires the lock screen feature.");
@@ -672,8 +653,7 @@
         newCredential.checkLength();
 
         try {
-            if (!getLockSettings().setLockCredential(
-                    newCredential, savedCredential, userHandle, allowUntrustedChange)) {
+            if (!getLockSettings().setLockCredential(newCredential, savedCredential, userHandle)) {
                 return false;
             }
         } catch (RemoteException e) {
diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
index dc4f09a..13bfc1b 100644
--- a/core/java/com/android/server/BootReceiver.java
+++ b/core/java/com/android/server/BootReceiver.java
@@ -66,10 +66,15 @@
 public class BootReceiver extends BroadcastReceiver {
     private static final String TAG = "BootReceiver";
 
+    private static final String TAG_TRUNCATED = "[[TRUNCATED]]\n";
+
     // Maximum size of a logged event (files get truncated if they're longer).
     // Give userdebug builds a larger max to capture extra debug, esp. for last_kmsg.
     private static final int LOG_SIZE =
         SystemProperties.getInt("ro.debuggable", 0) == 1 ? 98304 : 65536;
+    private static final int LASTK_LOG_SIZE =
+        SystemProperties.getInt("ro.debuggable", 0) == 1 ? 196608 : 65536;
+    private static final int GMSCORE_LASTK_LOG_SIZE = 196608;
 
     private static final File TOMBSTONE_DIR = new File("/data/tombstones");
     private static final String TAG_TOMBSTONE = "SYSTEM_TOMBSTONE";
@@ -224,12 +229,12 @@
             if (db != null) db.addText("SYSTEM_BOOT", headers);
 
             // Negative sizes mean to take the *tail* of the file (see FileUtils.readTextFile())
-            addFileWithFootersToDropBox(db, timestamps, headers, lastKmsgFooter,
-                    "/proc/last_kmsg", -LOG_SIZE, "SYSTEM_LAST_KMSG");
-            addFileWithFootersToDropBox(db, timestamps, headers, lastKmsgFooter,
-                    "/sys/fs/pstore/console-ramoops", -LOG_SIZE, "SYSTEM_LAST_KMSG");
-            addFileWithFootersToDropBox(db, timestamps, headers, lastKmsgFooter,
-                    "/sys/fs/pstore/console-ramoops-0", -LOG_SIZE, "SYSTEM_LAST_KMSG");
+            addLastkToDropBox(db, timestamps, headers, lastKmsgFooter,
+                    "/proc/last_kmsg", -LASTK_LOG_SIZE, "SYSTEM_LAST_KMSG");
+            addLastkToDropBox(db, timestamps, headers, lastKmsgFooter,
+                    "/sys/fs/pstore/console-ramoops", -LASTK_LOG_SIZE, "SYSTEM_LAST_KMSG");
+            addLastkToDropBox(db, timestamps, headers, lastKmsgFooter,
+                    "/sys/fs/pstore/console-ramoops-0", -LASTK_LOG_SIZE, "SYSTEM_LAST_KMSG");
             addFileToDropBox(db, timestamps, headers, "/cache/recovery/log", -LOG_SIZE,
                     "SYSTEM_RECOVERY_LOG");
             addFileToDropBox(db, timestamps, headers, "/cache/recovery/last_kmsg",
@@ -278,6 +283,23 @@
         sTombstoneObserver.startWatching();
     }
 
+    private static void addLastkToDropBox(
+            DropBoxManager db, HashMap<String, Long> timestamps,
+            String headers, String footers, String filename, int maxSize,
+            String tag) throws IOException {
+        int extraSize = headers.length() + TAG_TRUNCATED.length() + footers.length();
+        // GMSCore will do 2nd truncation to be 192KiB
+        // LASTK_LOG_SIZE + extraSize must be less than GMSCORE_LASTK_LOG_SIZE
+        if (LASTK_LOG_SIZE + extraSize > GMSCORE_LASTK_LOG_SIZE) {
+          if (GMSCORE_LASTK_LOG_SIZE > extraSize) {
+            maxSize = -(GMSCORE_LASTK_LOG_SIZE - extraSize);
+          } else {
+            maxSize = 0;
+          }
+        }
+        addFileWithFootersToDropBox(db, timestamps, headers, footers, filename, maxSize, tag);
+    }
+
     private static void addFileToDropBox(
             DropBoxManager db, HashMap<String, Long> timestamps,
             String headers, String filename, int maxSize, String tag) throws IOException {
@@ -301,7 +323,7 @@
         timestamps.put(filename, fileTime);
 
 
-        String fileContents = FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n");
+        String fileContents = FileUtils.readTextFile(file, maxSize, TAG_TRUNCATED);
         String text = headers + fileContents + footers;
         // Create an additional report for system server native crashes, with a special tag.
         if (tag.equals(TAG_TOMBSTONE) && fileContents.contains(">>> system_server <<<")) {
@@ -345,7 +367,7 @@
 
         timestamps.put(tag, fileTime);
 
-        String log = FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n");
+        String log = FileUtils.readTextFile(file, maxSize, TAG_TRUNCATED);
         StringBuilder sb = new StringBuilder();
         for (String line : log.split("\n")) {
             if (line.contains("audit")) {
@@ -370,7 +392,7 @@
         long fileTime = file.lastModified();
         if (fileTime <= 0) return;  // File does not exist
 
-        String log = FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n");
+        String log = FileUtils.readTextFile(file, maxSize, TAG_TRUNCATED);
         Pattern pattern = Pattern.compile(FS_STAT_PATTERN);
         String lines[] = log.split("\n");
         int lineNumber = 0;
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 49a73ee..e6232e85 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -226,7 +226,7 @@
      * Map of system pre-defined, uniquely named actors; keys are namespace,
      * value maps actor name to package name.
      */
-    private ArrayMap<String, ArrayMap<String, String>> mNamedActors = null;
+    private Map<String, Map<String, String>> mNamedActors = null;
 
     public static SystemConfig getInstance() {
         if (!isSystemProcess()) {
@@ -406,7 +406,7 @@
     }
 
     @NonNull
-    public Map<String, ? extends Map<String, String>> getNamedActors() {
+    public Map<String, Map<String, String>> getNamedActors() {
         return mNamedActors != null ? mNamedActors : Collections.emptyMap();
     }
 
@@ -1063,7 +1063,7 @@
                                 mNamedActors = new ArrayMap<>();
                             }
 
-                            ArrayMap<String, String> nameToPkgMap = mNamedActors.get(namespace);
+                            Map<String, String> nameToPkgMap = mNamedActors.get(namespace);
                             if (nameToPkgMap == null) {
                                 nameToPkgMap = new ArrayMap<>();
                                 mNamedActors.put(namespace, nameToPkgMap);
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 51f8fcc..025de5e 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -110,6 +110,7 @@
                 "android_view_InputEventReceiver.cpp",
                 "android_view_InputEventSender.cpp",
                 "android_view_InputQueue.cpp",
+                "android_view_FrameMetricsObserver.cpp",
                 "android_view_KeyCharacterMap.cpp",
                 "android_view_KeyEvent.cpp",
                 "android_view_MotionEvent.cpp",
@@ -151,6 +152,7 @@
                 "android_util_StringBlock.cpp",
                 "android_util_XmlBlock.cpp",
                 "android_util_jar_StrictJarFile.cpp",
+                "android_media_AudioDeviceAddress.cpp",
                 "android_media_AudioEffectDescriptor.cpp",
                 "android_media_AudioRecord.cpp",
                 "android_media_AudioSystem.cpp",
@@ -424,9 +426,9 @@
         android: {
             srcs: [ // sources that depend on android only libraries
                 "android/graphics/apex/android_canvas.cpp",
+                "android/graphics/apex/renderthread.cpp",
                 "android/graphics/apex/jni_runtime.cpp",
 
-                "android_view_FrameMetricsObserver.cpp",
                 "android_view_TextureLayer.cpp",
                 "android_view_ThreadedRenderer.cpp",
                 "android/graphics/BitmapRegionDecoder.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 378e125..d92ab49 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -86,6 +86,7 @@
 extern int register_android_hardware_UsbRequest(JNIEnv *env);
 extern int register_android_hardware_location_ActivityRecognitionHardware(JNIEnv* env);
 
+extern int register_android_media_AudioDeviceAddress(JNIEnv *env);
 extern int register_android_media_AudioEffectDescriptor(JNIEnv *env);
 extern int register_android_media_AudioRecord(JNIEnv *env);
 extern int register_android_media_AudioSystem(JNIEnv *env);
@@ -648,6 +649,7 @@
     char methodTraceFileSizeBuf[sizeof("-Xmethod-trace-file-size:") + PROPERTY_VALUE_MAX];
     std::string fingerprintBuf;
     char jdwpProviderBuf[sizeof("-XjdwpProvider:") - 1 + PROPERTY_VALUE_MAX];
+    char opaqueJniIds[sizeof("-Xopaque-jni-ids:") - 1 + PROPERTY_VALUE_MAX];
     char bootImageBuf[sizeof("-Ximage:") - 1 + PROPERTY_VALUE_MAX];
 
     // Read if we are using the profile configuration, do this at the start since the last ART args
@@ -839,6 +841,14 @@
                          "default");
     }
 
+    // Only pass an explicit opaque-jni-ids to apps forked from zygote
+    if (zygote) {
+      parseRuntimeOption("dalvik.vm.opaque-jni-ids",
+                        opaqueJniIds,
+                        "-Xopaque-jni-ids:",
+                        "swapable");
+    }
+
     parseRuntimeOption("dalvik.vm.lockprof.threshold",
                        lockProfThresholdBuf,
                        "-Xlockprofthreshold:");
@@ -1501,6 +1511,7 @@
     REG_JNI(register_android_hardware_UsbDeviceConnection),
     REG_JNI(register_android_hardware_UsbRequest),
     REG_JNI(register_android_hardware_location_ActivityRecognitionHardware),
+    REG_JNI(register_android_media_AudioDeviceAddress),
     REG_JNI(register_android_media_AudioEffectDescriptor),
     REG_JNI(register_android_media_AudioSystem),
     REG_JNI(register_android_media_AudioRecord),
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 2dec4b3..984f93c 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -12,7 +12,6 @@
 #include "SkWebpEncoder.h"
 
 #include "android_os_Parcel.h"
-#include "android_util_Binder.h"
 #include "android_nio_utils.h"
 #include "CreateJavaOutputStreamAdaptor.h"
 #include <hwui/Paint.h>
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index 6ffa72a..f18632d 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -25,18 +25,13 @@
 #include "SkBitmapRegionDecoder.h"
 #include "SkCodec.h"
 #include "SkData.h"
-#include "SkUtils.h"
-#include "SkPixelRef.h"
 #include "SkStream.h"
 
-#include "android_nio_utils.h"
-#include "android_util_Binder.h"
 #include "core_jni_helpers.h"
 
 #include <HardwareBitmapUploader.h>
 #include <nativehelper/JNIHelp.h>
 #include <androidfw/Asset.h>
-#include <binder/Parcel.h>
 #include <jni.h>
 #include <sys/stat.h>
 
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
index 7a9fea7..4de6c86 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
@@ -7,6 +7,7 @@
 #include "Utils.h"
 
 #include <nativehelper/JNIHelp.h>
+#include <log/log.h>
 #include <memory>
 
 static jmethodID    gInputStream_readMethodID;
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index 0cfbec5..4814452 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -419,7 +419,7 @@
         float errorSquared = acceptableError * acceptableError;
         float errorConic = acceptableError / 2; // somewhat arbitrary
 
-        while ((verb = pathIter.next(points, false)) != SkPath::kDone_Verb) {
+        while ((verb = pathIter.next(points)) != SkPath::kDone_Verb) {
             createVerbSegments(pathIter, verb, points, segmentPoints, lengths,
                     errorSquared, errorConic);
         }
@@ -497,12 +497,12 @@
 
     static jint getFillType(CRITICAL_JNI_PARAMS_COMMA jlong objHandle) {
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
-        return obj->getFillType();
+        return static_cast<int>(obj->getFillType());
     }
 
     static void setFillType(CRITICAL_JNI_PARAMS_COMMA jlong pathHandle, jint ftHandle) {;
         SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
-        SkPath::FillType ft = static_cast<SkPath::FillType>(ftHandle);
+        SkPathFillType ft = static_cast<SkPathFillType>(ftHandle);
         path->setFillType(ft);
     }
 };
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index bd28fe0..6095ffa 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -5,6 +5,7 @@
 #include "SkShader.h"
 #include "SkBlendMode.h"
 #include "core_jni_helpers.h"
+#include "src/shaders/SkRTShader.h"
 
 #include <jni.h>
 
@@ -212,6 +213,44 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
+static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderFactory, jlong matrixPtr,
+        jbyteArray inputs, jlong colorSpaceHandle) {
+    SkRuntimeShaderFactory* factory = reinterpret_cast<SkRuntimeShaderFactory*>(shaderFactory);
+    AutoJavaByteArray arInputs(env, inputs);
+
+    sk_sp<SkData> fData;
+    fData = SkData::MakeWithCopy(arInputs.ptr(), arInputs.length());
+    const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
+    sk_sp<SkShader> shader = factory->make(fData, matrix);
+    ThrowIAE_IfNull(env, shader);
+
+    return reinterpret_cast<jlong>(shader.release());
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+static jlong RuntimeShader_createShaderFactory(JNIEnv* env, jobject, jstring sksl,
+        jboolean isOpaque) {
+    ScopedUtfChars strSksl(env, sksl);
+    SkRuntimeShaderFactory* shaderFactory = new SkRuntimeShaderFactory(SkString(strSksl.c_str()),
+            isOpaque == JNI_TRUE);
+    ThrowIAE_IfNull(env, shaderFactory);
+
+    return reinterpret_cast<jlong>(shaderFactory);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+static void RuntimeShader_delete(SkRuntimeShaderFactory* shaderFactory) {
+    delete shaderFactory;
+}
+
+static jlong RuntimeShader_getNativeFinalizer(JNIEnv*, jobject) {
+    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&RuntimeShader_delete));
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+
 static const JNINativeMethod gColorMethods[] = {
     { "nativeRGBToHSV",    "(III[F)V", (void*)Color_RGBToHSV   },
     { "nativeHSVToColor",  "(I[F)I",   (void*)Color_HSVToColor }
@@ -241,6 +280,13 @@
     { "nativeCreate",      "(JJJI)J",   (void*)ComposeShader_create     },
 };
 
+static const JNINativeMethod gRuntimeShaderMethods[] = {
+    { "nativeGetFinalizer",   "()J",    (void*)RuntimeShader_getNativeFinalizer },
+    { "nativeCreate",     "(JJ[BJ)J",  (void*)RuntimeShader_create     },
+    { "nativeCreateShaderFactory",     "(Ljava/lang/String;Z)J",
+      (void*)RuntimeShader_createShaderFactory     },
+};
+
 int register_android_graphics_Shader(JNIEnv* env)
 {
     android::RegisterMethodsOrDie(env, "android/graphics/Color", gColorMethods,
@@ -257,6 +303,8 @@
                                   NELEM(gSweepGradientMethods));
     android::RegisterMethodsOrDie(env, "android/graphics/ComposeShader", gComposeShaderMethods,
                                   NELEM(gComposeShaderMethods));
+    android::RegisterMethodsOrDie(env, "android/graphics/RuntimeShader", gRuntimeShaderMethods,
+                                  NELEM(gRuntimeShaderMethods));
 
     return 0;
 }
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index 9603a10..4ce56ba 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -22,8 +22,6 @@
 #include <nativehelper/ScopedPrimitiveArray.h>
 #include <nativehelper/ScopedUtfChars.h>
 #include "SkTypeface.h"
-#include <android_runtime/android_util_AssetManager.h>
-#include <androidfw/AssetManager.h>
 #include <hwui/Typeface.h>
 #include <minikin/FontFamily.h>
 #include <minikin/SystemFonts.h>
diff --git a/core/jni/android/graphics/Utils.cpp b/core/jni/android/graphics/Utils.cpp
index 462d052..17c194d 100644
--- a/core/jni/android/graphics/Utils.cpp
+++ b/core/jni/android/graphics/Utils.cpp
@@ -18,6 +18,8 @@
 #include "SkUtils.h"
 #include "SkData.h"
 
+#include <log/log.h>
+
 using namespace android;
 
 AssetStreamAdaptor::AssetStreamAdaptor(Asset* asset)
diff --git a/core/jni/android/graphics/Utils.h b/core/jni/android/graphics/Utils.h
index ac291ea..8925517 100644
--- a/core/jni/android/graphics/Utils.h
+++ b/core/jni/android/graphics/Utils.h
@@ -19,8 +19,6 @@
 
 #include "SkStream.h"
 
-#include "android_util_Binder.h"
-
 #include <jni.h>
 #include <androidfw/Asset.h>
 
diff --git a/core/jni/android/graphics/apex/include/android/graphics/renderthread.h b/core/jni/android/graphics/apex/include/android/graphics/renderthread.h
new file mode 100644
index 0000000..0a790af
--- /dev/null
+++ b/core/jni/android/graphics/apex/include/android/graphics/renderthread.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+#ifndef ANDROID_GRAPHICS_RENDERTHREAD_H
+#define ANDROID_GRAPHICS_RENDERTHREAD_H
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * Dumps a textual representation of the graphics stats for this process.
+ * @param fd The file descriptor that the available graphics stats will be appended to.  The
+ *           function requires a valid fd, but does not persist or assume ownership of the fd
+ *           outside the scope of this function.
+ */
+void ARenderThread_dumpGraphicsMemory(int fd);
+
+__END_DECLS
+
+#endif // ANDROID_GRAPHICS_RENDERTHREAD_H
diff --git a/core/jni/android/graphics/apex/renderthread.cpp b/core/jni/android/graphics/apex/renderthread.cpp
new file mode 100644
index 0000000..5d26afe
--- /dev/null
+++ b/core/jni/android/graphics/apex/renderthread.cpp
@@ -0,0 +1,25 @@
+/*
+ * 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 "android/graphics/renderthread.h"
+
+#include <renderthread/RenderProxy.h>
+
+using namespace android;
+
+void ARenderThread_dumpGraphicsMemory(int fd) {
+    uirenderer::renderthread::RenderProxy::dumpGraphicsMemory(fd);
+}
diff --git a/core/jni/android_app_ActivityThread.cpp b/core/jni/android_app_ActivityThread.cpp
index ca8b8de..5aa684d 100644
--- a/core/jni/android_app_ActivityThread.cpp
+++ b/core/jni/android_app_ActivityThread.cpp
@@ -17,13 +17,11 @@
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
 
-#include <minikin/Layout.h>
-#include <renderthread/RenderProxy.h>
-
 #include "core_jni_helpers.h"
 #include <unistd.h>
 
 #include <bionic/malloc.h>
+#include <android/graphics/renderthread.h>
 
 namespace android {
 
@@ -35,7 +33,7 @@
 static void
 android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject javaFileDescriptor) {
     int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
-    android::uirenderer::renderthread::RenderProxy::dumpGraphicsMemory(fd);
+    ARenderThread_dumpGraphicsMemory(fd);
 }
 
 static void android_app_ActivityThread_initZygoteChildHeapProfiling(JNIEnv* env, jobject clazz) {
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
index f3a626e..5d13cf8 100644
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ b/core/jni/android_content_res_ApkAssets.cpp
@@ -32,6 +32,11 @@
 
 namespace android {
 
+static struct overlayableinfo_offsets_t {
+  jclass classObject;
+  jmethodID constructor;
+} gOverlayableInfoOffsets;
+
 static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, jstring java_path, jboolean system,
                         jboolean force_shared_lib, jboolean overlay, jboolean for_loader) {
   ScopedUtfChars path(env, java_path);
@@ -222,12 +227,9 @@
     return 0;
   }
 
-  jclass overlayable_class = env->FindClass("android/content/om/OverlayableInfo");
-  jmethodID overlayable_constructor = env->GetMethodID(overlayable_class, "<init>",
-                                                       "(Ljava/lang/String;Ljava/lang/String;I)V");
   return env->NewObject(
-      overlayable_class,
-      overlayable_constructor,
+      gOverlayableInfoOffsets.classObject,
+      gOverlayableInfoOffsets.constructor,
       overlayable_name,
       actor_string
   );
@@ -267,6 +269,11 @@
 };
 
 int register_android_content_res_ApkAssets(JNIEnv* env) {
+  jclass overlayableInfoClass = FindClassOrDie(env, "android/content/om/OverlayableInfo");
+  gOverlayableInfoOffsets.classObject = MakeGlobalRefOrDie(env, overlayableInfoClass);
+  gOverlayableInfoOffsets.constructor = GetMethodIDOrDie(env, gOverlayableInfoOffsets.classObject,
+      "<init>", "(Ljava/lang/String;Ljava/lang/String;)V");
+
   return RegisterMethodsOrDie(env, "android/content/res/ApkAssets", gApkAssetsMethods,
                               arraysize(gApkAssetsMethods));
 }
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index cb7f0dd..f2a51ad 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -396,9 +396,8 @@
 }
 
 static sp<ANativeWindow> getSurfaceTextureNativeWindow(JNIEnv* env, jobject thiz) {
-    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
     sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, thiz));
-    sp<Surface> surfaceTextureClient(surfaceTexture != NULL ? new Surface(producer) : NULL);
+    sp<Surface> surfaceTextureClient(producer != NULL ? new Surface(producer) : NULL);
     return surfaceTextureClient;
 }
 
diff --git a/core/jni/android_media_AudioDeviceAddress.cpp b/core/jni/android_media_AudioDeviceAddress.cpp
new file mode 100644
index 0000000..5f39f7e
--- /dev/null
+++ b/core/jni/android_media_AudioDeviceAddress.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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 "core_jni_helpers.h"
+#include "android_media_AudioDeviceAddress.h"
+#include "android_media_AudioErrors.h"
+
+#include <media/AudioDeviceTypeAddr.h>
+
+using namespace android;
+
+static jclass gAudioDeviceAddressClass;
+static jmethodID gAudioDeviceAddressCstor;
+
+namespace android {
+
+jint createAudioDeviceAddressFromNative(
+        JNIEnv *env, jobject *jAudioDeviceAddress,
+        const AudioDeviceTypeAddr *devTypeAddr) {
+    jint jStatus = (jint)AUDIO_JAVA_SUCCESS;
+    jint jNativeType = (jint)devTypeAddr->mType;
+    ScopedLocalRef<jstring> jAddress(env, env->NewStringUTF(devTypeAddr->mAddress.data()));
+
+    *jAudioDeviceAddress = env->NewObject(gAudioDeviceAddressClass, gAudioDeviceAddressCstor,
+            jNativeType, jAddress.get());
+
+    return jStatus;
+}
+
+}
+
+int register_android_media_AudioDeviceAddress(JNIEnv *env)
+{
+    jclass audioDeviceTypeAddressClass = FindClassOrDie(env, "android/media/AudioDeviceAddress");
+    gAudioDeviceAddressClass = MakeGlobalRefOrDie(env, audioDeviceTypeAddressClass);
+    gAudioDeviceAddressCstor = GetMethodIDOrDie(env, audioDeviceTypeAddressClass, "<init>",
+                                                "(ILjava/lang/String;)V");
+
+    return 0;
+}
diff --git a/core/jni/android_media_AudioDeviceAddress.h b/core/jni/android_media_AudioDeviceAddress.h
new file mode 100644
index 0000000..c66b179
--- /dev/null
+++ b/core/jni/android_media_AudioDeviceAddress.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_MEDIA_AUDIODEVICEADDRESS_H
+#define ANDROID_MEDIA_AUDIODEVICEADDRESS_H
+
+#include <system/audio.h>
+#include <media/AudioDeviceTypeAddr.h>
+
+#include "jni.h"
+
+namespace android {
+
+// Create a Java AudioDeviceAddress instance from a C++ AudioDeviceTypeAddress
+
+extern jint createAudioDeviceAddressFromNative(JNIEnv *env, jobject *jAudioDeviceAddress,
+        const AudioDeviceTypeAddr *devTypeAddr);
+} // namespace android
+
+#endif
\ No newline at end of file
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 01f9d0b0..79cf019 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -26,19 +26,19 @@
 #include <nativehelper/JNIHelp.h>
 #include "core_jni_helpers.h"
 
+#include "android_media_AudioAttributes.h"
+#include "android_media_AudioDeviceAddress.h"
+#include "android_media_AudioEffectDescriptor.h"
+#include "android_media_AudioErrors.h"
+#include "android_media_AudioFormat.h"
+#include "android_media_MicrophoneInfo.h"
 #include <audiomanager/AudioManager.h>
-#include <media/AudioDeviceTypeAddr.h>
-#include <media/AudioSystem.h>
 #include <media/AudioPolicy.h>
+#include <media/AudioSystem.h>
 #include <media/MicrophoneInfo.h>
 #include <nativehelper/ScopedLocalRef.h>
 #include <system/audio.h>
 #include <system/audio_policy.h>
-#include "android_media_AudioEffectDescriptor.h"
-#include "android_media_AudioFormat.h"
-#include "android_media_AudioErrors.h"
-#include "android_media_MicrophoneInfo.h"
-#include "android_media_AudioAttributes.h"
 
 // ----------------------------------------------------------------------------
 
@@ -2254,9 +2254,9 @@
 android_media_AudioSystem_setAudioHalPids(JNIEnv *env, jobject clazz, jintArray jPids)
 {
     if (jPids == NULL) {
-        return (jint)AUDIO_JAVA_BAD_VALUE;
+        return (jint) AUDIO_JAVA_BAD_VALUE;
     }
-    pid_t *nPidsArray = (pid_t *)env->GetIntArrayElements(jPids, NULL);
+    pid_t *nPidsArray = (pid_t *) env->GetIntArrayElements(jPids, NULL);
     std::vector<pid_t> nPids(nPidsArray, nPidsArray + env->GetArrayLength(jPids));
     status_t status = AudioSystem::setAudioHalPids(nPids);
     env->ReleaseIntArrayElements(jPids, nPidsArray, 0);
@@ -2270,6 +2270,48 @@
     return AudioSystem::isCallScreenModeSupported();
 }
 
+static jint
+android_media_AudioSystem_setPreferredDeviceForStrategy(JNIEnv *env, jobject thiz,
+        jint strategy, jint deviceType, jstring deviceAddress) {
+
+    const char *c_address = env->GetStringUTFChars(deviceAddress, NULL);
+    int status = check_AudioSystem_Command(
+            AudioSystem::setPreferredDeviceForStrategy((product_strategy_t) strategy,
+                    AudioDeviceTypeAddr(deviceType, c_address)));
+    env->ReleaseStringUTFChars(deviceAddress, c_address);
+    return (jint) status;
+}
+
+static jint
+android_media_AudioSystem_removePreferredDeviceForStrategy(JNIEnv *env, jobject thiz, jint strategy)
+{
+    return (jint) check_AudioSystem_Command(
+            AudioSystem::removePreferredDeviceForStrategy((product_strategy_t) strategy));
+}
+
+static jint
+android_media_AudioSystem_getPreferredDeviceForStrategy(JNIEnv *env, jobject thiz,
+        jint strategy, jobjectArray jDeviceArray)
+{
+    if (jDeviceArray == nullptr || env->GetArrayLength(jDeviceArray) != 1) {
+        ALOGE("%s invalid array to store AudioDeviceAddress", __FUNCTION__);
+        return (jint)AUDIO_JAVA_BAD_VALUE;
+    }
+
+    AudioDeviceTypeAddr elDevice;
+    status_t status = check_AudioSystem_Command(
+            AudioSystem::getPreferredDeviceForStrategy((product_strategy_t) strategy, elDevice));
+    if (status != NO_ERROR) {
+        return (jint) status;
+    }
+    jobject jAudioDeviceAddress = NULL;
+    jint jStatus = createAudioDeviceAddressFromNative(env, &jAudioDeviceAddress, &elDevice);
+    if (jStatus == AUDIO_JAVA_SUCCESS) {
+        env->SetObjectArrayElement(jDeviceArray, 0, jAudioDeviceAddress);
+    }
+    return jStatus;
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gMethods[] = {
@@ -2350,6 +2392,9 @@
     {"setRttEnabled",       "(Z)I",     (void *)android_media_AudioSystem_setRttEnabled},
     {"setAudioHalPids",  "([I)I", (void *)android_media_AudioSystem_setAudioHalPids},
     {"isCallScreeningModeSupported", "()Z", (void *)android_media_AudioSystem_isCallScreeningModeSupported},
+    {"setPreferredDeviceForStrategy", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setPreferredDeviceForStrategy},
+    {"removePreferredDeviceForStrategy", "(I)I", (void *)android_media_AudioSystem_removePreferredDeviceForStrategy},
+    {"getPreferredDeviceForStrategy", "(I[Landroid/media/AudioDeviceAddress;)I", (void *)android_media_AudioSystem_getPreferredDeviceForStrategy},
 };
 
 static const JNINativeMethod gEventHandlerMethods[] = {
diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp
index bd82bd9..0f7611a 100644
--- a/core/jni/android_os_Trace.cpp
+++ b/core/jni/android_os_Trace.cpp
@@ -50,10 +50,6 @@
     callback(buffer.data());
 }
 
-static jlong android_os_Trace_nativeGetEnabledTags(JNIEnv*, jclass) {
-    return atrace_get_enabled_tags();
-}
-
 static void android_os_Trace_nativeTraceCounter(JNIEnv* env, jclass,
         jlong tag, jstring nameStr, jlong value) {
     withString(env, nameStr, [tag, value](char* str) {
@@ -96,9 +92,6 @@
 
 static const JNINativeMethod gTraceMethods[] = {
     /* name, signature, funcPtr */
-    { "nativeGetEnabledTags",
-            "()J",
-            (void*)android_os_Trace_nativeGetEnabledTags },
     { "nativeSetAppTracingAllowed",
             "(Z)V",
             (void*)android_os_Trace_nativeSetAppTracingAllowed },
@@ -123,6 +116,11 @@
     { "nativeAsyncTraceEnd",
             "(JLjava/lang/String;I)V",
             (void*)android_os_Trace_nativeAsyncTraceEnd },
+
+    // ----------- @CriticalNative  ----------------
+    { "nativeGetEnabledTags",
+            "()J",
+            (void*)atrace_get_enabled_tags },
 };
 
 int register_android_os_Trace(JNIEnv* env) {
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 2232393..0992beb 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -30,12 +30,13 @@
 #include <unistd.h>
 
 #include <android-base/stringprintf.h>
-#include <binder/IInterface.h>
-#include <binder/IServiceManager.h>
-#include <binder/IPCThreadState.h>
-#include <binder/Parcel.h>
 #include <binder/BpBinder.h>
+#include <binder/IInterface.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
 #include <binder/ProcessState.h>
+#include <binder/Stability.h>
 #include <cutils/atomic.h>
 #include <log/log.h>
 #include <utils/KeyedVector.h>
@@ -459,6 +460,9 @@
         sp<JavaBBinder> b = mBinder.promote();
         if (b == NULL) {
             b = new JavaBBinder(env, obj);
+            if (mVintf) {
+                ::android::internal::Stability::markVintf(b.get());
+            }
             mBinder = b;
             ALOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%" PRId32 "\n",
                  b.get(), b->getWeakRefs(), obj, b->getWeakRefs()->getWeakCount());
@@ -473,9 +477,18 @@
         return mBinder.promote();
     }
 
+    void markVintf() {
+        mVintf = true;
+    }
+
 private:
     Mutex           mLock;
     wp<JavaBBinder> mBinder;
+
+    // in the future, we might condense this into int32_t stability, or if there
+    // is too much binder state here, we can think about making JavaBBinder an
+    // sp here (avoid recreating it)
+    bool            mVintf = false;
 };
 
 // ----------------------------------------------------------------------------
@@ -965,6 +978,12 @@
     IPCThreadState::self()->restoreCallingWorkSource(token);
 }
 
+static void android_os_Binder_markVintfStability(JNIEnv* env, jobject clazz) {
+    JavaBBinderHolder* jbh =
+        (JavaBBinderHolder*) env->GetLongField(clazz, gBinderOffsets.mObject);
+    jbh->markVintf();
+}
+
 static void android_os_Binder_flushPendingCommands(JNIEnv* env, jobject clazz)
 {
     IPCThreadState::self()->flushCommands();
@@ -1041,6 +1060,7 @@
     // @CriticalNative
     { "clearCallingWorkSource", "()J", (void*)android_os_Binder_clearCallingWorkSource },
     { "restoreCallingWorkSource", "(J)V", (void*)android_os_Binder_restoreCallingWorkSource },
+    { "markVintfStability", "()V", (void*)android_os_Binder_markVintfStability},
     { "flushPendingCommands", "()V", (void*)android_os_Binder_flushPendingCommands },
     { "getNativeBBinderHolder", "()J", (void*)android_os_Binder_getNativeBBinderHolder },
     { "getNativeFinalizer", "()J", (void*)android_os_Binder_getNativeFinalizer },
diff --git a/core/jni/android_util_StatsLog.cpp b/core/jni/android_util_StatsLog.cpp
index e749d34..9225fc2 100644
--- a/core/jni/android_util_StatsLog.cpp
+++ b/core/jni/android_util_StatsLog.cpp
@@ -18,18 +18,17 @@
 #define LOG_TAG "StatsLog_println"
 
 #include <assert.h>
-#include <cutils/properties.h>
 
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
 #include "utils/misc.h"
 #include "core_jni_helpers.h"
-#include "stats_event_list.h"
+#include "stats_buffer_writer.h"
 
 namespace android {
 
-static void android_util_StatsLog_writeRaw(JNIEnv* env, jobject clazz, jbyteArray buf, jint size)
-{
+static void android_util_StatsLog_write(JNIEnv* env, jobject clazz, jbyteArray buf, jint size,
+        jint atomId) {
     if (buf == NULL) {
         return;
     }
@@ -42,13 +41,8 @@
     if (bufferArray == NULL) {
         return;
     }
-    const uint32_t statsEventTag = 1937006964;
-    struct iovec vec[2];
-    vec[0].iov_base = (void*) &statsEventTag;
-    vec[0].iov_len = sizeof(statsEventTag);
-    vec[1].iov_base = (void*) bufferArray;
-    vec[1].iov_len = size;
-    write_to_statsd(vec, 2);
+
+    write_buffer_to_statsd((void*) bufferArray, size, atomId);
 
     env->ReleaseByteArrayElements(buf, bufferArray, 0);
 }
@@ -58,7 +52,7 @@
  */
 static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
-    { "writeRaw", "([BI)V", (void*) android_util_StatsLog_writeRaw },
+    { "writeImpl", "([BII)V", (void*) android_util_StatsLog_write },
 };
 
 int register_android_util_StatsLog(JNIEnv* env)
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index ba538a8..3531cf2 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -23,11 +23,10 @@
 #include <inttypes.h>
 
 #include <android_runtime/AndroidRuntime.h>
-#include <androidfw/DisplayEventDispatcher.h>
+#include <gui/DisplayEventDispatcher.h>
 #include <utils/Log.h>
 #include <utils/Looper.h>
 #include <utils/threads.h>
-#include <gui/DisplayEventReceiver.h>
 #include "android_os_MessageQueue.h"
 
 #include <nativehelper/ScopedLocalRef.h>
@@ -59,7 +58,6 @@
 private:
     jobject mReceiverWeakGlobal;
     sp<MessageQueue> mMessageQueue;
-    DisplayEventReceiver mReceiver;
 
     void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) override;
     void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 9f20388..c6e678ab 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -138,6 +138,14 @@
     jmethodID builder;
 } gScreenshotGraphicBufferClassInfo;
 
+static struct {
+    jclass clazz;
+    jmethodID ctor;
+    jfieldID defaultModeId;
+    jfieldID minRefreshRate;
+    jfieldID maxRefreshRate;
+} gDesiredDisplayConfigSpecsClassInfo;
+
 class JNamedColorSpace {
 public:
     // ColorSpace.Named.SRGB.ordinal() = 0;
@@ -810,6 +818,23 @@
     return allowedConfigsArray;
 }
 
+static jboolean nativeSetDesiredDisplayConfigSpecs(JNIEnv* env, jclass clazz, jobject tokenObj,
+                                                   jobject desiredDisplayConfigSpecs) {
+    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+    if (token == nullptr) return JNI_FALSE;
+
+    jint defaultModeId = env->GetIntField(desiredDisplayConfigSpecs,
+                                          gDesiredDisplayConfigSpecsClassInfo.defaultModeId);
+    jfloat minRefreshRate = env->GetFloatField(desiredDisplayConfigSpecs,
+                                               gDesiredDisplayConfigSpecsClassInfo.minRefreshRate);
+    jfloat maxRefreshRate = env->GetFloatField(desiredDisplayConfigSpecs,
+                                               gDesiredDisplayConfigSpecsClassInfo.maxRefreshRate);
+
+    size_t result = SurfaceComposerClient::setDesiredDisplayConfigSpecs(
+            token, defaultModeId, minRefreshRate, maxRefreshRate);
+    return result == NO_ERROR ? JNI_TRUE : JNI_FALSE;
+}
+
 static jint nativeGetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj) {
     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
     if (token == NULL) return -1;
@@ -1366,6 +1391,9 @@
             (void*)nativeSetAllowedDisplayConfigs },
     {"nativeGetAllowedDisplayConfigs", "(Landroid/os/IBinder;)[I",
             (void*)nativeGetAllowedDisplayConfigs },
+    {"nativeSetDesiredDisplayConfigSpecs",
+            "(Landroid/os/IBinder;Landroid/view/SurfaceControl$DesiredDisplayConfigSpecs;)Z",
+            (void*)nativeSetDesiredDisplayConfigSpecs },
     {"nativeGetDisplayColorModes", "(Landroid/os/IBinder;)[I",
             (void*)nativeGetDisplayColorModes},
     {"nativeGetDisplayNativePrimaries", "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DisplayPrimaries;",
@@ -1535,6 +1563,19 @@
     gDisplayPrimariesClassInfo.white = GetFieldIDOrDie(env, displayPrimariesClazz, "white",
             "Landroid/view/SurfaceControl$CieXyz;");
 
+    jclass desiredDisplayConfigSpecsClazz =
+            FindClassOrDie(env, "android/view/SurfaceControl$DesiredDisplayConfigSpecs");
+    gDesiredDisplayConfigSpecsClassInfo.clazz =
+            MakeGlobalRefOrDie(env, desiredDisplayConfigSpecsClazz);
+    gDesiredDisplayConfigSpecsClassInfo.ctor =
+            GetMethodIDOrDie(env, gDesiredDisplayConfigSpecsClassInfo.clazz, "<init>", "(IFF)V");
+    gDesiredDisplayConfigSpecsClassInfo.defaultModeId =
+            GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "mDefaultModeId", "I");
+    gDesiredDisplayConfigSpecsClassInfo.minRefreshRate =
+            GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "mMinRefreshRate", "F");
+    gDesiredDisplayConfigSpecsClassInfo.maxRefreshRate =
+            GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "mMaxRefreshRate", "F");
+
     return err;
 }
 
diff --git a/core/jni/android_view_TextureLayer.cpp b/core/jni/android_view_TextureLayer.cpp
index 6475151..5491a33 100644
--- a/core/jni/android_view_TextureLayer.cpp
+++ b/core/jni/android_view_TextureLayer.cpp
@@ -17,7 +17,6 @@
 #define LOG_TAG "OpenGLRenderer"
 
 #include "jni.h"
-#include "GraphicsJNI.h"
 #include <nativehelper/JNIHelp.h>
 
 #include "core_jni_helpers.h"
@@ -27,12 +26,8 @@
 #include <gui/surfacetexture/surface_texture_platform.h>
 #include <gui/surfacetexture/SurfaceTexture.h>
 #include <hwui/Paint.h>
-
 #include <SkMatrix.h>
-
 #include <DeferredLayerUpdater.h>
-#include <Rect.h>
-#include <RenderNode.h>
 
 namespace android {
 
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 8fabb23..0c21076 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -36,6 +36,9 @@
   "/apex/com.android.conscrypt/javalib/conscrypt.jar",
   "/apex/com.android.ipsec/javalib/ike.jar",
   "/apex/com.android.media/javalib/updatable-media.jar",
+  "/apex/com.android.sdkext/javalib/framework-sdkext.jar",
+  "/apex/com.android.telephony/javalib/telephony-common.jar",
+  "/apex/com.android.telephony/javalib/ims-common.jar",
   "/dev/null",
   "/dev/socket/zygote",
   "/dev/socket/zygote_secondary",
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 0cfb36b..ab97fdd 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -693,6 +693,12 @@
     // CATEGORY: SETTINGS
     // OS: R
     ACTION_CONTROLLER_UPDATE_STATE = 1728;
+
+    // Custom tag to evaluate the consuming time from onAttach to
+    // DashboardFragment.updatePreferenceStates.
+    // CATEGORY: SETTINGS
+    // OS: R
+    ACTION_DASHBOARD_VISIBLE_TIME = 1729;
 }
 
 /**
@@ -2451,4 +2457,14 @@
     // CATEGORY: SETTINGS
     // OS: R
     SETTINGS_PLATFORM_COMPAT_DASHBOARD = 1805;
+
+    // OPEN: Settings > Location -> Work profile tab
+    // CATEGORY: SETTINGS
+    // OS: R
+    LOCATION_WORK = 1806;
+
+    // OPEN: Settings > Account -> Work profile tab
+    // CATEGORY: SETTINGS
+    // OS: R
+    ACCOUNT_WORK = 1807;
 }
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index ce2717b..9f31b59 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -77,12 +77,14 @@
 message ActivityDisplayProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
-    optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1;
+    // To be removed soon.
+    optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1 [deprecated=true];
     optional int32 id = 2;
     repeated ActivityStackProto stacks = 3;
     optional int32 focused_stack_id = 4;
     optional .com.android.server.wm.IdentifierProto resumed_activity = 5;
     optional bool single_task_instance = 6;
+    optional .com.android.server.wm.DisplayContentProto display = 7;
 }
 
 message ActivityStackProto {
diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto
index 1ec05fb..ecb4193 100644
--- a/core/proto/android/service/notification.proto
+++ b/core/proto/android/service/notification.proto
@@ -264,3 +264,14 @@
     optional Sender priority_calls = 16;
     optional Sender priority_messages = 17;
 }
+
+// Next Tag: 2
+message PackageRemoteViewInfoProto {
+    optional string package_name = 1;
+    // add per-package additional info here (like channels)
+}
+
+// Next Tag: 2
+message NotificationRemoteViewsProto {
+    repeated PackageRemoteViewInfoProto package_remote_view_info = 1;
+}
\ No newline at end of file
diff --git a/core/proto/android/stats/devicepolicy/device_policy_enums.proto b/core/proto/android/stats/devicepolicy/device_policy_enums.proto
index 15813a1..f8c304c 100644
--- a/core/proto/android/stats/devicepolicy/device_policy_enums.proto
+++ b/core/proto/android/stats/devicepolicy/device_policy_enums.proto
@@ -151,4 +151,5 @@
   PROVISIONING_FLOW_TYPE = 124;
   CROSS_PROFILE_APPS_GET_TARGET_USER_PROFILES = 125;
   CROSS_PROFILE_APPS_START_ACTIVITY_AS_USER = 126;
+  SET_AUTO_TIME = 127;
 }
diff --git a/core/proto/android/stats/mediaprovider/mediaprovider_enums.proto b/core/proto/android/stats/mediaprovider/mediaprovider_enums.proto
new file mode 100644
index 0000000..138782b
--- /dev/null
+++ b/core/proto/android/stats/mediaprovider/mediaprovider_enums.proto
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.stats.mediaprovider;
+option java_multiple_files = true;
+
+enum VolumeType {
+    // Volume is unknown
+    UNKNOWN = 0;
+    // Volume is MediaStore.VOLUME_INTERNAL
+    INTERNAL = 1;
+    // Volume is MediaStore.VOLUME_EXTERNAL_PRIMARY
+    EXTERNAL_PRIMARY = 2;
+    // Volume is non-primary external storage
+    EXTERNAL_OTHER = 3;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 99dfffe..8f1114c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -635,6 +635,10 @@
 
     <protected-broadcast android:name="android.intent.action.DEVICE_CUSTOMIZATION_READY" />
 
+    <!-- NETWORK_SET_TIME moved from com.android.phone to system server. It should ultimately be
+         removed. -->
+    <protected-broadcast android:name="android.intent.action.NETWORK_SET_TIME" />
+
     <!-- For tether entitlement recheck-->
     <protected-broadcast
         android:name="com.android.server.connectivity.tethering.PROVISIONING_RECHECK_ALARM" />
@@ -1609,6 +1613,14 @@
     <permission android:name="android.permission.NETWORK_STACK"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi @hide Allows an application to observe network policy changes. -->
+    <permission android:name="android.permission.OBSERVE_NETWORK_POLICY"
+                android:protectionLevel="signature" />
+
+    <!-- @SystemApi @hide Allows applications to register network factory or agent -->
+    <permission android:name="android.permission.NETWORK_FACTORY"
+                android:protectionLevel="signature" />
+
     <!-- Allows Settings and SystemUI to call methods in Networking services
          <p>Not for use by third-party or privileged applications.
          @SystemApi
@@ -1668,13 +1680,13 @@
     <permission android:name="android.permission.NETWORK_BYPASS_PRIVATE_DNS"
         android:protectionLevel="signature" />
 
-    <!-- #SystemApi @hide Allows device mobility state to be set so that Wifi scan interval can be increased
-         when the device is stationary in order to save power.
+    <!-- @SystemApi @hide Allows device mobility state to be set so that Wifi scan interval can
+         be increased when the device is stationary in order to save power.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.WIFI_SET_DEVICE_MOBILITY_STATE"
         android:protectionLevel="signature|privileged" />
 
-    <!-- #SystemApi @hide Allows privileged system APK to update Wifi usability stats and score.
+    <!-- @SystemApi @hide Allows privileged system APK to update Wifi usability stats and score.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE"
         android:protectionLevel="signature|privileged" />
@@ -1739,7 +1751,11 @@
     <permission android:name="android.permission.NFC_TRANSACTION_EVENT"
         android:protectionLevel="normal" />
 
-    <!-- @SystemApi Allows an internal user to use privileged ConnectivityManager APIs.
+    <!-- @deprecated This permission used to allow too broad access to sensitive methods and all its
+         uses have been replaced by a more appropriate permission. Most uses have been replaced with
+         a NETWORK_STACK or NETWORK_SETTINGS check. Please look up the documentation of the
+         individual functions to figure out what permission now protects the individual function.
+         @SystemApi Allows an internal user to use privileged ConnectivityManager APIs.
          @hide -->
     <permission android:name="android.permission.CONNECTIVITY_INTERNAL"
         android:protectionLevel="signature|privileged" />
@@ -3531,9 +3547,10 @@
         android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to manage the holders of a role.
-         @hide -->
+         @hide
+         STOPSHIP b/145526313: Remove wellbeing protection flag from MANAGE_ROLE_HOLDERS. -->
     <permission android:name="android.permission.MANAGE_ROLE_HOLDERS"
-                android:protectionLevel="signature|installer|telephony" />
+                android:protectionLevel="signature|installer|telephony|wellbeing" />
 
     <!-- @SystemApi Allows an application to observe role holder changes.
          @hide -->
@@ -5052,6 +5069,10 @@
                  android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
+        <service android:name="com.android.server.usage.UsageStatsIdleService"
+                 android:permission="android.permission.BIND_JOB_SERVICE" >
+        </service>
+
         <service android:name="com.android.server.net.watchlist.ReportWatchlistJobService"
                  android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
diff --git a/core/res/res/layout/shutdown_dialog.xml b/core/res/res/layout/shutdown_dialog.xml
index 2d214b3..ec67aa8 100644
--- a/core/res/res/layout/shutdown_dialog.xml
+++ b/core/res/res/layout/shutdown_dialog.xml
@@ -32,6 +32,19 @@
         android:layout_height="32sp"
         android:text="@string/shutdown_progress"
         android:textDirection="locale"
+        android:textSize="18sp"
+        android:textAppearance="?attr/textAppearanceMedium"
+        android:gravity="center"
+        android:layout_marginBottom="24dp"
+        android:visibility="gone"
+        android:fontFamily="@string/config_headlineFontFamily"/>
+
+    <TextView
+        android:id="@+id/text2"
+        android:layout_width="wrap_content"
+        android:layout_height="32sp"
+        android:text="@string/shutdown_progress"
+        android:textDirection="locale"
         android:textSize="24sp"
         android:textAppearance="?attr/textAppearanceLarge"
         android:gravity="center"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index db5b2cb..4acdeeb 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Die werkprofiel se administrasieprogram ontbreek of is korrup. Gevolglik is jou werkprofiel en verwante data uitgevee. Kontak jou administrateur vir bystand."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Jou werkprofiel is nie meer op hierdie toestel beskikbaar nie"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Te veel wagwoordpogings"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Toestel word bestuur"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Jou organisasie bestuur hierdie toestel en kan netwerkverkeer monitor. Tik vir besonderhede."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Jou toestel sal uitgevee word"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Laai tans..."</string>
     <string name="capital_on" msgid="2770685323900821829">"AAN"</string>
     <string name="capital_off" msgid="7443704171014626777">"AF"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"gemerk"</string>
+    <string name="not_checked" msgid="7972320087569023342">"nie gemerk nie"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Voltooi handeling met"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Voltooi handeling met gebruik van %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Voltooi handeling"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Dien in"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Bestuurprogram werk tans"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Tik om die bestuurprogram te verlaat."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Verbinding of Wi-Fi-warmkol aktief"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Tik om op te stel."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Verbinding is gedeaktiveer"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Kontak jou administrateur vir besonderhede"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Terug"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Volgende"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Slaan oor"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 4e84c66..c6e55c3 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"የሥራ መገለጫ አስተዳዳሪ መተግበሪያው ወይም ይጎድላል ወይም ተበላሽቷል። በዚህ ምክንያት የሥራ መገለጫዎ እና ተዛማጅ ውሂብ ተሰርዘዋል። እርዳታን ለማግኘት አስተዳዳሪዎን ያነጋግሩ።"</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"የሥራ መገለጫዎ ከዚህ በኋላ በዚህ መሣሪያ ላይ አይገኝም"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"በጣም ብዙ የይለፍ ቃል ሙከራዎች"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"መሣሪያው የሚተዳደር ነው"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"የእርስዎ ድርጅት ይህን መሣሪያ ያስተዳድራል፣ እና የአውታረ መረብ ትራፊክን ሊከታተል ይችላል። ዝርዝሮችን ለማግኘት መታ ያድርጉ።"</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"የእርስዎ መሣሪያ ይደመሰሳል"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"በመጫን ላይ…"</string>
     <string name="capital_on" msgid="2770685323900821829">"በ"</string>
     <string name="capital_off" msgid="7443704171014626777">"ውጪ"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"ምልክት ተደርጎበታል"</string>
+    <string name="not_checked" msgid="7972320087569023342">"ምልክት አልተደረገበትም"</string>
     <string name="whichApplication" msgid="5432266899591255759">"... በመጠቀም ድርጊቱን አጠናቅ"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$sን ተጠቅመው እርምጃ ያጠናቅቁ"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"እርምጃውን አጠናቅቅ"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"አስረክብ"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"የመንዳት መተግበሪያ እያሄደ ነው"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ከመንዳት መተግበሪያ ለመውጣት መታ ያድርጉ።"</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"መሰካት ወይም ገባሪ ድረስ ነጥብ"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"ለማዋቀር መታ ያድርጉ።"</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"እንደ ሞደም መሰካት ተሰናክሏል"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"ለዝርዝሮች የእርስዎን አስተዳዳሪ ያነጋግሩ"</string>
     <string name="back_button_label" msgid="4078224038025043387">"ተመለስ"</string>
     <string name="next_button_label" msgid="6040209156399907780">"ቀጥሎ"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"ዝለል"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"የተከፈለ ማያን ቀያይር"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"የማያ ገጽ ቁልፍ"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ቅጽበታዊ ገጽ እይታ"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"የ<xliff:g id="APP_NAME">%1$s</xliff:g> መተግበሪያ በብቅ-ባይ መስኮት ውስጥ።"</string>
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index bf9eeb2..609b77e 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -196,6 +196,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"تطبيق المشرف للملف الشخصي للعمل مفقود أو تالف لذا تم حذف الملف الشخصي للعمل والبيانات ذات الصلة. اتصل بالمشرف للحصول على المساعدة."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"لم يعد ملفك الشخصي للعمل متاحًا على هذا الجهاز"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"تم إجراء محاولات كثيرة جدًا لإدخال كلمة المرور"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"تتم إدارة الجهاز"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"تدير مؤسستك هذا الجهاز ويمكنها مراقبة حركة بيانات الشبكة. يمكنك النقر للحصول على تفاصيل."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"سيتم محو بيانات جهازك."</string>
@@ -1196,10 +1198,8 @@
     <string name="loading" msgid="3138021523725055037">"جارٍ التحميل…"</string>
     <string name="capital_on" msgid="2770685323900821829">"مفعّلة"</string>
     <string name="capital_off" msgid="7443704171014626777">"إيقاف"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"تم وضع علامة"</string>
+    <string name="not_checked" msgid="7972320087569023342">"لم يتم وضع علامة"</string>
     <string name="whichApplication" msgid="5432266899591255759">"إكمال الإجراء باستخدام"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"‏إكمال الإجراء باستخدام %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"إكمال الإجراء"</string>
@@ -1509,10 +1509,6 @@
     <string name="submit" msgid="862795280643405865">"إرسال"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"تطبيق القيادة قيد التشغيل"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"انقر للخروج من تطبيق القيادة."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"النطاق أو نقطة الاتصال نشطة"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"انقر للإعداد."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"تم إيقاف التوصيل"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"اتصل بالمشرف للحصول على التفاصيل"</string>
     <string name="back_button_label" msgid="4078224038025043387">"رجوع"</string>
     <string name="next_button_label" msgid="6040209156399907780">"التالي"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"التخطي"</string>
@@ -2140,6 +2136,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"تبديل \"تقسيم الشاشة\""</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"شاشة القفل"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"لقطة شاشة"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> في نافذة منبثقة"</string>
 </resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 7fa36deb..091b563f 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"কৰ্মস্থানৰ প্ৰ\'ফাইলৰ প্ৰশাসক এপ্ নাই বা ব্যৱহাৰযোগ্য হৈ থকা নাই। যাৰ ফলত আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইল আৰু ইয়াৰ লগত জড়িত অন্য ডেটাসমূহ মচা হৈছে। সহায়ৰ বাবে আপোনাৰ প্ৰশাসকৰ সৈতে সম্পর্ক কৰক।"</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইল এই ডিভাইচটোত আৰু উপলব্ধ নহয়"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"বহুতবাৰ ভুলকৈ পাছৱৰ্ড দিয়া হৈছে"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"পৰিচালিত ডিভাইচ"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"আপোনাৰ প্ৰতিষ্ঠানটোৱে এই ডিভাইচটো পৰিচালনা কৰে আৰু ই নেটৱৰ্কৰ ট্ৰেফিক পৰ্যবেক্ষণ কৰিব পাৰে। সবিশেষ জানিবলৈ টিপক।"</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"আপোনাৰ ডিভাইচৰ ডেটা মচা হ\'ব"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"ল\'ড কৰি থকা হৈছে…"</string>
     <string name="capital_on" msgid="2770685323900821829">"অন কৰক"</string>
     <string name="capital_off" msgid="7443704171014626777">"অফ কৰক"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"টিক চিহ্ন দিয়া হৈছে"</string>
+    <string name="not_checked" msgid="7972320087569023342">"টিক চিহ্ন দিয়া হোৱা নাই"</string>
     <string name="whichApplication" msgid="5432266899591255759">"এয়া ব্যৱহাৰ কৰি কার্য সম্পূর্ণ কৰক"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ব্যৱহাৰ কৰি কাৰ্যটো সম্পূৰ্ণ কৰক"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"কাৰ্য সম্পূৰ্ণ কৰক"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"দাখিল কৰক"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ড্ৰাইভিং এপ্ চলি আছে"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ড্ৰাইভিং এপৰ পৰা বাহিৰ হ\'বলৈ টিপক।"</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"টেডাৰিং বা হটস্প\'ট সক্ৰিয় অৱস্থাত আছে"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"ছেট আপ কৰিবলৈ টিপক।"</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"টেডাৰিং অক্ষম কৰি থোৱা হৈছে"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"সবিশেষ জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক"</string>
     <string name="back_button_label" msgid="4078224038025043387">"উভতি যাওক"</string>
     <string name="next_button_label" msgid="6040209156399907780">"পৰৱৰ্তী"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"এৰি যাওক"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"বিভাজিত স্ক্ৰীন ট’গল কৰক"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"লক স্ক্ৰীন"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"স্ক্ৰীণশ্বট"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"পপ আপ ৱিণ্ড’ত <xliff:g id="APP_NAME">%1$s</xliff:g> এপ্‌।"</string>
 </resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 85186fa..359dfb7 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"İş profili admin tətbiqi ya yoxdur, ya da korlanıb. Nəticədə iş profili və onunla bağlı data silinib. Kömək üçün admin ilə əlaqə saxlayın."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"İş profili artıq bu cihazda əlçatan deyil"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Həddindən çox parol cəhdi"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Cihaz idarə olunur"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Təşkilat bu cihazı idarə edir və şəbəkənin ötürülməsinə nəzarət edə bilər. Detallar üçün klikləyin."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Cihazınız təmizlənəcəkdir"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Yüklənir…"</string>
     <string name="capital_on" msgid="2770685323900821829">"AÇIQ"</string>
     <string name="capital_off" msgid="7443704171014626777">"QAPALI"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"yoxlanılıb"</string>
+    <string name="not_checked" msgid="7972320087569023342">"yoxlanılmayıb"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Əməliyyatı tamamlayın:"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s istifadə edərək əməliyyatı tamamlayın"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Əməliyyatı tamamlayın"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Göndər"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Sürücülük tətbiqi işləyir"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Sürücülük tətbiqindən çıxmaq üçün klikləyin."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Tezerinq və ya hotspot aktivdir"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Quraşdırmaq üçün tıklayın."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Birləşmə deaktivdir"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Məlumat üçün adminlə əlaqə saxlayın"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Geri"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Növbəti"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Keç"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Bölünmüş Ekrana keçid"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Kilid Ekranı"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekran şəkli"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Açilən pəncərədə <xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqi."</string>
 </resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index d576e8c..a27d359 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -190,6 +190,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Aplikacija za administratore na profilu za Work nedostaje ili je oštećena. Zbog toga su profil za Work i povezani podaci izbrisani. Obratite se administratoru za pomoć."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Profil za Work više nije dostupan na ovom uređaju"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Previše pokušaja unosa lozinke"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Uređajem se upravlja"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Organizacija upravlja ovim uređajem i može da nadgleda mrežni saobraćaj. Dodirnite za detalje."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će biti obrisan"</string>
@@ -1136,10 +1138,8 @@
     <string name="loading" msgid="3138021523725055037">"Učitava se…"</string>
     <string name="capital_on" msgid="2770685323900821829">"DA"</string>
     <string name="capital_off" msgid="7443704171014626777">"NE"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"označeno je"</string>
+    <string name="not_checked" msgid="7972320087569023342">"nije označeno"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Dovršavanje radnje pomoću"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Završite radnju pomoću aplikacije %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Završi radnju"</string>
@@ -1449,10 +1449,6 @@
     <string name="submit" msgid="862795280643405865">"Pošalji"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Aplikacija za vožnju je pokrenuta"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Dodirnite da biste izašli iz aplikacije za vožnju."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Aktivno povezivanje sa internetom preko mobilnog uređaja ili hotspot"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Dodirnite da biste podesili."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Privezivanje je onemogućeno"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Potražite detalje od administratora"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Nazad"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Next"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Preskoči"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index f2fb72e..fb0fa33 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -192,6 +192,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Праграма адміністратара для працоўнага профілю адсутнічае або пашкоджана. У выніку гэтага ваш працоўны профіль і звязаныя з ім даныя былі выдалены. Звярніцеся па дапамогу да адміністратара."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Ваш працоўны профіль больш не даступны на гэтай прыладзе"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Занадта шмат спроб уводу пароля"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Прылада знаходзіцца пад кіраваннем"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Ваша арганізацыя кіруе гэтай прыладай і можа сачыць за сеткавым трафікам. Дакраніцеся для атрымання дадатковай інфармацыі."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Даныя вашай прылады будуць сцерты"</string>
@@ -1156,10 +1158,8 @@
     <string name="loading" msgid="3138021523725055037">"Загрузка..."</string>
     <string name="capital_on" msgid="2770685323900821829">"Уключыць"</string>
     <string name="capital_off" msgid="7443704171014626777">"Выключана"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"пазначана"</string>
+    <string name="not_checked" msgid="7972320087569023342">"не пазначана"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Завяршыць дзеянне з дапамогай"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Завяршыць дзеянне з дапамогай %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Завяршыць дзеянне"</string>
@@ -1469,10 +1469,6 @@
     <string name="submit" msgid="862795280643405865">"Перадаць"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Праграма для ваджэння ўключана"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Націсніце, каб выйсці з праграмы для ваджэння."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"USB-мадэм або хот-спот Wi-Fi актыўныя"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Дакраніцеся, каб наладзіць."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Рэжым мадэма адключаны"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Звярніцеся да адміністратара па падрабязную інфармацыю"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Назад"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Далей"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Прапусціць"</string>
@@ -2072,6 +2068,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Пераключальнік падзеленага экрана"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Экран блакіроўкі"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Здымак экрана"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" ва ўсплывальным акне."</string>
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index f89b985..69c998d 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Приложението за администриране на служебния потребителски профил липсва или е повредено. В резултат на това той и свързаните с него данни са изтрити. За съдействие се свържете с администратора си."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Служебният ви потребителски профил вече не е налице на това устройство"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Опитите за паролата са твърде много"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Устройството се управлява"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Организацията ви управлява това устройство и може да наблюдава мрежовия трафик. Докоснете за подробности."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Данните на устройството ви ще бъдат изтрити"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Зарежда се..."</string>
     <string name="capital_on" msgid="2770685323900821829">"ВКЛ"</string>
     <string name="capital_off" msgid="7443704171014626777">"ИЗКЛ"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"с отметка"</string>
+    <string name="not_checked" msgid="7972320087569023342">"без отметка"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Изпълняване на действието чрез"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Завършване на действието посредством %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Изпълняване на действието"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Изпращане"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Приложението за шофиране е включено"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Докоснете, за да излезете от приложението за шофиране."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Има активна споделена връзка или безжична точка за достъп"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Докоснете, за да настроите."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Функцията за тетъринг е деактивирана"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Свържете се с администратора си за подробности"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Назад"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Напред"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Пропускане"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Превключване на разделения екран"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заключен екран"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Екранна снимка"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Приложението <xliff:g id="APP_NAME">%1$s</xliff:g> в изскачащ прозорец."</string>
 </resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 2086da7..e335396 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"কর্মস্থলের প্রোফাইলের প্রশাসক অ্যাপটি হয় নেই, অথবা সেটি ক্ষতিগ্রস্ত হয়েছে৷ এর ফলে আপনার কর্মস্থলের প্রোফাইল এবং সম্পর্কিত ডেটা মুছে ফেলা হয়েছে৷ সহায়তার জন্য আপনার প্রশাসকের সাথে যোগাযোগ করুন৷"</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"আপনার কর্মস্থলের প্রোফাইলটি আর এই ডিভাইসে নেই"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"বহুবার ভুল পাসওয়ার্ড দিয়েছেন"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"ডিভাইসটি পরিচালনা করা হচ্ছে"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"আপনার প্রতিষ্ঠান এই ডিভাইসটি পরিচালনা করে এবং এটির নেটওয়ার্ক ট্রাফিকের উপরে নজর রাখতে পারে। বিশদ বিবরণের জন্য ট্যাপ করুন।,"</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"আপনার ডিভাইসটি মুছে ফেলা হবে"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"লোড হচ্ছে..."</string>
     <string name="capital_on" msgid="2770685323900821829">"চালু"</string>
     <string name="capital_off" msgid="7443704171014626777">"বন্ধ আছে"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"টিকচিহ্ন দেওয়া আছে"</string>
+    <string name="not_checked" msgid="7972320087569023342">"টিকচিহ্ন দেওয়া নেই"</string>
     <string name="whichApplication" msgid="5432266899591255759">"এটি ব্যবহার করে ক্রিয়াকলাপ সম্পূর্ণ করুন"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ব্যবহার করে ক্রিয়াকলাপ সম্পূর্ণ করুন"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"ক্রিয়াকলাপ সম্পূর্ণ করুন"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"জমা দিন"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ড্রাইভিং অ্যাপ চালু আছে"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ড্রাইভিং অ্যাপ বন্ধ করতে ট্যাপ করুন।"</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"টিথারিং বা হটস্পট সক্রিয় আছে"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"সেট-আপ করার জন্য আলতো চাপুন৷"</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"টিথারিং অক্ষম করা আছে"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"বিশদ বিবরণের জন্য প্রশাসকের সাথে যোগাযোগ করুন"</string>
     <string name="back_button_label" msgid="4078224038025043387">"ফিরুন"</string>
     <string name="next_button_label" msgid="6040209156399907780">"পরবর্তী"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"এড়িয়ে যান"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"স্প্লিট স্ক্রিন টগল করুন"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"লক স্ক্রিন"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"স্ক্রিনশট"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"পপ-আপ উইন্ডোতে <xliff:g id="APP_NAME">%1$s</xliff:g> অ্যাপ।"</string>
 </resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index b30ea426..d7bd7a1 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -190,6 +190,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Nedostaje aplikacija administratora za radni profil ili je neispravna. Zbog toga su vaš radni profil i povezani podaci izbrisani. Obratite administratoru za pomoć."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Radni profil više nije dostupan na ovom uređaju"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Previše puta ste pokušali otključati uređaj"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Uređajem se upravlja."</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Vaša organizacija upravlja ovim uređajem i može pratiti mrežni saobraćaj. Dodirnite za detalje."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će biti izbrisan"</string>
@@ -1136,10 +1138,8 @@
     <string name="loading" msgid="3138021523725055037">"Učitavanje..."</string>
     <string name="capital_on" msgid="2770685323900821829">"Uključeno"</string>
     <string name="capital_off" msgid="7443704171014626777">"Isključeno"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"označeno"</string>
+    <string name="not_checked" msgid="7972320087569023342">"nije označeno"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Izvrši akciju koristeći"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Dovršite akciju koristeći %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Izvršiti akciju"</string>
@@ -1451,10 +1451,6 @@
     <string name="submit" msgid="862795280643405865">"Potvrdi"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Aplikacija za vožnju je pokrenuta"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Dodirnite za izlaz iz aplikacije za vožnju."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Uređaj dijeli vezu ili djeluje kao pristupna tačka"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Dodirnite za postavke"</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Povezivanje putem mobitela je onemogućeno"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Kontaktirajte svog administratora za dodatne detalje"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Nazad"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Naprijed"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Preskoči"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 560e493..1f7d82e 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Falta l\'aplicació d\'administració del perfil professional o està malmesa. Com a conseqüència, s\'han suprimit el teu perfil professional i les dades relacionades. Contacta amb l\'administrador per obtenir ajuda."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"El teu perfil professional ja no està disponible en aquest dispositiu"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Has intentat introduir la contrasenya massa vegades"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"El dispositiu està gestionat"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"La teva organització gestiona aquest dispositiu i és possible que supervisi el trànsit de xarxa. Toca per obtenir més informació."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"El contingut del dispositiu s\'esborrarà"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"S\'està carregant…"</string>
     <string name="capital_on" msgid="2770685323900821829">"SÍ"</string>
     <string name="capital_off" msgid="7443704171014626777">"NO"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"seleccionat"</string>
+    <string name="not_checked" msgid="7972320087569023342">"no seleccionat"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Completa l\'acció mitjançant"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Completa l\'acció amb %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Completa l\'acció"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Envia"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"S\'està executant l\'aplicació de conducció"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Toca per sortir de l\'aplicació de conducció."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Compartició de xarxa o punt d\'accés Wi-Fi activat"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Toca per configurar."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"La compartició de xarxa està desactivada"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Contacta amb el teu administrador per obtenir més informació"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Enrere"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Següent"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Omet"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Commuta Pantalla dividida"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantalla de bloqueig"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Aplicació <xliff:g id="APP_NAME">%1$s</xliff:g> a la finestra emergent."</string>
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 9527c15..e05f299 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -192,6 +192,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Aplikace pro správu pracovního profilu chybí nebo je poškozena. Váš pracovní profil a související data proto byla smazána. Požádejte o pomoc administrátora."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Váš pracovní profil v tomto zařízení již není k dispozici"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Příliš mnoho pokusů o zadání hesla"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Zařízení je spravováno"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Toto zařízení je spravováno vaší organizací, která může sledovat síťový provoz. Podrobnosti zobrazíte klepnutím."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Zařízení bude vymazáno"</string>
@@ -1156,10 +1158,8 @@
     <string name="loading" msgid="3138021523725055037">"Načítání..."</string>
     <string name="capital_on" msgid="2770685323900821829">"I"</string>
     <string name="capital_off" msgid="7443704171014626777">"O"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"vybráno"</string>
+    <string name="not_checked" msgid="7972320087569023342">"nevybráno"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Dokončit akci pomocí aplikace"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Dokončit akci pomocí aplikace %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Dokončit akci"</string>
@@ -1469,10 +1469,6 @@
     <string name="submit" msgid="862795280643405865">"Odeslat"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Jízdní aplikace je spuštěna"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Jízdní aplikaci zavřete klepnutím."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Sdílené připojení nebo hotspot je aktivní."</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Klepnutím zahájíte nastavení."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering je zakázán"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"O podrobnosti požádejte administrátora"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Zpět"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Další"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Přeskočit"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 852256e..772b7b0 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Administrationsappen til arbejdsprofilen mangler eller er beskadiget. Derfor er din arbejdsprofil og dine relaterede data blevet slettet. Kontakt din administrator for at få hjælp."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Din arbejdsprofil er ikke længere tilgængelig på denne enhed"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"For mange mislykkede adgangskodeforsøg"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Dette er en administreret enhed"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Din organisation administrerer denne enhed og kan overvåge netværkstrafik. Tryk for at se info."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Enheden slettes"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Indlæser…"</string>
     <string name="capital_on" msgid="2770685323900821829">"TIL"</string>
     <string name="capital_off" msgid="7443704171014626777">"FRA"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"slået til"</string>
+    <string name="not_checked" msgid="7972320087569023342">"slået fra"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Brug"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Gennemfør handling ved hjælp af %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Afslut handling"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Send"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Bilkørselsappen er aktiv"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Tryk for at lukke bilkørselsappen."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Netdeling eller hotspot er aktivt"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Tryk for at konfigurere"</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Netdeling er deaktiveret"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Kontakt din administrator for at få oplysninger"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Tilbage"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Næste"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Spring over"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 8d86317..bb29a0e 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Die Admin-App für das Arbeitsprofil fehlt oder ist beschädigt. Daher wurden dein Arbeitsprofil und alle zugehörigen Daten gelöscht. Bitte wende dich für weitere Hilfe an deinen Administrator."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Dein Arbeitsprofil ist auf diesem Gerät nicht mehr verfügbar"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Zu viele falsche Passworteingaben"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Dies ist ein verwaltetes Gerät"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Deine Organisation verwaltet dieses Gerät und überprüft unter Umständen den Netzwerkverkehr. Tippe hier, um weitere Informationen zu erhalten."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Die Daten auf deinem Gerät werden gelöscht."</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Wird geladen…"</string>
     <string name="capital_on" msgid="2770685323900821829">"AN"</string>
     <string name="capital_off" msgid="7443704171014626777">"AUS"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"aktiviert"</string>
+    <string name="not_checked" msgid="7972320087569023342">"deaktiviert"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Aktion durchführen mit"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Aktion mit %1$s abschließen"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Abschließen"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Senden"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Fahr-App wird ausgeführt"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Tippen, um die Fahr-App zu beenden."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Tethering oder Hotspot aktiv"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Zum Einrichten tippen."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering ist deaktiviert"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Bitte wende dich für weitere Informationen an den Administrator"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Zurück"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Weiter"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Überspringen"</string>
@@ -1539,7 +1535,7 @@
     <string name="launchBrowserDefault" msgid="6328349989932924119">"Browser starten?"</string>
     <string name="SetupCallDefault" msgid="5581740063237175247">"Anruf annehmen?"</string>
     <string name="activity_resolver_use_always" msgid="5575222334666843269">"Immer"</string>
-    <string name="activity_resolver_set_always" msgid="4142825808921411476">"Auf \"Immer öffnen\" festlegen"</string>
+    <string name="activity_resolver_set_always" msgid="4142825808921411476">"Immer damit öffnen"</string>
     <string name="activity_resolver_use_once" msgid="948462794469672658">"Nur diesmal"</string>
     <string name="activity_resolver_app_settings" msgid="6758823206817748026">"Einstellungen"</string>
     <string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"Das Arbeitsprofil wird von %1$s nicht unterstützt."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 890a548..807c4c2 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Η εφαρμογή διαχείρισης προφίλ εργασίας είτε λείπει είτε είναι κατεστραμμένη. Ως αποτέλεσμα, διαγράφηκε το προφίλ εργασίας και τα σχετικά δεδομένα. Επικοινωνήστε με τον διαχειριστή σας για βοήθεια."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Το προφίλ εργασίας σας δεν είναι πια διαθέσιμο σε αυτήν τη συσκευή"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Πάρα πολλές προσπάθειες εισαγωγής κωδικού πρόσβασης"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Η συσκευή είναι διαχειριζόμενη"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Ο οργανισμός σας διαχειρίζεται αυτήν τη συσκευή και ενδέχεται να παρακολουθεί την επισκεψιμότητα δικτύου. Πατήστε για λεπτομέρειες."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Η συσκευή σας θα διαγραφεί"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Φόρτωση…"</string>
     <string name="capital_on" msgid="2770685323900821829">"Ενεργό"</string>
     <string name="capital_off" msgid="7443704171014626777">"Ανενεργό"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"επιλεγμένο"</string>
+    <string name="not_checked" msgid="7972320087569023342">"μη επιλεγμένο"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Ολοκλήρωση ενέργειας με τη χρήση"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Ολοκληρωμένη ενέργεια με χρήση %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Ολοκλήρωση ενέργειας"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Υποβολή"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Η εφαρμογή οδήγησης εκτελείται"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Πατήστε για να εξέλθετε από την εφαρμογή οδήγησης."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Πρόσδεση ή σύνδεση σημείου πρόσβασης ενεργή"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Πατήστε για ρύθμιση."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Η σύνδεση είναι απενεργοποιημένη"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Επικοινωνήστε με τον διαχειριστή σας για λεπτομέρειες"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Πίσω"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Επόμενο"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Παράλειψη"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 468b9a3..8d2f805 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"The work profile admin app is either missing or corrupted. As a result, your work profile and related data have been deleted. Contact your admin for assistance."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Your work profile is no longer available on this device"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Too many password attempts"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Device is managed"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Your organisation manages this device and may monitor network traffic. Tap for details."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Loading…"</string>
     <string name="capital_on" msgid="2770685323900821829">"ON"</string>
     <string name="capital_off" msgid="7443704171014626777">"OFF"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"ticked"</string>
+    <string name="not_checked" msgid="7972320087569023342">"not ticked"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Complete action using"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Complete action using %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Complete action"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Submit"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Driving app is running"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Tap to exit driving app."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Tethering or hotspot active"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Tap to set up."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering is disabled"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Contact your admin for details"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Back"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Next"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Skip"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 2c71577..e538587 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"The work profile admin app is either missing or corrupted. As a result, your work profile and related data have been deleted. Contact your admin for assistance."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Your work profile is no longer available on this device"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Too many password attempts"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Device is managed"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Your organisation manages this device and may monitor network traffic. Tap for details."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Loading…"</string>
     <string name="capital_on" msgid="2770685323900821829">"ON"</string>
     <string name="capital_off" msgid="7443704171014626777">"OFF"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"ticked"</string>
+    <string name="not_checked" msgid="7972320087569023342">"not ticked"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Complete action using"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Complete action using %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Complete action"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Submit"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Driving app is running"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Tap to exit driving app."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Tethering or hotspot active"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Tap to set up."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering is disabled"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Contact your admin for details"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Back"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Next"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Skip"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 468b9a3..8d2f805 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"The work profile admin app is either missing or corrupted. As a result, your work profile and related data have been deleted. Contact your admin for assistance."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Your work profile is no longer available on this device"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Too many password attempts"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Device is managed"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Your organisation manages this device and may monitor network traffic. Tap for details."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Loading…"</string>
     <string name="capital_on" msgid="2770685323900821829">"ON"</string>
     <string name="capital_off" msgid="7443704171014626777">"OFF"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"ticked"</string>
+    <string name="not_checked" msgid="7972320087569023342">"not ticked"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Complete action using"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Complete action using %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Complete action"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Submit"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Driving app is running"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Tap to exit driving app."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Tethering or hotspot active"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Tap to set up."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering is disabled"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Contact your admin for details"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Back"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Next"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Skip"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 468b9a3..8d2f805 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"The work profile admin app is either missing or corrupted. As a result, your work profile and related data have been deleted. Contact your admin for assistance."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Your work profile is no longer available on this device"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Too many password attempts"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Device is managed"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Your organisation manages this device and may monitor network traffic. Tap for details."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Loading…"</string>
     <string name="capital_on" msgid="2770685323900821829">"ON"</string>
     <string name="capital_off" msgid="7443704171014626777">"OFF"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"ticked"</string>
+    <string name="not_checked" msgid="7972320087569023342">"not ticked"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Complete action using"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Complete action using %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Complete action"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Submit"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Driving app is running"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Tap to exit driving app."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Tethering or hotspot active"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Tap to set up."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering is disabled"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Contact your admin for details"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Back"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Next"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Skip"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 03ed6a5..1436692 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‎‏‏‏‎‏‏‏‎‎‏‏‏‏‎‎‏‎‎‎‎‎‏‎‎‎‏‎‏‏‏‏‏‎‎‎‎‎‎The work profile admin app is either missing or corrupted. As a result, your work profile and related data have been deleted. Contact your admin for assistance.‎‏‎‎‏‎"</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‎‎‎‎‏‏‏‏‎‎‎‏‎‎‏‎‏‏‎‎‏‎‎‏‏‎‏‎‎‏‏‎‎‎‎‎‏‎‎‎‏‏‏‏‎‏‎‎‎‎‎‎‎Your work profile is no longer available on this device‎‏‎‎‏‎"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‎‎‎‏‏‎‎‎‎‎‏‎‎‏‏‏‎‎‎‎‎‏‎‎‎‎‏‏‏‏‏‏‏‎‎‏‏‏‏‏‏‎Too many password attempts‎‏‎‎‏‎"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‏‎‎‏‎‎‏‎‎‎‏‎‎‏‏‎‎‎‏‏‎‎‏‏‏‎‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‎Device is managed‎‏‎‎‏‎"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‎‏‏‎‏‎‏‏‏‏‎‎‎‏‏‎‏‏‎‎‎‏‏‎‏‎‎‎‎‏‎‏‎‏‎‎‎‏‏‎‏‎‎‏‎‏‎‎‎‏‎‏‎‎‎‎‎Your organization manages this device and may monitor network traffic. Tap for details.‎‏‎‎‏‎"</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‏‏‏‏‎‎‎‎‎‏‎‎‎‏‎‏‎‏‏‎‏‎‏‎‏‎‏‏‎‏‏‎‏‎‎‏‎‎‏‎‎‏‎‎‎‏‎‎‎‎‎‏‎Your device will be erased‎‏‎‎‏‎"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‎‎‏‏‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‎‏‎‏‏‎‎‏‎‏‎‎‏‎‏‏‏‎‏‎‎‎‎‏‏‏‏‎‏‎Loading…‎‏‎‎‏‎"</string>
     <string name="capital_on" msgid="2770685323900821829">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‏‎‎‏‏‎‏‏‏‎‎‏‏‏‎‎‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‎‏‎‎‎‏‎‏‎ON‎‏‎‎‏‎"</string>
     <string name="capital_off" msgid="7443704171014626777">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‏‎‏‎‏‎‏‏‎‎‏‏‎‎‎‎‎‎‏‎‏‎‎‏‏‏‎‎‏‏‎‏‎‏‏‏‎‎‏‏‏‎‏‏‏‎‏‏‎‎‏‎OFF‎‏‎‎‏‎"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‎‎‏‎‏‏‏‎‎‎‎‏‏‎‏‏‏‎‏‎‏‏‎‏‎‏‎‎‎‏‏‏‎‏‏‎‏‏‏‏‎‏‏‏‏‏‎checked‎‏‎‎‏‎"</string>
+    <string name="not_checked" msgid="7972320087569023342">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‎‏‏‎‏‎‏‏‏‏‎‏‏‏‎‎‎‎‏‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‏‎‎not checked‎‏‎‎‏‎"</string>
     <string name="whichApplication" msgid="5432266899591255759">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‏‎‎‎‏‏‎‏‎‎‏‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‏‎‏‏‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‏‏‏‎Complete action using‎‏‎‎‏‎"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‎‎‎‎‎‎‎‎‏‏‎‎‎‎‏‏‎‎‎‎‎‎‏‎Complete action using %1$s‎‏‎‎‏‎"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‎‎‎‏‎‎‎‏‏‏‎‏‏‎‎‏‏‎‏‎‎‎‎‎‎‎‏‏‏‏‏‎‎‎‏‏‏‏‎‏‏‎‏‎‎‎‏‎‎‎‎‎Complete action‎‏‎‎‏‎"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‎‎‏‎‎‎‏‎‏‎‎‎‏‎‎‎‏‏‏‎‎‎‎‎‏‎‏‎‎‏‎Submit‎‏‎‎‏‎"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‏‏‎‏‏‏‎‎‏‎‎‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‏‏‏‎‏‎‎‎‏‎‎‎‎‏‏‏‎‎‏‏‏‎‎‎‎‎Driving app is running‎‏‎‎‏‎"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‏‎‎‏‏‏‏‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎‏‎‎‎‎‎‏‏‎‏‏‎‏‏‎Tap to exit driving app.‎‏‎‎‏‎"</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‏‏‏‎‏‎‎‎‏‏‎‎‎‎‎‎‏‏‎‏‎‎‎‎‏‏‏‏‎‏‎‎‏‏‏‎‏‎‎‎‏‎‎‏‏‎‎‎‏‏‏‎‎‏‎Tethering or hotspot active‎‏‎‎‏‎"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‏‏‏‎‏‎‎‏‎‏‏‎‎‏‏‏‎‎‏‏‎‎‎‏‏‎‏‏‏‎‎‏‎‎‏‏‎‏‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎Tap to set up.‎‏‎‎‏‎"</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‏‎‏‏‎‎‏‏‏‏‏‏‎‎‏‎‎‏‎‏‎‎‎‎‏‏‏‎‏‏‏‎‏‏‏‏‏‏‎‎‎‎‎‎‎‎‏‎‎‎‏‏‏‎Tethering is disabled‎‏‎‎‏‎"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‎‏‎‏‏‏‎‏‎‎‏‎‏‎‏‎‎‏‎‏‎‏‎‏‏‎‎‏‏‎‎‎‎‎‎‏‎‎‏‏‎‏‏‎‏‎‎‏‏‎‏‏‎‏‏‏‎Contact your admin for details‎‏‎‎‏‎"</string>
     <string name="back_button_label" msgid="4078224038025043387">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‏‎‎‎‏‏‎‎‎‎‏‏‎‎‏‎‎‏‏‏‏‎‏‏‏‏‎‎‏‏‏‏‎‎‎‏‎‎‎‏‏‏‎‏‏‎‏‏‏‎‏‏‎Back‎‏‎‎‏‎"</string>
     <string name="next_button_label" msgid="6040209156399907780">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‏‎‎‏‏‎‎‏‎‎‎‏‎‎‎‏‏‏‎‎‏‏‎‏‏‎‎‎‎‎‏‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‎‎‎‏‎‎‎Next‎‏‎‎‏‎"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‏‏‎‏‏‏‎‏‎‎‎‎‏‏‎‏‏‏‎‏‎‎‎‎‏‏‎‏‎‎‎‏‏‏‏‎‎‏‎‎‎‎‏‎‏‎Skip‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 6d0caff..b04882a 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"La app de administración de perfil de trabajo no se encuentra o está dañada. Por lo tanto, se borraron tu perfil de trabajo y los datos relacionados. Para obtener asistencia, comunícate con el administrador."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Tu perfil de trabajo ya no está disponible en este dispositivo"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Demasiados intentos para ingresar la contraseña"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Dispositivo administrado"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Tu organización administra este dispositivo y es posible que controle el tráfico de red. Presiona para obtener más información."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Se borrarán los datos del dispositivo"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Cargando…"</string>
     <string name="capital_on" msgid="2770685323900821829">"Sí"</string>
     <string name="capital_off" msgid="7443704171014626777">"No"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"activado"</string>
+    <string name="not_checked" msgid="7972320087569023342">"desactivado"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Completar la acción mediante"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Completar acción con %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Completar acción"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Enviar"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Se está ejecutando la app de conducción"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Presiona para salir de la app de conducción."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Anclaje a red o zona activa conectados"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Presiona para configurar."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Se inhabilitó la conexión mediante dispositivo portátil"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Para obtener más información, comunícate con el administrador"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Atrás"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Siguiente"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Omitir"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index ca5097b..81f210b 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Falta la aplicación de administración del perfil de trabajo o está dañada. Por ello, se han eliminado tu perfil de trabajo y los datos relacionados. Ponte en contacto con el administrador para obtener ayuda."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Tu perfil de trabajo ya no está disponible en este dispositivo"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Has fallado demasiadas veces al introducir la contraseña"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"El dispositivo está administrado"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Tu organización administra este dispositivo y puede supervisar el tráfico de red. Toca la notificación para obtener más información."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Tu dispositivo se borrará"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Cargando..."</string>
     <string name="capital_on" msgid="2770685323900821829">"ACTIVADO"</string>
     <string name="capital_off" msgid="7443704171014626777">"DESACTIVADO"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"seleccionado"</string>
+    <string name="not_checked" msgid="7972320087569023342">"no seleccionado"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Completar acción utilizando"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Completar acción con %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Completar acción"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Enviar"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Aplicación de conducción en uso"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Toca para salir de la aplicación de conducción."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Compartir conexión/Zona Wi-Fi activada"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Toca para configurar."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"La conexión compartida está inhabilitada"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Ponte en contacto con el administrador para obtener más información"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Atrás"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Siguiente"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Saltar"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 6b01527..61b18bb 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Tööprofiili administraatori rakendus puudub või on rikutud. Seetõttu on teie tööprofiil ja seotud andmed kustutatud. Abi saamiseks võtke ühendust administraatoriga."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Teie tööprofiil pole selles seadmes enam saadaval"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Liiga palju paroolikatseid"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Seade on hallatud"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Teie organisatsioon haldab seda seadet ja võib jälgida võrguliiklust. Puudutage üksikasjade vaatamiseks."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Seade kustutatakse"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Laadimine ..."</string>
     <string name="capital_on" msgid="2770685323900821829">"SEES"</string>
     <string name="capital_off" msgid="7443704171014626777">"VÄLJAS"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"märgitud"</string>
+    <string name="not_checked" msgid="7972320087569023342">"märkimata"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Lõpetage toiming rakendusega"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Toimingu lõpetamine, kasutades rakendust %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Vii toiming lõpule"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Saada"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Sõidurakendus töötab"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Puudutage sõidurakendusest väljumiseks."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Jagamine või kuumkoht on aktiivne"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Puudutage seadistamiseks."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Jagamine on keelatud"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Lisateabe saamiseks võtke ühendust oma administraatoriga"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Tagasi"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Järgmine"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Jäta vahele"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Vaheta jagatud ekraanikuva"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lukustuskuva"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekraanipilt"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> on hüpikaknas."</string>
 </resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 66672dd..fda8565 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Laneko profila administratzeko aplikazioa falta da edo hondatuta dago. Ondorioz, ezabatu egin dira laneko profila bera eta harekin erlazionatutako datuak. Laguntza lortzeko, jarri administratzailearekin harremanetan."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Laneko profila ez dago erabilgarri gailu honetan"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Gehiegitan saiatu zara pasahitza idazten"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Jabeak kudeatzen du gailua"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Erakundeak kudeatzen du gailua eta baliteke sareko trafikoa gainbegiratzea. Sakatu hau xehetasunak ikusteko."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Gailuko datuak ezabatu egingo dira"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Kargatzen…"</string>
     <string name="capital_on" msgid="2770685323900821829">"AKTIBATUTA"</string>
     <string name="capital_off" msgid="7443704171014626777">"DESAKTIBATUTA"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"markatuta"</string>
+    <string name="not_checked" msgid="7972320087569023342">"markatu gabe"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Gauzatu ekintza hau erabilita:"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Osatu ekintza %1$s erabiliz"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Osatu ekintza"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Bidali"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Abian da gidatzeko aplikazioa"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Sakatu gidatzeko aplikaziotik irteteko."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Konexioa partekatzea edo sare publikoa aktibo"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Sakatu konfiguratzeko."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Desgaituta dago konexioa partekatzeko aukera"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Xehetasunak lortzeko, jarri administratzailearekin harremanetan"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Atzera"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Hurrengoa"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Saltatu"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index c10dba5..433d4f3 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"برنامه سرپرست نمایه کاری یا وجود ندارد یا خراب است. در نتیجه، نمایه کاری شما و داده‌های مرتبط با آن حذف شده است. برای دریافت راهنمایی با سرپرست سیستم تماس بگیرید."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"نمایه کاری شما دیگر در این دستگاه دردسترس نیست"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"تلاش‌های بسیار زیادی برای وارد کردن گذرواژه انجام شده است"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"دستگاه مدیریت می‌شود"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"سازمانتان این دستگاه را مدیریت می‌کند و ممکن است ترافیک شبکه را پایش کند. برای اطلاع از جزئیات، ضربه بزنید."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"دستگاهتان پاک خواهد شد"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"درحال بارکردن…"</string>
     <string name="capital_on" msgid="2770685323900821829">"روشن"</string>
     <string name="capital_off" msgid="7443704171014626777">"خاموش"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"علامت‌زده‌شده"</string>
+    <string name="not_checked" msgid="7972320087569023342">"بدون علامت"</string>
     <string name="whichApplication" msgid="5432266899591255759">"تکمیل عملکرد با استفاده از"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"‏تکمیل عملکرد با استفاده از %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"تکمیل عملکرد"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"ارسال"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"برنامه رانندگی درحال اجرا است"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"برای خروج از برنامه رانندگی ضربه بزنید."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"اشتراک‌گذاری اینترنت یا نقطه اتصال فعال"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"برای راه‌اندازی ضربه بزنید."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"اشتراک‌گذاری اینترنت غیرفعال است"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"برای جزئیات، با سرپرستتان تماس بگیرید"</string>
     <string name="back_button_label" msgid="4078224038025043387">"برگشت"</string>
     <string name="next_button_label" msgid="6040209156399907780">"بعدی"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"رد شدن"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"تغییر وضعیت صفحهٔ دونیمه"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"صفحه قفل"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"عکس صفحه‌نمایش"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"برنامه <xliff:g id="APP_NAME">%1$s</xliff:g> در پنجره بالاپر."</string>
 </resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 35addd1..0c7bd77 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Työprofiilin hallintasovellus puuttuu tai se on vioittunut. Tästä syystä työprofiilisi ja siihen liittyvät tiedot on poistettu. Pyydä ohjeita järjestelmänvalvojaltasi."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Työprofiilisi ei ole enää käytettävissä tällä laitteella."</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Liikaa salasanayrityksiä"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Hallinnoitu laite"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Organisaatiosi hallinnoi tätä laitetta ja voi tarkkailla verkkoliikennettä. Katso lisätietoja napauttamalla."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Laitteen tiedot poistetaan"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Ladataan…"</string>
     <string name="capital_on" msgid="2770685323900821829">"PÄÄLLÄ"</string>
     <string name="capital_off" msgid="7443704171014626777">"POIS"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"valittu"</string>
+    <string name="not_checked" msgid="7972320087569023342">"ei valittu"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Tee toiminto käyttäen sovellusta"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Suorita sovelluksella %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Suorita toiminto"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Lähetä"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Ajosovellus on käynnissä"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Poistu ajosovelluksesta napauttamalla."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Internetin jakaminen tai yhteyspiste käytössä"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Määritä napauttamalla."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Yhteyden jakaminen poistettu käytöstä"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Kysy lisätietoja järjestelmänvalvojalta."</string>
     <string name="back_button_label" msgid="4078224038025043387">"Takaisin"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Seuraava"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Ohita"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 39dd905..3c8f75f 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Le profil professionnel de l\'application d\'administration est manquant ou corrompu. Votre profil professionnel et ses données connexes ont donc été supprimés. Communiquez avec votre administrateur pour obtenir de l\'assistance."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Votre profil professionnel n\'est plus accessible sur cet appareil"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Trop de tentatives d\'entrée du mot de passe"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"L\'appareil est géré"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Votre organisation gère cet appareil et peut surveiller le trafic réseau. Touchez ici pour obtenir plus d\'information."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Le contenu de votre appareil sera effacé"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Chargement en cours..."</string>
     <string name="capital_on" msgid="2770685323900821829">"OUI"</string>
     <string name="capital_off" msgid="7443704171014626777">"NON"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"coché"</string>
+    <string name="not_checked" msgid="7972320087569023342">"non coché"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Continuer avec"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Continuer avec %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Terminer l\'action"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Envoyer"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"L\'application de conduite est en cours d\'exécution"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Touchez pour quitter l\'application de conduite."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Partage de connexion ou point d\'accès sans fil activé"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Touchez pour configurer."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Le partage de connexion est désactivé"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Communiquez avec votre administrateur pour obtenir plus de détails"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Précédent"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Suivante"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Passer"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Basculer l\'écran partagé"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Écran de verrouillage"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capture d\'écran"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Application <xliff:g id="APP_NAME">%1$s</xliff:g> dans une fenêtre contextuelle."</string>
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index edc050c..1b53bd9 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"L\'application d\'administration du profil professionnel est manquante ou endommagée. Par conséquent, votre profil professionnel et toutes les données associées ont été supprimés. Pour obtenir de l\'aide, contactez l\'administrateur."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Votre profil professionnel n\'est plus disponible sur cet appareil"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Trop de tentatives de saisie du mot de passe"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"L\'appareil est géré"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Votre organisation gère cet appareil et peut surveiller le trafic réseau. Appuyez ici pour obtenir plus d\'informations."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Les données de votre appareil vont être effacées"</string>
@@ -1066,7 +1068,7 @@
     <string name="selectAll" msgid="1532369154488982046">"Tout sélectionner"</string>
     <string name="cut" msgid="2561199725874745819">"Couper"</string>
     <string name="copy" msgid="5472512047143665218">"Copier"</string>
-    <string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"Échec de la copie dans le Presse-papiers"</string>
+    <string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"Échec de la copie dans le presse-papiers"</string>
     <string name="paste" msgid="461843306215520225">"Coller"</string>
     <string name="paste_as_plain_text" msgid="7664800665823182587">"Coller au format texte brut"</string>
     <string name="replace" msgid="7842675434546657444">"Remplacer..."</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Chargement…"</string>
     <string name="capital_on" msgid="2770685323900821829">"OUI"</string>
     <string name="capital_off" msgid="7443704171014626777">"NON"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"activé"</string>
+    <string name="not_checked" msgid="7972320087569023342">"désactivé"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Continuer avec"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Terminer l\'action avec %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Terminer l\'action"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Envoyer"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"L\'application de conduite est en cours d\'exécution"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Appuyez ici pour quitter l\'application de conduite."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Partage de connexion ou point d\'accès sans fil activé"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Appuyez ici pour configurer."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Le partage de connexion est désactivé"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Pour en savoir plus, contactez votre administrateur"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Retour"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Suivant"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Ignorer"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 583cadf..4572db7 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Falta a aplicación de administración do perfil de traballo ou ben está danada. Como resultado, eliminouse o teu perfil de traballo e os datos relacionados. Para obter asistencia, contacta co administrador."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"O teu perfil de traballo xa non está dispoñible neste dispositivo"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Demasiados intentos de introdución do contrasinal"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"O dispositivo está xestionado"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"A túa organización xestiona este dispositivo e pode controlar o tráfico de rede. Toca para obter máis detalles."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Borrarase o teu dispositivo"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Cargando..."</string>
     <string name="capital_on" msgid="2770685323900821829">"SI"</string>
     <string name="capital_off" msgid="7443704171014626777">"NON"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"seleccionado"</string>
+    <string name="not_checked" msgid="7972320087569023342">"non seleccionado"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Completar a acción usando"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Completar a acción usando %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Completar acción"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Enviar"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Estase executando a aplicación de condución"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Toca para saír da aplicación de condución."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Conexión compartida ou zona wifi activada"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Tocar para configurar."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"A conexión compartida está desactivada"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Contacta co administrador para obter información"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Volver"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Seguinte"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Omitir"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Activar/desactivar pantalla dividida"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantalla de bloqueo"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Aplicación <xliff:g id="APP_NAME">%1$s</xliff:g> nunha ventá emerxente."</string>
 </resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index de31542..5e4f753 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"કાર્ય પ્રોફાઇલ વ્યવસ્થાપક ઍપ્લિકેશન ખૂટે છે અથવા તો દૂષિત છે. પરિણામે, તમારી કાર્યાલયની પ્રોફાઇલ અને તે સંબંધિત ડેટા કાઢી નાખવામાં આવ્યો છે. સહાયતા માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"આ ઉપકરણ પર તમારી કાર્યાલયની પ્રોફાઇલ હવે ઉપલબ્ધ નથી"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"પાસવર્ડના ઘણા વધુ પ્રયત્નો"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"ઉપકરણ સંચાલિત છે"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"તમારી સંસ્થા આ ઉપકરણનું સંચાલન કરે છે અને નેટવર્ક ટ્રાફિફનું નિયમન કરી શકે છે. વિગતો માટે ટૅપ કરો."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"તમારું ઉપકરણ કાઢી નાખવામાં આવશે"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"લોડ કરી રહ્યું છે…"</string>
     <string name="capital_on" msgid="2770685323900821829">"ચાલુ"</string>
     <string name="capital_off" msgid="7443704171014626777">"બંધ"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"ચેક કર્યું"</string>
+    <string name="not_checked" msgid="7972320087569023342">"ચેક કર્યું નથી"</string>
     <string name="whichApplication" msgid="5432266899591255759">"આના ઉપયોગથી ક્રિયા પૂર્ણ કરો"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ઉપયોગથી ક્રિયા પૂર્ણ કરો"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"ક્રિયા પૂર્ણ કરો"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"સબમિટ કરો"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ડ્રાઇવિંગ ઍપ ચાલી રહી છે"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ડ્રાઇવિંગ ઍપથી બહાર નીકળવા માટે ટૅપ કરો."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"ટિથરિંગ અથવા હૉટસ્પૉટ સક્રિય"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"સેટ કરવા માટે ટૅપ કરો."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"ટિથરિંગ અક્ષમ કરેલ છે"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"વિગતો માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો"</string>
     <string name="back_button_label" msgid="4078224038025043387">"પાછળ"</string>
     <string name="next_button_label" msgid="6040209156399907780">"આગલું"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"છોડો"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"સ્ક્રીનને વિભાજિત કરવાની ક્રિયા ટૉગલ કરો"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"લૉક સ્ક્રીન"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"સ્ક્રીનશૉટ"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"પૉપ-અપ વિંડોમાં <xliff:g id="APP_NAME">%1$s</xliff:g> ઍપ."</string>
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 5a422d8..eecfd5b 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"वर्क प्रोफ़ाइल व्यवस्थापक ऐप्लिकेशन या तो मौजूद नहीं है या वह खराब हो गया है. परिणामस्वरूप, आपकी वर्क प्रोफ़ाइल और उससे जुड़े डेटा को हटा दिया गया है. सहायता के लिए अपने व्यवस्थापक से संपर्क करें."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"आपकी वर्क प्रोफ़ाइल अब इस डिवाइस पर उपलब्‍ध नहीं है"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"कई बार गलत पासवर्ड डाला गया"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"डिवाइस प्रबंधित है"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"आपका संगठन इस डिवाइस का प्रबंधन करता है और वह नेटवर्क ट्रैफ़िक की निगरानी भी कर सकता है. विवरण के लिए टैप करें."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"आपके डिवाइस को मिटा दिया जाएगा"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"लोड हो रहे हैं..."</string>
     <string name="capital_on" msgid="2770685323900821829">"ऑन"</string>
     <string name="capital_off" msgid="7443704171014626777">"बंद"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"चालू है"</string>
+    <string name="not_checked" msgid="7972320087569023342">"बंद है"</string>
     <string name="whichApplication" msgid="5432266899591255759">"इसका इस्तेमाल करके कार्रवाई को पूरा करें"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s का उपयोग करके कार्रवाई पूरी करें"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"कार्रवाई पूरी करें"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"सबमिट करें"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ड्राइविंग ऐप्लिकेशन चल रहा है"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ड्राइविंग ऐप्लिकेशन से निकलने के लिए टैप करें."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"टेदरिंग या हॉटस्‍पॉट सक्रिय"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"सेट करने के लिए टैप करें."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"टेदरिंग अक्षम है"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"जानकारी के लिए अपने एडमिन से संपर्क करें"</string>
     <string name="back_button_label" msgid="4078224038025043387">"वापस जाएं"</string>
     <string name="next_button_label" msgid="6040209156399907780">"आगे बढ़ें"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"अभी नहीं"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"स्प्लिट स्क्रीन पर टॉगल करें"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"स्क्रीन लॉक करें"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"स्क्रीनशॉट लें"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"पॉप-अप विंडो में <xliff:g id="APP_NAME">%1$s</xliff:g> ऐप्लिकेशन."</string>
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index ed7234b..e8f02b2 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -190,6 +190,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Administratorska aplikacija radnog profila nedostaje ili je oštećena. Zbog toga su radni profil i povezani podaci izbrisani. Za pomoć se obratite svom administratoru."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Vaš radni profil više nije dostupan na ovom uređaju"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Previše pokušaja unosa zaporke"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Uređaj je upravljan"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Vaša organizacija upravlja ovim uređajem i može nadzirati mrežni promet. Dodirnite za pojedinosti."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će se izbrisati"</string>
@@ -1136,10 +1138,8 @@
     <string name="loading" msgid="3138021523725055037">"Učitavanje…"</string>
     <string name="capital_on" msgid="2770685323900821829">"Uklj."</string>
     <string name="capital_off" msgid="7443704171014626777">"Isklj."</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"potvrđeno"</string>
+    <string name="not_checked" msgid="7972320087569023342">"nije potvrđeno"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Radnju dovrši pomoću stavke"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Dovršavanje radnje pomoću aplikacije %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Dovrši radnju"</string>
@@ -1449,10 +1449,6 @@
     <string name="submit" msgid="862795280643405865">"Pošalji"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Pokrenuta je aplikacija za vožnju"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Dodirnite za zatvaranje aplikacije za vožnju."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Ograničenje ili aktivan hotspot"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Dodirnite da biste postavili."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Modemsko je povezivanje onemogućeno"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Obratite se administratoru da biste saznali pojedinosti"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Natrag"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Dalje"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Preskoči"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index aab5298..1d1b994 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"A munkaprofil rendszergazdai alkalmazása hiányzik vagy sérült. A rendszer ezért törölte a munkaprofilt, és az ahhoz kapcsolódó adatokat. Ha segítségre van szüksége, vegye fel a kapcsolatot rendszergazdájával."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Munkaprofilja már nem hozzáférhető ezen az eszközön."</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Túl sok jelszómegadási kísérlet"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Felügyelt eszköz"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Ezt az eszközt szervezete kezeli, és lehetséges, hogy a hálózati forgalmat is figyelik. További részletekért koppintson."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"A rendszer törölni fogja eszközét"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Betöltés..."</string>
     <string name="capital_on" msgid="2770685323900821829">"Be"</string>
     <string name="capital_off" msgid="7443704171014626777">"Ki"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"kiválasztva"</string>
+    <string name="not_checked" msgid="7972320087569023342">"nincs kiválasztva"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Művelet végrehajtása a következővel:"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Művelet elvégzése a(z) %1$s segítségével"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Művelet végrehajtása"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Elküldés"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Az autós alkalmazás fut"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Koppintson ide az autós alkalmazásból való kilépéshez."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Megosztás vagy aktív hotspot"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Koppintson a beállításhoz."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Az internetmegosztás le van tiltva"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"A részletekért forduljon rendszergazdájához"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Vissza"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Tovább"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Kihagyás"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index ee461f5..599ce86 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Աշխատանքային պրոֆիլի ադմինիստրատորի հավելվածը բացակայում է կամ վնասված է: Արդյունքում ձեր աշխատանքային պրոֆիլը և առնչվող տվյալները ջնջվել են: Օգնության համար դիմեք ձեր ադմինիստրատորին:"</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Ձեր աշխատանքային պրոֆիլն այս սարքում այլևս հասանելի չէ"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Գաղտնաբառը մուտքագրելու չափից շատ փորձեր են կատարվել"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Սարքը կառավարվում է"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Ձեր կազմակերպությունը կառավարում է այս սարքը և կարող է վերահսկել ցանցի թրաֆիկը: Հպեք՝ մանրամասները դիտելու համար:"</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Ձեր սարքը ջնջվելու է"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Բեռնում..."</string>
     <string name="capital_on" msgid="2770685323900821829">"I"</string>
     <string name="capital_off" msgid="7443704171014626777">"O"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"նշված է"</string>
+    <string name="not_checked" msgid="7972320087569023342">"նշված չէ"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Ավարտել գործողությունը` օգտագործելով"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Եզրափակել գործողությունը՝ օգտագործելով %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Ավարտել գործողությունը"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Ուղարկել"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Հավելվածն աշխատում է"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Հպեք՝ հավելվածը փակելու համար:"</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Մոդեմի ռեժիմը միացված է"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Հպեք՝ կարգավորելու համար:"</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Մոդեմի ռեժիմն անջատված է"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Մանրամասների համար դիմեք ձեր ադմինիստրատորին"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Հետ"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Հաջորդը"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Բաց թողնել"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Միացնել/անջատել էկրանի տրոհումը"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Կողպէկրան"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Սքրինշոթ"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը ելնող պատուհանում։"</string>
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index ece3a6c..1f81eb5 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Aplikasi admin profil kerja tidak ada atau rusak. Akibatnya, profil kerja dan data terkait telah dihapus. Hubungi admin untuk meminta bantuan."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Profil kerja tidak tersedia lagi di perangkat ini"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Terlalu banyak percobaan memasukkan sandi"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Perangkat ini ada yang mengelola"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Organisasi mengelola perangkat ini dan mungkin memantau traffic jaringan. Ketuk untuk melihat detailnya."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Perangkat akan dihapus"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Memuat..."</string>
     <string name="capital_on" msgid="2770685323900821829">"AKTIF"</string>
     <string name="capital_off" msgid="7443704171014626777">"MATI"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"dicentang"</string>
+    <string name="not_checked" msgid="7972320087569023342">"tidak dicentang"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Tindakan lengkap menggunakan"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Selesaikan tindakan menggunakan %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Selesaikan tindakan"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Kirim"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Aplikasi mengemudi sedang berjalan"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Ketuk untuk keluar dari aplikasi mengemudi."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Tethering (Penambatan) atau hotspot aktif"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Ketuk untuk menyiapkan."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering dinonaktifkan"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Hubungi admin untuk mengetahui detailnya"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Kembali"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Selanjutnya"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Lewati"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 3bcdda6..d23cf5f 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Stjórnunarforrit vinnusniðsins vantar eða er skemmt. Vinnusniðinu og gögnum því tengdu hefur því verið eytt. Hafðu samband við kerfisstjórann til að fá frekari aðstoð."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Vinnusniðið þitt er ekki lengur í boði á þessu tæki"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Of margar tilraunir til að slá inn aðgangsorð"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Tækinu er stjórnað"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Fyrirtækið þitt stjórnar þessu tæki og kann að fylgjast með netnotkun. Ýttu hér til að fá upplýsingar."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Tækið verður hreinsað"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Hleður…"</string>
     <string name="capital_on" msgid="2770685323900821829">"KVEIKT"</string>
     <string name="capital_off" msgid="7443704171014626777">"SLÖKKT"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"valið"</string>
+    <string name="not_checked" msgid="7972320087569023342">"ekki valið"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Ljúka aðgerð með"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Ljúka aðgerð með %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Ljúka aðgerð"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Senda"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Akstursforrit er í gangi"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Ýttu til að loka akstursforritinu."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Kveikt á tjóðrun eða aðgangsstað"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Ýttu til að setja upp."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Slökkt er á tjóðrun"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Hafðu samband við kerfisstjórann til að fá upplýsingar"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Til baka"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Áfram"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Sleppa"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Breyta skjáskiptingu"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lásskjár"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skjámynd"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Forritið <xliff:g id="APP_NAME">%1$s</xliff:g> í sprettiglugga."</string>
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 01bb136..8ebcb0e 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"L\'app di amministrazione dei profili di lavoro manca o è danneggiata. Di conseguenza, il tuo profilo di lavoro e i relativi dati sono stati eliminati. Contatta l\'amministratore per ricevere assistenza."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Il tuo profilo di lavoro non è più disponibile sul dispositivo"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Troppi tentativi di inserimento della password"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Il dispositivo è gestito"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Questo dispositivo è gestito dalla tua organizzazione, che potrebbe monitorare il traffico di rete. Tocca per i dettagli."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Il dispositivo verrà resettato"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Caricamento..."</string>
     <string name="capital_on" msgid="2770685323900821829">"ON"</string>
     <string name="capital_off" msgid="7443704171014626777">"OFF"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"selezionato"</string>
+    <string name="not_checked" msgid="7972320087569023342">"deselezionato"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Completa l\'azione con"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Completamento azione con %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Completa azione"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Invia"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"App di guida in esecuzione"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Tocca per uscire dall\'app di guida."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Tethering oppure hotspot attivo"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Tocca per impostare."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering disattivato"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Contatta il tuo amministratore per avere informazioni dettagliate"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Indietro"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Avanti"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Ignora"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index ed2e66a..85d0f3b 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -192,6 +192,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"אפליקציית הניהול של פרופיל העבודה חסרה או פגומה. כתוצאה מכך, פרופיל העבודה שלך נמחק, כולל כל הנתונים הקשורים אליו. לקבלת עזרה, פנה למנהל המערכת."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"פרופיל העבודה שלך אינו זמין עוד במכשיר הזה"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"בוצעו ניסיונות רבים מדי להזנת סיסמה"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"המכשיר מנוהל"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"הארגון שלך מנהל מכשיר זה ועשוי לנטר את התנועה ברשת. הקש לקבלת פרטים."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"תתבצע מחיקה של המכשיר"</string>
@@ -1156,10 +1158,8 @@
     <string name="loading" msgid="3138021523725055037">"טוען..."</string>
     <string name="capital_on" msgid="2770685323900821829">"מופעל"</string>
     <string name="capital_off" msgid="7443704171014626777">"כבוי"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"מסומן"</string>
+    <string name="not_checked" msgid="7972320087569023342">"לא מסומן"</string>
     <string name="whichApplication" msgid="5432266899591255759">"השלמת פעולה באמצעות"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"‏להשלמת הפעולה באמצעות %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"השלם פעולה"</string>
@@ -1469,10 +1469,6 @@
     <string name="submit" msgid="862795280643405865">"שלח"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"אפליקציית הנהיגה פועלת"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"יש להקיש כדי לצאת מאפליקציית הנהיגה."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"שיתוף אינטרנט פעיל"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"הקש כדי להגדיר."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"שיתוף האינטרנט בין ניידים מושבת"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"לפרטים, יש לפנות למנהל המערכת"</string>
     <string name="back_button_label" msgid="4078224038025043387">"הקודם"</string>
     <string name="next_button_label" msgid="6040209156399907780">"הבא"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"דילוג"</string>
@@ -2072,6 +2068,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"החלפת מצב של מסך מפוצל"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"מסך הנעילה"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"צילום מסך"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> בחלון קופץ."</string>
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 7ad1bc2..e21035f 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"仕事用プロファイルの管理アプリがないか、破損しています。そのため仕事用プロファイルと関連データが削除されました。管理者にサポートをご依頼ください。"</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"お使いの仕事用プロファイルはこのデバイスで使用できなくなりました"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"パスワード入力回数が上限を超えました"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"管理対象のデバイス"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"このデバイスは組織によって管理され、ネットワーク トラフィックが監視される場合があります。詳しくはタップしてください。"</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"デバイスのデータが消去されます"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"読み込んでいます..."</string>
     <string name="capital_on" msgid="2770685323900821829">"ON"</string>
     <string name="capital_off" msgid="7443704171014626777">"OFF"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"ON"</string>
+    <string name="not_checked" msgid="7972320087569023342">"OFF"</string>
     <string name="whichApplication" msgid="5432266899591255759">"アプリケーションを選択"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$sを使用してアクションを完了"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"アクションを実行"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"送信"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"運転アプリを実行しています"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"運転アプリを終了するにはタップしてください。"</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"テザリングまたはアクセスポイントが有効です"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"タップしてセットアップします。"</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"テザリングは無効に設定されています"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"詳しくは、管理者にお問い合わせください"</string>
     <string name="back_button_label" msgid="4078224038025043387">"戻る"</string>
     <string name="next_button_label" msgid="6040209156399907780">"次へ"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"スキップ"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"分割画面の切り替え"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ロック画面"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"スクリーンショット"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"<xliff:g id="APP_NAME">%1$s</xliff:g> アプリがポップアップ ウィンドウで開きます。"</string>
 </resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 7e4035d..941dbbd 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"სამსახურის პროფილის ადმინისტრატორის აპი მიუწვდომელია ან დაზიანებულია. ამის გამო, თქვენი სამსახურის პროფილი და დაკავშირებული მონაცემები წაიშალა. დახმარებისთვის დაუკავშირდით თქვენს ადმინისტრატორს."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"თქვენი სამსახურის პროფილი აღარ არის ხელმისაწვდომი ამ მოწყობილობაზე"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"დაფიქსირდა პაროლის შეყვანის ზედმეტად ბევრი მცდელობა"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"მოწყობილობა მართულია"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"ამ მოწყობილობას თქვენი ორგანიზაცია მართავს და მას ქსელის ტრაფიკის მონიტორინგი შეუძლია. შეეხეთ დამატებითი დეტალებისთვის."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"თქვენი მოწყობილობა წაიშლება"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"ჩატვირთვა…"</string>
     <string name="capital_on" msgid="2770685323900821829">"ჩართ."</string>
     <string name="capital_off" msgid="7443704171014626777">"გამორთ."</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"მონიშნულია"</string>
+    <string name="not_checked" msgid="7972320087569023342">"არ არის მონიშნული"</string>
     <string name="whichApplication" msgid="5432266899591255759">"რა გამოვიყენოთ?"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"მოქმედების %1$s-ის გამოყენებით დასრულება"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"მოქმედების დასრულება"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"გაგზავნა"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"მართვის აპი გაშვებულია"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"შეეხეთ მართვის აპიდან გასასვლელად."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"ტეტერინგი ან უსადენო ქსელი აქტიურია"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"შეეხეთ დასაყენებლად."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"ტეტერინგი გათიშულია"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს"</string>
     <string name="back_button_label" msgid="4078224038025043387">"უკან"</string>
     <string name="next_button_label" msgid="6040209156399907780">"მომდევნო"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"გამოტოვება"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"გაყოფილი ეკრანის გადართვა"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ჩაკეტილი ეკრანი"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ეკრანის ანაბეჭდი"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"<xliff:g id="APP_NAME">%1$s</xliff:g> აპი ამომხტარ ფანჯარაში."</string>
 </resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 661f7c1..b142e58 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Жұмыс профилінің әкімші қолданбасы жоқ немесе бүлінген. Нәтижесінде жұмыс профиліңіз және қатысты деректер жойылды. Көмек алу үшін әкімшіге хабарласыңыз."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Жұмыс профиліңіз осы құрылғыда енді қолжетімді емес"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Құпия сөз көп рет қате енгізілді"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Құрылғы басқарылады"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Ұйымыңыз осы құрылғыны басқарады және желі трафигін бақылауы мүмкін. Мәліметтер алу үшін түртіңіз."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Құрылғыңыздағы деректер өшіріледі"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Жүктелуде…"</string>
     <string name="capital_on" msgid="2770685323900821829">"Қосулы"</string>
     <string name="capital_off" msgid="7443704171014626777">"Өшірулі"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"белгіленген"</string>
+    <string name="not_checked" msgid="7972320087569023342">"белгіленбеген"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Әрекетті аяқтау"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Әрекетті %1$s қолданбасын пайдаланып аяқтау"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Әрекетті аяқтау"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Жіберу"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Көлік жүргізу қолданбасы қосулы"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Көлік жүргізу қолданбасынан шығу үшін түртіңіз."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Тетеринг немесе хотспот қосулы"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Реттеу үшін түртіңіз."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Тетеринг өшірілді"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Мәліметтерді әкімшіден алыңыз"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Артқа"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Келесі"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Өткізіп жіберу"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Экранды бөлу мүмкіндігін қосу/өшіру"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Құлып экраны"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Қалқымалы терезедегі <xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы"</string>
 </resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index ded2999..43289eb 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"កម្មវិធី​អ្នកគ្រប់គ្រង​កម្រងព័ត៌មាន​ការងារនេះ​អាច​បាត់ ឬ​មាន​បញ្ហា។ ដូច្នេះហើយ​ទើប​កម្រងព័ត៌មាន​ការងារ​របស់អ្នក និង​ទិន្នន័យ​ដែល​ពាក់ព័ន្ធត្រូវ​បានលុប។ សូមទាក់ទង​ទៅអ្នក​គ្រប់គ្រង​របស់អ្នក ដើម្បី​ទទួល​បាន​ជំនួយ។"</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"កម្រងព័ត៌មាន​ការងារ​របស់អ្នក​លែងមាន​នៅលើ​ឧបករណ៍​នេះទៀត​ហើយ"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"ការព្យាយាមបញ្ចូលពាក្យសម្ងាត់ច្រើនដងពេកហើយ"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"ឧបករណ៍ស្ថិតក្រោមការគ្រប់គ្រង"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"ស្ថាប័នរបស់អ្នកគ្រប់គ្រងឧបករណ៍នេះ ហើយអាចនឹងតាមដានចរាចរណ៍បណ្តាញ។ ចុចដើម្បីទទួលបានព័ត៌មានលម្អិត។"</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"ឧបករណ៍របស់អ្នកនឹងត្រូវបានលុប"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"កំពុង​ផ្ទុក..."</string>
     <string name="capital_on" msgid="2770685323900821829">"បើក"</string>
     <string name="capital_off" msgid="7443704171014626777">"បិទ"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"បានធីក​"</string>
+    <string name="not_checked" msgid="7972320087569023342">"មិន​បាន​ធីក​"</string>
     <string name="whichApplication" msgid="5432266899591255759">"បញ្ចប់​សកម្មភាព​ដោយ​ប្រើ"</string>
     <!-- String.format failed for translation -->
     <!-- no translation found for whichApplicationNamed (6969946041713975681) -->
@@ -1431,10 +1431,6 @@
     <string name="submit" msgid="862795280643405865">"ដាក់​ស្នើ"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"កម្មវិធី​បើកបរ​កំពុង​ដំណើរការ"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ចុច​ដើម្បី​ចាកចេញ​ពីកម្មវិធី​បើកបរ។"</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"ភ្ជាប់ ឬ​ហតស្ពត​សកម្ម"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"ប៉ះដើម្បីកំណត់"</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"ការភ្ជាប់​ត្រូវបានបិទ"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"ទាក់ទងអ្នកគ្រប់គ្រង​របស់អ្នកសម្រាប់​ព័ត៌មានលម្អិត"</string>
     <string name="back_button_label" msgid="4078224038025043387">"ថយក្រោយ"</string>
     <string name="next_button_label" msgid="6040209156399907780">"បន្ទាប់​"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"រំលង"</string>
@@ -2006,6 +2002,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"បិទ/បើក​មុខងារ​បំបែកអេក្រង់"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"អេក្រង់ចាក់សោ"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"រូបថតអេក្រង់"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"កម្មវិធី <xliff:g id="APP_NAME">%1$s</xliff:g> នៅក្នុងវិនដូ​លោតឡើង។"</string>
 </resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 10930af..6ebe7b4 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್‌ ನಿರ್ವಾಹಕ ಅಪ್ಲಿಕೇಶನ್ ಕಳೆದು ಹೋಗಿದೆ ಅಥವಾ ಹಾಳಾಗಿದೆ. ಇದರ ಪರಿಣಾಮವಾಗಿ ನಿಮ್ಮ ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್‌ ಮತ್ತು ಅದಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗಿದೆ. ಸಹಾಯಕ್ಕಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ನಿಮ್ಮ ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್‌ ಈ ಸಾಧನದಲ್ಲಿ ಈಗ ಲಭ್ಯವಿಲ್ಲ"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"ಹಲವಾರು ಪಾಸ್‌ವರ್ಡ್ ಪ್ರಯತ್ನಗಳು"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"ಸಾಧನವನ್ನು ನಿರ್ವಹಿಸಲಾಗುತ್ತಿದೆ"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"ನಿಮ್ಮ ಸಂಸ್ಥೆಯು ಈ ಸಾಧನವನ್ನು ನಿರ್ವಹಿಸುತ್ತದೆ ಮತ್ತು ಅದು ನೆಟ್‌ವರ್ಕ್ ಟ್ರಾಫಿಕ್ ಮೇಲೆ ಗಮನವಿರಿಸಬಹುದು. ವಿವರಗಳಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ..."</string>
     <string name="capital_on" msgid="2770685323900821829">"ಆನ್‌ ಮಾಡಿ"</string>
     <string name="capital_off" msgid="7443704171014626777">"ಆಫ್ ಮಾಡು"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"ಪರಿಶೀಲಿಸಲಾಗಿದೆ"</string>
+    <string name="not_checked" msgid="7972320087569023342">"ಪರಿಶೀಲಿಸಲಾಗಿಲ್ಲ"</string>
     <string name="whichApplication" msgid="5432266899591255759">"ಇದನ್ನು ಬಳಸಿಕೊಂಡು ಕ್ರಿಯೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿ"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ಬಳಸಿಕೊಂಡು ಕ್ರಿಯೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿ"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"ಕ್ರಿಯೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿ"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"ಸಲ್ಲಿಸು"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ಡ್ರೈವಿಂಗ್‌ ಅಪ್ಲಿಕೇಶನ್ ಚಾಲನೆಯಲ್ಲಿದೆ"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ಡ್ರೈವಿಂಗ್‌ ಅಪ್ಲಿಕೇಶನ್ ನಿರ್ಗಮಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"ಟೆಥರಿಂಗ್ ಅಥವಾ ಹಾಟ್‌ಸ್ಪಾಟ್ ಸಕ್ರಿಯವಾಗಿದೆ"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"ಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"ಟೆಥರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"ವಿವರಗಳಿಗಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ"</string>
     <string name="back_button_label" msgid="4078224038025043387">"ಹಿಂದೆ"</string>
     <string name="next_button_label" msgid="6040209156399907780">"ಮುಂದಿನದು"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"ಸ್ಕಿಪ್‌"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"ಸ್ಪ್ಲಿಟ್-ಸ್ಕ್ರೀನ್ ಟಾಗಲ್ ಮಾಡಿ"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ಲಾಕ್ ಸ್ಕ್ರೀನ್"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"ಪಾಪ್-ಅಪ್ ಸ್ಪೇಸ್ ವಿಂಡೋದಲ್ಲಿ <xliff:g id="APP_NAME">%1$s</xliff:g> ಆ್ಯಪ್."</string>
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 431af17..c6caedf 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"직장 프로필 관리 앱이 없거나 손상되어 직장 프로필 및 관련 데이터가 삭제되었습니다. 도움이 필요한 경우 관리자에게 문의하세요."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"직장 프로필을 이 기기에서 더 이상 사용할 수 없습니다."</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"비밀번호 입력을 너무 많이 시도함"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"관리되는 기기"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"조직에서 이 기기를 관리하며 네트워크 트래픽을 모니터링할 수도 있습니다. 자세한 내용을 보려면 탭하세요."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"기기가 삭제됩니다."</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"로드 중.."</string>
     <string name="capital_on" msgid="2770685323900821829">"ON"</string>
     <string name="capital_off" msgid="7443704171014626777">"OFF"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"선택함"</string>
+    <string name="not_checked" msgid="7972320087569023342">"선택 안함"</string>
     <string name="whichApplication" msgid="5432266899591255759">"작업을 수행할 때 사용하는 애플리케이션"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s을(를) 사용하여 작업 완료"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"작업 완료"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"제출"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"운전 앱 실행 중"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"운전 앱을 종료하려면 탭하세요."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"테더링 또는 핫스팟 사용"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"설정하려면 탭하세요."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"테더링이 사용 중지됨"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"자세한 정보는 관리자에게 문의하세요."</string>
     <string name="back_button_label" msgid="4078224038025043387">"뒤로"</string>
     <string name="next_button_label" msgid="6040209156399907780">"다음"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"건너뛰기"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"화면 분할 모드 전환"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"잠금 화면"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"스크린샷"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"팝업 창의 <xliff:g id="APP_NAME">%1$s</xliff:g> 앱"</string>
 </resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index c8116cc..341c996 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Жумуш профилинин башкаруучу колдонмосу жок же бузулгандыктан, жумуш профилиңиз жана ага байланыштуу дайындар жок кылынды. Жардам алуу үчүн администраторуңузга кайрылыңыз."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Жумуш профилиңиз бул түзмөктөн жок кылынды"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Өтө көп жолу сырсөздү киргизүү аракети жасалды"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Түзмөктү ишкана башкарат"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Ишканаңыз бул түзмөктү башкарат жана тармак трафигин көзөмөлдөшү мүмкүн. Чоо-жайын көрүү үчүн таптап коюңуз."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Түзмөгүңүз тазаланат"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Жүктөлүүдө…"</string>
     <string name="capital_on" msgid="2770685323900821829">"ЖАНДЫРЫЛГАН"</string>
     <string name="capital_off" msgid="7443704171014626777">"ӨЧҮК"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"белгиленген"</string>
+    <string name="not_checked" msgid="7972320087569023342">"белгилене элек"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Аракет колдонууну бүтүрүү"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s аркылуу аракетти аягына чейин чыгаруу"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Аракетти аягына чыгаруу"</string>
@@ -1307,8 +1307,7 @@
     <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Тиркелген түзмөк бул телефонго шайкеш келбейт. Көбүрөөк маалымат алуу үчүн таптап коюңуз."</string>
     <string name="adb_active_notification_title" msgid="408390247354560331">"Мүчүлүштүктөрдү USB аркылуу оңдоо иштеп жатат"</string>
     <string name="adb_active_notification_message" msgid="5617264033476778211">"Өчүрүү үчүн тийип коюңуз"</string>
-    <!-- no translation found for adb_active_notification_message (6624498401272780855) -->
-    <skip />
+    <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB аркылуу мүчүлүштүктөрдү оңдоону өчүрүүнү тандаңыз."</string>
     <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Сыноо программасынын режими иштетилди"</string>
     <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Сыноо программасынын режимин өчүрүү үчүн, баштапкы жөндөөлөргө кайтарыңыз."</string>
     <string name="console_running_notification_title" msgid="6087888939261635904">"Сериялык консоль иштетилди"</string>
@@ -1430,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Тапшыруу"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Унаа айдоо колдонмосу иштеп жатат"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Унаа айдоо колдонмосунан чыгуу үчүн таптаңыз."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Жалгаштыруу же хотспот жандырылган"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Жөндөө үчүн таптап коюңуз."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Жалгаштыруу функциясы өчүрүлгөн"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Кеңири маалымат үчүн администраторуңузга кайрылыңыз"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Артка"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Кийинки"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Өткөрүп жиберүү"</string>
@@ -2005,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Экранды бөлүүнү күйгүзүү же өчүрүү"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Кулпуланган экран"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу Калкыма терезеде көрүндү."</string>
 </resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 9acb031..e0da206 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"ບໍ່ມີແອັບຜູ້ເບິ່ງແຍງລະບົບໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ ຫຼື ເສຍຫາຍ. ຜົນກໍຄື, ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ ແລະ ຂໍ້ມູນທີ່ກ່ຽວຂ້ອງຂອງທ່ານຖືກລຶບອອກແລ້ວ. ໃຫ້ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບການຊ່ວຍເຫຼືອ."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຂອງທ່ານບໍ່ສາມາດໃຊ້ໄດ້ໃນອຸປະກອນນີ້ອີກຕໍ່ໄປ"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"ລອງໃສ່ລະຫັດຜ່ານຫຼາຍເທື່ອເກີນໄປ"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"ອຸປະກອນມີການຈັດການ"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"ອົງກອນຂອງທ່ານຈັດການອຸປະກອນນີ້ ແລະ ອາດກວດສອບທຣາບຟິກເຄືອຂ່າຍນຳ. ແຕະເພື່ອເບິ່ງລາຍລະອຽດ."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ​ຈະ​ຖືກ​ລຶບ"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"ກຳລັງໂຫລດ..."</string>
     <string name="capital_on" msgid="2770685323900821829">"ເປີດ"</string>
     <string name="capital_off" msgid="7443704171014626777">"ປິດ"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"ໝາຍຖືກແລ້ວ"</string>
+    <string name="not_checked" msgid="7972320087569023342">"ບໍ່ໄດ້ໝາຍຖືກ"</string>
     <string name="whichApplication" msgid="5432266899591255759">"ດຳເນີນການໂດຍໃຊ້"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"ສຳ​ເລັດ​​​ການ​ດຳ​ເນີນ​ການ​ໂດຍ​ໃຊ້ %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"ສຳເລັດຄຳສັ່ງ"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"ສົ່ງຂໍ້ມູນ"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ແອັບຂັບລົດກຳລັງເຮັດວຽກຢູ່"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ແຕະເພື່ອອອກຈາກແອັບຂັບລົດ."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"ເປີດ​ການ​ປ່ອຍ​ສັນຍານ ຫຼື​ຮັອດສະປອດ​ແລ້ວ"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"ແຕະເພື່ອຕັ້ງຄ່າ."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"ການປ່ອຍສັນຍານຖືກປິດໄວ້"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບລາຍລະອຽດ"</string>
     <string name="back_button_label" msgid="4078224038025043387">"ກັບຄືນ"</string>
     <string name="next_button_label" msgid="6040209156399907780">"ຕໍ່ໄປ"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"ຂ້າມ"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"ເປີດ/ປິດການແບ່ງໜ້າຈໍ"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ໜ້າຈໍລັອກ"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ຮູບໜ້າຈໍ"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"ແອັບ <xliff:g id="APP_NAME">%1$s</xliff:g> ໃນໜ້າຈໍປັອບອັບ."</string>
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 30b551e..1212aa4 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -192,6 +192,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Trūksta darbo profilio administratoriaus programos arba ji sugadinta. Todėl darbo profilis ir susiję duomenys buvo ištrinti. Jei reikia pagalbos, susisiekite su administratoriumi."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Darbo profilis nebepasiekiamas šiame įrenginyje"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Per daug slaptažodžio bandymų"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Įrenginys yra tvarkomas"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Šį įrenginį tvarko organizacija ir gali stebėti tinklo srautą. Palieskite, kad gautumėte daugiau informacijos."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Įrenginys bus ištrintas"</string>
@@ -1156,10 +1158,8 @@
     <string name="loading" msgid="3138021523725055037">"Įkeliama..."</string>
     <string name="capital_on" msgid="2770685323900821829">"ĮJ."</string>
     <string name="capital_off" msgid="7443704171014626777">"IŠJ."</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"pažymėta"</string>
+    <string name="not_checked" msgid="7972320087569023342">"nepažymėta"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Užbaigti veiksmą naudojant"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Užbaigti veiksmą naudojant %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Užbaigti veiksmą"</string>
@@ -1469,10 +1469,6 @@
     <string name="submit" msgid="862795280643405865">"Pateikti"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Veikia vairavimo programa"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Palieskite, kad išeitumėte iš vairavimo programos."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Susietas ar aktyvus"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Palieskite, kad nustatytumėte."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Įrenginio kaip modemo naudojimas išjungtas"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Jei reikia išsamios informacijos, susisiekite su administratoriumi"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Atgal"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Kitas"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Praleisti"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index ae1831b..547b6c9 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -190,6 +190,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Trūkst darba profila administratora lietotnes, vai šī lietotne ir bojāta. Šī iemesla dēļ jūsu darba profils un saistītie dati tika dzēsti. Lai saņemtu palīdzību, sazinieties ar administratoru."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Jūsu darba profils šai ierīcē vairs nav pieejams."</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Veikts pārāk daudz paroles ievadīšanas mēģinājumu."</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Ierīce tiek pārvaldīta"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Jūsu organizācija pārvalda šo ierīci un var uzraudzīt tīkla datplūsmu. Pieskarieties, lai saņemtu detalizētu informāciju."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Jūsu ierīces dati tiks dzēsti"</string>
@@ -1136,10 +1138,8 @@
     <string name="loading" msgid="3138021523725055037">"Notiek ielāde..."</string>
     <string name="capital_on" msgid="2770685323900821829">"IESLĒGT"</string>
     <string name="capital_off" msgid="7443704171014626777">"IZSL."</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"atzīmēts"</string>
+    <string name="not_checked" msgid="7972320087569023342">"nav atzīmēts"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Izvēlieties lietotni"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Pabeigt darbību, izmantojot %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Pabeigt darbību"</string>
@@ -1449,10 +1449,6 @@
     <string name="submit" msgid="862795280643405865">"Iesniegt"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Autovadīšanas lietotne darbojas"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Pieskarieties, lai izietu no autovadīšanas lietotnes"</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Piesaiste vai tīklājs ir aktīvs."</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Pieskarieties, lai iestatītu."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Piesaiste ir atspējota"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Lai iegūtu detalizētu informāciju, sazinieties ar savu administratoru."</string>
     <string name="back_button_label" msgid="4078224038025043387">"Atpakaļ"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Tālāk"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Izlaist"</string>
@@ -2038,6 +2034,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Pārslēgt ekrāna sadalīšanu"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloķēt ekrānu"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekrānuzņēmums"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> uznirstošajā logā."</string>
 </resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 480561f..93f2da1 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Апликацијата на администраторот за работниот профил или исчезна или е оштетена. Како резултат на тоа, вашиот работен профил и поврзаните податоци ќе се избришат. За помош, контактирајте со администраторот."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Вашиот работен профил веќе не е достапен на уредов"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Премногу обиди за внесување лозинка"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Некој управува со уредот"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Вашата организација управува со уредов и можно е да го следи сообраќајот на мрежата. Допрете за детали."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Уредот ќе се избрише"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Се вчитува..."</string>
     <string name="capital_on" msgid="2770685323900821829">"ВКЛУЧЕНО"</string>
     <string name="capital_off" msgid="7443704171014626777">"ИСКЛУЧЕНО"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"штиклирано"</string>
+    <string name="not_checked" msgid="7972320087569023342">"не е штиклирано"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Заврши дејство со"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Остварете го дејството со %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Заврши го дејството"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Поднеси"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Апликацијата за возење работи"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Допрете за да излезете од апликацијата за возење."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Поврзувањето или точката на пристап се активни"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Допрете за поставување."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Врзувањето е оневозможено"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Контактирајте со администраторот за детали"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Назад"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Следно"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Прескокни"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index d3b9123..c220cdd 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"ഔദ്യോഗിക പ്രൊഫൈൽ അഡ്‌മിൻ ആപ്പ് വിട്ടുപോയിരിക്കുന്നു അല്ലെങ്കിൽ കേടായിരിക്കുന്നു. ഫലമായി, നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലും ബന്ധപ്പെട്ട വിവരങ്ങളും ഇല്ലാതാക്കിയിരിക്കുന്നു. സഹായത്തിന് അഡ്‌മിനെ ബന്ധപ്പെടുക."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ഈ ഉപകരണത്തിൽ തുടർന്നങ്ങോട്ട് നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ ലഭ്യമല്ല"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"വളരെയധികം പാസ്‌വേഡ് ശ്രമങ്ങൾ"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"ഉപകരണം മാനേജുചെയ്യുന്നുണ്ട്"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"നിങ്ങളുടെ സ്ഥാപനമാണ് ഈ ഉപകരണം മാനേജുചെയ്യുന്നത്, നെറ്റ്‌വർക്ക് ട്രാഫിക്ക് നിരീക്ഷിക്കുകയും ചെയ്തേക്കാം, വിശദാംശങ്ങൾ അറിയാൻ ടാപ്പുചെയ്യുക."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"നിങ്ങളുടെ ഉപകരണം മായ്‌ക്കും"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"ലോഡുചെയ്യുന്നു..."</string>
     <string name="capital_on" msgid="2770685323900821829">"ഓൺ"</string>
     <string name="capital_off" msgid="7443704171014626777">"ഓഫ്"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"പരിശോധിച്ചത്"</string>
+    <string name="not_checked" msgid="7972320087569023342">"പരിശോധിക്കാത്തത്"</string>
     <string name="whichApplication" msgid="5432266899591255759">"പൂർണ്ണമായ പ്രവർത്തനം ഉപയോഗിക്കുന്നു"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ഉപയോഗിച്ച് പ്രവർത്തനം പൂർത്തിയാക്കുക"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"പ്രവർത്തനം പൂർത്തിയാക്കുക"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"സമർപ്പിക്കുക"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ഡ്രൈവിംഗ് ആപ്പ് റൺ ചെയ്യുകയാണ്"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ഡ്രൈവിംഗ് ആപ്പിൽ നിന്ന് പുറത്തുകടക്കാൻ ടാപ്പ് ചെയ്യുക."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"ടെതറിംഗ് അല്ലെങ്കിൽ ഹോട്ട്സ്‌പോട്ട് സജീവമാണ്"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"സജ്ജമാക്കാൻ ടാപ്പുചെയ്യുക."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"ടെതറിംഗ് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"വിശദവിവരങ്ങൾക്ക് നിങ്ങളുടെ അഡ്മിനെ ബന്ധപ്പെടുക"</string>
     <string name="back_button_label" msgid="4078224038025043387">"മടങ്ങുക"</string>
     <string name="next_button_label" msgid="6040209156399907780">"അടുത്തത്"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"ഒഴിവാക്കുക"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"സ്‌ക്രീൻ വിഭജന മോഡ് മാറ്റുക"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ലോക്ക് സ്‌ക്രീൻ"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"സ്ക്രീൻഷോട്ട്"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"പോപ്പ്-അപ്പ് വിൻഡോയിലെ <xliff:g id="APP_NAME">%1$s</xliff:g> ആപ്പ്."</string>
 </resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index e8f6a50..8c26113 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Ажлын профайлын админ апп байхгүй эсвэл эвдэрсэн байна. Үүний улмаас таны ажлын профайл болон холбогдох мэдээллийг устгасан болно. Тусламж хэрэгтэй бол админтай холбогдоно уу."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Таны ажлын профайл энэ төхөөрөмжид боломжгүй байна"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Нууц үгийг хэт олон удаа буруу оруулсан байна"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Төхөөрөмжийг удирдсан"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Таны байгууллага энэ төхөөрөмжийг удирдаж, сүлжээний ачааллыг хянадаг. Дэлгэрэнгүй мэдээлэл авах бол товшино уу."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Таны төхөөрөмж устах болно."</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Ачааллаж байна..."</string>
     <string name="capital_on" msgid="2770685323900821829">"Идэвхтэй"</string>
     <string name="capital_off" msgid="7443704171014626777">"Идэвхгүй"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"тэмдэглэсэн"</string>
+    <string name="not_checked" msgid="7972320087569023342">"тэмдэглээгүй"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Үйлдлийг дуусгах"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ашиглан үйлдлийг гүйцээх"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Үйлдлийг дуусгах"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Илгээх"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Жолоо барих апп ажиллаж байна"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Жолооны аппаас гарахын тулд товшино уу."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Модем болгох эсвэл идэвхтэй цэг болгох"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Тохируулахын тулд товшино уу."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Модем болгох боломжгүй байна"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Дэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Буцах"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Дараах"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Алгасах"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Дэлгэц хуваахыг унтраах/асаах"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Дэлгэцийг түгжих"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Дэлгэцийн зураг дарах"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Үзэгдэх цонхонд байгаа <xliff:g id="APP_NAME">%1$s</xliff:g> апп."</string>
 </resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 18f0911..2782caf 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"कार्य प्रोफाइल प्रशासक अ‍ॅप गहाळ आहे किंवा करप्ट आहे. परिणामी, तुमचे कार्य प्रोफाइल आणि संबंधित डेटा हटवले गेले आहेत. सहाय्यासाठी आपल्या प्रशासकाशी संपर्क साधा."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"तुमचे कार्य प्रोफाइल आता या डिव्हाइसवर उपलब्‍ध नाही"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"बर्‍याचदा पासवर्ड टाकण्‍याचा प्रयत्‍न केला"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"डिव्हाइस व्यवस्थापित केले आहे"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"तुमची संस्था हे डिव्हाइस व्यवस्थापित करते आणि नेटवर्क रहदारीचे निरीक्षण करू शकते. तपशीलांसाठी टॅप करा."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"तुमचे डिव्हाइस मिटविले जाईल"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"लोड करत आहे..."</string>
     <string name="capital_on" msgid="2770685323900821829">"सुरू"</string>
     <string name="capital_off" msgid="7443704171014626777">"बंद"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"तपासले"</string>
+    <string name="not_checked" msgid="7972320087569023342">"तपासले नाही"</string>
     <string name="whichApplication" msgid="5432266899591255759">"याचा वापर करून क्रिया पूर्ण करा"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s वापरून क्रिया पूर्ण करा"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"क्रिया पूर्ण झाली"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"सबमिट करा"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ड्रायव्हिंग अ‍ॅप चालू आहे"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ड्रायव्हिंग ॲपमधून बाहेर पाडण्यासाठी टॅप करा."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"टेदरिंग किंवा हॉटस्पॉट सक्रिय"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"सेट करण्यासाठी टॅप करा."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"टेदरिंग बंद आहे"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"तपशीलांसाठी तुमच्या प्रशासकाशी संपर्क साधा"</string>
     <string name="back_button_label" msgid="4078224038025043387">"मागे"</string>
     <string name="next_button_label" msgid="6040209156399907780">"पुढील"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"वगळा"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"विभाजित स्क्रीन टॉगल करा"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"स्‍क्रीन लॉक करा"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"स्क्रीनशॉट"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"पॉप-अप विंडोमध्ये <xliff:g id="APP_NAME">%1$s</xliff:g> ॲप."</string>
 </resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 0a404e7..a40eca0 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Apl pentadbir profil kerja tiada atau rosak. Akibatnya, profil kerja anda dan data yang berkaitan telah dipadamkan. Hubungi pentadbir anda untuk mendapatkan bantuan."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Profil kerja anda tidak lagi tersedia pada peranti ini"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Terlalu banyak percubaan kata laluan"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Peranti ini diurus"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Organisasi anda mengurus peranti ini dan mungkin memantau trafik rangkaian. Ketik untuk mendapatkan butiran."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Peranti anda akan dipadam"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Memuatkan…"</string>
     <string name="capital_on" msgid="2770685323900821829">"HIDUP"</string>
     <string name="capital_off" msgid="7443704171014626777">"MATIKAN"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"ditandai"</string>
+    <string name="not_checked" msgid="7972320087569023342">"tidak ditandai"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Selesaikan tindakan menggunakan"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Selesaikan tindakan menggunakan %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Selesaikan tindakan"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Serah"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Apl memandu sedang berjalan"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Ketik untuk keluar daripada apl memandu."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Penambatan atau titik panas aktif"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Ketik untuk membuat persediaan."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Penambatan dilumpuhkan"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Hubungi pentadbir anda untuk maklumat lanjut"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Kembali"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Seterusnya"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Langkau"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Togol Skrin Pisah"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Skrin Kunci"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Tangkapan skrin"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Apl <xliff:g id="APP_NAME">%1$s</xliff:g> dalam tetingkap Timbul."</string>
 </resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index e34190d..64e2376 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"အလုပ်ပရိုဖိုင် စီမံခန့်ခွဲရန်အက်ပ် မရှိပါ သို့မဟုတ် ပျက်စီးနေပါသည်။ ထို့ကြောင့် သင်၏ အလုပ်ပရိုဖိုင်နှင့် ဆက်စပ်နေသော ဒေတာများကို ဖျက်လိုက်ပါပြီ။ အကူအညီရယူရန် သင်၏စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။"</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ဤစက်ပစ္စည်းတွင် သင်၏ အလုပ်ပရိုဖိုင်မရှိတော့ပါ"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"စကားဝှက်ထည့်သွင်းရန် ကြိုးစားသည့် အကြိမ်အရေအတွက် အလွန်များသွား၍ ဖြစ်ပါသည်"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"စက်ပစ္စည်းကို စီမံခန့်ခွဲထားပါသည်"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"ဤစက်ပစ္စည်းကို သင်၏ အဖွဲ့အစည်းက စီမံပြီး ကွန်ရက်အသွားအလာကို စောင့်ကြည့်နိုင်ပါသည်။ ထပ်မံလေ့လာရန် တို့ပါ။"</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"သင့်ကိရိယာအား ပယ်ဖျက်လိမ့်မည်"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"တင်နေ…"</string>
     <string name="capital_on" msgid="2770685323900821829">"ဖွင့်ရန်"</string>
     <string name="capital_off" msgid="7443704171014626777">"ပိတ်"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"အမှန်ခြစ်ပြီး"</string>
+    <string name="not_checked" msgid="7972320087569023342">"ခြစ် မထား"</string>
     <string name="whichApplication" msgid="5432266899591255759">"အသုံးပြု၍ ဆောင်ရွက်မှုအားပြီးဆုံးစေခြင်း"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ကို သုံးပြီး လုပ်ဆောင်ချက် ပြီးဆုံးပါစေ"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"လုပ်ဆောင်ချက်ကို အပြီးသတ်ပါ"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"ပေးပို့ရန်"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ကားမောင်းသည့်အက်ပ် ပွင့်နေပါသည်"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ကားမောင်းသည့်အက်ပ်မှ ထွက်ရန် တို့ပါ။"</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"တဆင့်ပြန်လည်လွှင့်ခြင်း သို့မဟုတ် ဟော့စပေါ့ ဖွင့်ထားသည်"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"စနစ်ထည့်သွင်းရန် တို့ပါ။"</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"မိုဘိုင်းဖုန်းကို မိုဒမ်အဖြစ်သုံးခြင်းအား ပိတ်ထားသည်"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"အသေးစိတ်အချက်အလက်များအတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ"</string>
     <string name="back_button_label" msgid="4078224038025043387">"နောက်သို့"</string>
     <string name="next_button_label" msgid="6040209156399907780">"ရှေ့သို့"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"ကျော်ရန်"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းကို နှိပ်ပါ"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"လော့ခ်မျက်နှာပြင်"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"ပေါ့ပ်အပ်ဝင်းဒိုးတွင်ရှိသော <xliff:g id="APP_NAME">%1$s</xliff:g>အက်ပ်။"</string>
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 69ee017..69e341e 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Administratorappen for jobbprofilen mangler eller er skadet. Dette har ført til at jobbprofilen og alle data knyttet til den, har blitt slettet. Ta kontakt med administratoren for å få hjelp."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Jobbprofilen din er ikke lenger tilgjengelig på denne enheten"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"For mange passordforsøk"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Enheten administreres"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Organisasjonen din kontrollerer denne enheten og kan overvåke nettverkstrafikk. Trykk for å få mer informasjon."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Enheten blir slettet"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Laster inn …"</string>
     <string name="capital_on" msgid="2770685323900821829">"På"</string>
     <string name="capital_off" msgid="7443704171014626777">"Av"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"avmerket"</string>
+    <string name="not_checked" msgid="7972320087569023342">"ikke avmerket"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Fullfør med"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Fullfør handlingen med %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Fullfør handlingen"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Send inn"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Kjøreappen kjører"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Trykk for å lukke kjøreappen."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Internettdeling eller trådløs sone er aktiv"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Trykk for å konfigurere."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Internettdeling er slått av"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Ta kontakt med administratoren din for å få mer informasjon"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Tilbake"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Neste"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Hopp over"</string>
@@ -1539,7 +1535,7 @@
     <string name="launchBrowserDefault" msgid="6328349989932924119">"Vil du starte nettleseren?"</string>
     <string name="SetupCallDefault" msgid="5581740063237175247">"Vil du besvare anropet?"</string>
     <string name="activity_resolver_use_always" msgid="5575222334666843269">"Alltid"</string>
-    <string name="activity_resolver_set_always" msgid="4142825808921411476">"Angi som alltid åpen"</string>
+    <string name="activity_resolver_set_always" msgid="4142825808921411476">"Alltid"</string>
     <string name="activity_resolver_use_once" msgid="948462794469672658">"Bare én gang"</string>
     <string name="activity_resolver_app_settings" msgid="6758823206817748026">"Innstillinger"</string>
     <string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s støtter ikke arbeidsprofiler"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Slå delt skjerm av/på"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Låseskjerm"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skjermdump"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"<xliff:g id="APP_NAME">%1$s</xliff:g>-appen i forgrunnsvindu."</string>
 </resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index cabb5c0..0fb2213 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"उक्त कार्य प्रोफाइलको प्रशासकीय अनुप्रयोग छैन वा बिग्रेको छ। त्यसले गर्दा, तपाईंको कार्य प्रोफाइल र सम्बन्धित डेटालाई मेटिएको छ। सहायताका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्।"</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"तपाईंको कार्य प्रोफाइल अब उप्रान्त यस यन्त्रमा उपलब्ध छैन"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"पासवर्ड प्रविष्ट गर्ने अत्यधिक गलत प्रयासहरू भए"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"यन्त्र व्यवस्थित गरिएको छ"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"तपाईंको संगठनले यस यन्त्रको व्यवस्थापन गर्दछ र नेटवर्क ट्राफिकको अनुगमन गर्न सक्छ। विवरणहरूका लागि ट्याप गर्नुहोस्।"</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"तपाईंको यन्त्र मेटिनेछ"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"लोड हुँदै..."</string>
     <string name="capital_on" msgid="2770685323900821829">"चालु"</string>
     <string name="capital_off" msgid="7443704171014626777">"बन्द"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"जाँच गरिएको"</string>
+    <string name="not_checked" msgid="7972320087569023342">"जाँच गरिएको छैन"</string>
     <string name="whichApplication" msgid="5432266899591255759">"प्रयोग गरेर कारबाही पुरा गर्नुहोस्"</string>
     <!-- String.format failed for translation -->
     <!-- no translation found for whichApplicationNamed (6969946041713975681) -->
@@ -1435,10 +1435,6 @@
     <string name="submit" msgid="862795280643405865">"पेस गर्नुहोस्"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ड्राइभिङ अनुप्रयोग चलिरहेको छ"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ड्राइभिङ अनुप्रयोगबाट बाहिर निस्कन ट्याप गर्नुहोस्।"</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"टेथर गर्ने वा हटस्पट सक्रिय"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"सेटअप गर्न ट्याप गर्नुहोस्।"</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"टेदरिङलाई असक्षम पारिएको छ"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"विवरणहरूका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्"</string>
     <string name="back_button_label" msgid="4078224038025043387">"पछाडि"</string>
     <string name="next_button_label" msgid="6040209156399907780">"अर्को"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"छोड्नुहोस्"</string>
@@ -2010,6 +2006,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"विभाजित स्क्रिन टगल गर्नुहोस्"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"लक स्क्रिन"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"स्क्रिनसट"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"पपअप विन्डोमा <xliff:g id="APP_NAME">%1$s</xliff:g> अनुप्रयोग छ।"</string>
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 28fdfa5..363c3c3 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"De beheer-app van het werkprofiel ontbreekt of is beschadigd. Als gevolg hiervan zijn je werkprofiel en alle gerelateerde gegevens verwijderd. Neem contact op met je beheerder voor hulp."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Je werkprofiel is niet meer beschikbaar op dit apparaat"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Te veel wachtwoordpogingen"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Apparaat wordt beheerd"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Dit apparaat wordt beheerd door je organisatie. Het netwerkverkeer kan worden bijgehouden. Tik voor meer informatie."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Je apparaat wordt gewist"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Laden..."</string>
     <string name="capital_on" msgid="2770685323900821829">"AAN"</string>
     <string name="capital_off" msgid="7443704171014626777">"UIT"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"aangevinkt"</string>
+    <string name="not_checked" msgid="7972320087569023342">"niet aangevinkt"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Actie voltooien met"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Actie voltooien via %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Actie voltooien"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Verzenden"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Auto-app wordt uitgevoerd"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Tik om de auto-app te sluiten."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Tethering of hotspot actief"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Tik om in te stellen."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering is uitgeschakeld"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Neem contact op met je beheerder voor meer informatie"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Vorige"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Volgende"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Overslaan"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 23e04b7..566d778 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"ଆଡମିନ୍‍ ଆପ୍‍ ନାହିଁ କିମ୍ବା ଭୁଲ ଅଛି। ଫଳସ୍ୱରୂପ, ଆପଣଙ୍କ ୱାର୍କ ପ୍ରୋଫାଇଲ୍‍ ଏବଂ ସମ୍ବନ୍ଧୀୟ ଡାଟା ଡିଲିଟ୍ କରାଯାଇଛି। ସହାୟତା ପାଇଁ ଆପଣଙ୍କ ଆଡମିନଙ୍କୁ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ଏହି ଡିଭାଇସରେ ଆପଣଙ୍କ ୱର୍କ ପ୍ରୋଫାଇଲ୍‍ ଆଉ ଉପଲବ୍ଧ ନାହିଁ"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"ବହୁତ ଥର ଭୁଲ ପାସ୍‌ୱର୍ଡ ଲେଖିଛନ୍ତି"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"ଡିଭାଇସକୁ ପରିଚାଳନା କରାଯାଉଛି"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"ଆପଣଙ୍କ ସଂସ୍ଥା ଏହି ଡିଭାଇସକୁ ପରିଚାଳନା କରନ୍ତି ଏବଂ ନେଟୱର୍କ ଟ୍ରାଫିକ୍‍ ନୀରିକ୍ଷଣ କରନ୍ତି। ବିବରଣୀ ପାଇଁ ଟାପ୍‍ କରନ୍ତୁ।"</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"ଆପଣଙ୍କ ଡିଭାଇସ୍‍ ବର୍ତ୍ତମାନ ଲିଭାଯିବ"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"ଲୋଡ୍ କରାଯାଉଛି…"</string>
     <string name="capital_on" msgid="2770685323900821829">"ଅନ୍"</string>
     <string name="capital_off" msgid="7443704171014626777">"ଅଫ୍"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"ଯାଞ୍ଚ ହୋଇଛି"</string>
+    <string name="not_checked" msgid="7972320087569023342">"ଯାଞ୍ଚ ହୋଇନାହିଁ"</string>
     <string name="whichApplication" msgid="5432266899591255759">"ବ୍ୟବହାର କରି କାର୍ଯ୍ୟ ସମ୍ପୂର୍ଣ୍ଣ କରନ୍ତୁ"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ବ୍ୟବହାର କରି କାର୍ଯ୍ୟ ସମ୍ପୂର୍ଣ୍ଣ କରନ୍ତୁ"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"କାର୍ଯ୍ୟ ସମ୍ପୂର୍ଣ୍ଣ କରନ୍ତୁ"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"ଦାଖଲ କରନ୍ତୁ"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ଡ୍ରାଇଭିଙ୍ଗ ଆପ୍ ଚାଲୁଛି"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ଡ୍ରାଇଭିଙ୍ଗ ଆପ୍‌ରୁ ବାହାରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ।"</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"ଟିଥରିଙ୍ଗ କିମ୍ୱା ହଟସ୍ପଟ୍‌ ସକ୍ରିୟ ଅଛି"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"ସେଟଅପ୍‍ କରିବାକୁ ଟାପ୍‍ କରନ୍ତୁ।"</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"ଟିଥରିଙ୍ଗ ଅକ୍ଷମ କରାଯାଇଛି"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"ବିବରଣୀ ପାଇଁ ନିଜ ଆଡମିନ୍‌ଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ"</string>
     <string name="back_button_label" msgid="4078224038025043387">"ଫେରନ୍ତୁ"</string>
     <string name="next_button_label" msgid="6040209156399907780">"ପରବର୍ତ୍ତୀ"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"ଛାଡ଼ିଦିଅନ୍ତୁ"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"ଦୁଇଟି ସ୍କ୍ରିନ୍ ମଧ୍ୟରେ ଟୋଗଲ୍ କରନ୍ତୁ"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ସ୍କ୍ରିନ୍ ଲକ୍ କରନ୍ତୁ"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ସ୍କ୍ରି‍ନ୍‍ସଟ୍ ନିଅନ୍ତୁ"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"ପପ୍-ଅପ୍ ୱିଣ୍ଡୋରେ <xliff:g id="APP_NAME">%1$s</xliff:g> ଆପ୍"</string>
 </resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 891f1f1..7760db0 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਪ੍ਰਸ਼ਾਸਕ ਐਪ ਜਾਂ ਤਾਂ ਗੁੰਮਸ਼ੁਦਾ ਹੈ ਜਾਂ ਖਰਾਬ ਹੈ। ਨਤੀਜੇ ਵਜੋਂ, ਤੁਹਾਡੀ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਅਤੇ ਸਬੰਧਿਤ ਡਾਟਾ ਮਿਟਾਇਆ ਗਿਆ ਹੈ। ਸਹਾਇਤਾ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ।"</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ਤੁਹਾਡਾ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਹੁਣ ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"ਕਈ ਵਾਰ ਗਲਤ ਪਾਸਵਰਡ ਦਾਖਲ ਕੀਤਾ ਗਿਆ"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"ਡੀਵਾਈਸ ਪ੍ਰਬੰਧਨ ਅਧੀਨ ਹੈ"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"ਤੁਹਾਡਾ ਸੰਗਠਨ ਇਸ ਡੀਵਾਈਸ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਦਾ ਹੈ ਅਤੇ ਨੈੱਟਵਰਕ ਟਰੈਫਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦਾ ਹੈ। ਵੇਰਵਿਆਂ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਮਿਟਾਇਆ ਜਾਏਗਾ"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"ਲੋਡ ਹੋ ਰਿਹਾ ਹੈ..."</string>
     <string name="capital_on" msgid="2770685323900821829">"ਚਾਲੂ"</string>
     <string name="capital_off" msgid="7443704171014626777">"ਬੰਦ"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"ਨਿਸ਼ਾਨਬੱਧ ਕੀਤਾ ਗਿਆ"</string>
+    <string name="not_checked" msgid="7972320087569023342">"ਨਿਸ਼ਾਨਬੱਧ ਨਹੀਂ ਕੀਤਾ ਗਿਆ"</string>
     <string name="whichApplication" msgid="5432266899591255759">"ਇਸਨੂੰ ਵਰਤਦੇ ਹੋਏ ਕਾਰਵਾਈ ਪੂਰੀ ਕਰੋ"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ਵਰਤਦੇ ਹੋਏ ਕਾਰਵਾਈ ਪੂਰੀ ਕਰੋ"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"ਕਾਰਵਾਈ ਪੂਰੀ ਕਰੋ"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"ਪ੍ਰਸਤੁਤ ਕਰੋ"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ਗੱਡੀ ਚਲਾਉਣ ਸੰਬੰਧੀ ਐਪ ਚੱਲ ਰਹੀ ਹੈ"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ਗੱਡੀ ਚਲਾਉਣ ਸੰਬੰਧੀ ਐਪ ਤੋਂ ਬਾਹਰ ਜਾਣ ਲਈ ਟੈਪ ਕਰੋ।"</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"ਟੈਦਰਿੰਗ ਜਾਂ ਹੌਟਸਪੌਟ ਕਿਰਿਆਸ਼ੀਲ"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"ਸਥਾਪਤ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"ਟੈਦਰਿੰਗ ਨੂੰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"ਵੇਰਵਿਆਂ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ"</string>
     <string name="back_button_label" msgid="4078224038025043387">"ਪਿੱਛੇ"</string>
     <string name="next_button_label" msgid="6040209156399907780">"ਅੱਗੇ"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"ਛੱਡੋ"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਨੂੰ ਟੌਗਲ ਕਰੋ"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ਲਾਕ ਸਕ੍ਰੀਨ"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"ਪੌਪ-ਅੱਪ ਵਿੰਡੋ ਵਿੱਚ <xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ।"</string>
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 811c5d8..4ff7cc4 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -192,6 +192,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Brakuje aplikacji administratora profilu do pracy lub jest ona uszkodzona. Dlatego Twój profil służbowy i związane z nim dane zostały usunięte. Skontaktuj się ze swoim administratorem, by uzyskać pomoc."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Twój profil służbowy nie jest już dostępny na tym urządzeniu"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Zbyt wiele prób podania hasła"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Urządzenie jest zarządzane"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Twoja organizacja zarządza tym urządzeniem i może monitorować ruch w sieci. Kliknij, by dowiedzieć się więcej."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Twoje urządzenie zostanie wyczyszczone"</string>
@@ -1156,10 +1158,8 @@
     <string name="loading" msgid="3138021523725055037">"Wczytuję…"</string>
     <string name="capital_on" msgid="2770685323900821829">"Wł."</string>
     <string name="capital_off" msgid="7443704171014626777">"Wył."</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"wybrano"</string>
+    <string name="not_checked" msgid="7972320087569023342">"nie wybrano"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Wykonaj czynność przez..."</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Wykonaj czynność w aplikacji %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Wykonaj działanie"</string>
@@ -1469,10 +1469,6 @@
     <string name="submit" msgid="862795280643405865">"Prześlij"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Tryb samochodowy jest włączony"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Kliknij, by zakończyć tryb samochodowy."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Aktywny tethering lub punkt dostępu"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Kliknij, by skonfigurować."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering został wyłączony"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Aby uzyskać szczegółowe informacje, skontaktuj się z administratorem"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Wróć"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Dalej"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Pomiń"</string>
@@ -2072,6 +2068,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Przełącz podzielony ekran"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ekran blokady"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Zrzut ekranu"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> w wyskakującym okienku."</string>
 </resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index ecd10c3..1750d2a 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"O app para administrador do perfil de trabalho não foi encontrado ou está corrompido. Consequentemente, seu perfil de trabalho e os dados relacionados foram excluídos. Entre em contato com seu administrador para receber assistência."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Seu perfil de trabalho não está mais disponível neste dispositivo"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Muitas tentativas de senha"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"O dispositivo é gerenciado"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Sua organização gerencia este dispositivo e pode monitorar o tráfego de rede. Toque para ver detalhes."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Seu dispositivo será limpo"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Carregando…"</string>
     <string name="capital_on" msgid="2770685323900821829">"LIG"</string>
     <string name="capital_off" msgid="7443704171014626777">"DESL"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"marcado"</string>
+    <string name="not_checked" msgid="7972320087569023342">"não marcado"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Complete a ação usando"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Concluir a ação usando %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Concluir ação"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Enviar"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"O app para carro está sendo usado"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Toque para sair do app para carro."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Ponto de acesso ou tethering ativo"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Toque para configurar."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering desativado"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Fale com seu administrador para saber detalhes"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Voltar"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Avançar"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Pular"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 0cfbf8c..5c21c0d 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"A aplicação de administração do perfil de trabalho está em falta ou danificada. Consequentemente, o seu perfil de trabalho e os dados relacionados foram eliminados. Contacte o gestor para obter assistência."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"O seu perfil de trabalho já não está disponível neste dispositivo"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Demasiadas tentativas de introdução da palavra-passe"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"O dispositivo é gerido"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"A sua entidade gere este dispositivo e pode monitorizar o tráfego de rede. Toque para obter mais detalhes."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"O seu dispositivo será apagado"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"A carregar…"</string>
     <string name="capital_on" msgid="2770685323900821829">"Ativado"</string>
     <string name="capital_off" msgid="7443704171014626777">"Desativado"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"selecionado"</string>
+    <string name="not_checked" msgid="7972320087569023342">"não selecionado"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Concluir ação utilizando"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Concluir ação utilizando %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Concluir ação"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Enviar"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"A aplicação de condução está em execução."</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Toque para sair da aplicação de condução."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Ligação ponto a ponto ou hotspot activos"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Toque para configurar."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"A ligação (à Internet) via telemóvel está desativada."</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Contacte o gestor para obter detalhes."</string>
     <string name="back_button_label" msgid="4078224038025043387">"Anterior"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Seguinte"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Ignorar"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index ecd10c3..1750d2a 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"O app para administrador do perfil de trabalho não foi encontrado ou está corrompido. Consequentemente, seu perfil de trabalho e os dados relacionados foram excluídos. Entre em contato com seu administrador para receber assistência."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Seu perfil de trabalho não está mais disponível neste dispositivo"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Muitas tentativas de senha"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"O dispositivo é gerenciado"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Sua organização gerencia este dispositivo e pode monitorar o tráfego de rede. Toque para ver detalhes."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Seu dispositivo será limpo"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Carregando…"</string>
     <string name="capital_on" msgid="2770685323900821829">"LIG"</string>
     <string name="capital_off" msgid="7443704171014626777">"DESL"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"marcado"</string>
+    <string name="not_checked" msgid="7972320087569023342">"não marcado"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Complete a ação usando"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Concluir a ação usando %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Concluir ação"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Enviar"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"O app para carro está sendo usado"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Toque para sair do app para carro."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Ponto de acesso ou tethering ativo"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Toque para configurar."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering desativado"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Fale com seu administrador para saber detalhes"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Voltar"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Avançar"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Pular"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index f501032..397525a 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -190,6 +190,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Aplicația de administrare a profilului de serviciu lipsește sau este deteriorată. Prin urmare, profilul de serviciu și datele asociate au fost șterse. Pentru asistență, contactați administratorul."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Profilul de serviciu nu mai este disponibil pe acest dispozitiv"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Prea multe încercări de introducere a parolei"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Dispozitivul este gestionat"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Organizația dvs. gestionează acest dispozitiv și poate monitoriza traficul în rețea. Atingeți pentru mai multe detalii."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Datele de pe dispozitiv vor fi șterse"</string>
@@ -1136,10 +1138,8 @@
     <string name="loading" msgid="3138021523725055037">"Se încarcă…"</string>
     <string name="capital_on" msgid="2770685323900821829">"DA"</string>
     <string name="capital_off" msgid="7443704171014626777">"NU"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"bifat"</string>
+    <string name="not_checked" msgid="7972320087569023342">"nebifat"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Finalizare acțiune utilizând"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Finalizați acțiunea utilizând %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Finalizați acțiunea"</string>
@@ -1449,10 +1449,6 @@
     <string name="submit" msgid="862795280643405865">"Trimiteți"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Aplicația pentru condus rulează"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Atingeți ca să ieșiți din aplicația pentru condus."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Tethering sau hotspot activ"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Atingeți ca să configurați."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tetheringul este dezactivat"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Contactați administratorul pentru detalii"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Înapoi"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Înainte"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Omiteți"</string>
@@ -2038,6 +2034,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Activați ecranul împărțit"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ecran de blocare"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captură de ecran"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Aplicația <xliff:g id="APP_NAME">%1$s</xliff:g> în fereastră pop-up."</string>
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index aefc373..a7abbff 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -192,6 +192,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Приложение для администрирования рабочего профиля отсутствует или повреждено. Из-за этого рабочий профиль и связанные с ним данные были удалены. Если у вас возникли вопросы, обратитесь к администратору."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Ваш рабочий профиль больше не доступен на этом устройстве"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Слишком много попыток ввести пароль."</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Это управляемое устройство"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Ваша организация управляет этим устройством и может отслеживать сетевой трафик. Подробнее…"</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Все данные с устройства будут удалены"</string>
@@ -1156,10 +1158,8 @@
     <string name="loading" msgid="3138021523725055037">"Загрузка…"</string>
     <string name="capital_on" msgid="2770685323900821829">"I"</string>
     <string name="capital_off" msgid="7443704171014626777">"O"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"отмечено"</string>
+    <string name="not_checked" msgid="7972320087569023342">"не отмечено"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Что использовать?"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Выполнить с помощью приложения \"%1$s\""</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Выполнить действие"</string>
@@ -1469,10 +1469,6 @@
     <string name="submit" msgid="862795280643405865">"Отправить"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Приложение для вождения включено"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Нажмите, чтобы выйти из приложения для вождения."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Включен режим модема"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Нажмите, чтобы настроить."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Включить режим модема нельзя"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Обратитесь к администратору, чтобы узнать подробности."</string>
     <string name="back_button_label" msgid="4078224038025043387">"Назад"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Далее"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Пропустить"</string>
@@ -2072,6 +2068,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Включить или выключить разделение экрана"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заблокированный экран"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" в всплывающем окне."</string>
 </resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 67dfbd3..7d3f80d 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"කාර්යාල පැතිකඩ පාලක යෙදුම නොමැති හෝ දූෂණය වී ඇත. ප්‍රතිඵලයක් ලෙස ඔබගේ කාර්යාල පැතිකඩ සහ අදාළ දත්ත මකා දමා ඇත. සහය සඳහා ඔබගේ පරිපාලකයා සම්බන්ධ කර ගන්න."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ඔබේ කාර්යාල පැතිකඩ මෙම උපාංගය මත තවදුරටත් ලබා ගැනීමට නොහැකිය"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"මුරපද උත්සාහ කිරීම් ඉතා වැඩි ගණනකි"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"උපාංගය කළමනාකරණය කෙරේ"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"ඔබගේ ආයතනය මෙම උපාංගය කළමනාකරණය කරන අතර එය ජාල තදබදය නිරීක්ෂණය කළ හැක. විස්තර සඳහා තට්ටු කරන්න."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"ඔබගේ උපාංගය මකා දැමෙනු ඇත"</string>
@@ -1118,10 +1120,8 @@
     <string name="loading" msgid="3138021523725055037">"පූරණය වෙමින්..."</string>
     <string name="capital_on" msgid="2770685323900821829">"සක්‍රීයයි"</string>
     <string name="capital_off" msgid="7443704171014626777">"ක්‍රියාවිරහිතයි"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"පරීක්ෂා කර ඇත"</string>
+    <string name="not_checked" msgid="7972320087569023342">"පරීක්ෂා කර නැත"</string>
     <string name="whichApplication" msgid="5432266899591255759">"පහත භාවිතයෙන් ක්‍රියාව සම්පූර්ණ කරන්න"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s භාවිතා කරමින් ක්‍රියාව සම්පුර්ණ කරන්න"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"ක්‍රියාව සම්පූර්ණ කරන්න"</string>
@@ -1431,10 +1431,6 @@
     <string name="submit" msgid="862795280643405865">"යොමු කරන්න"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"රියදුරු යෙදුම ධාවනය වේ."</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"රියදුරු යෙදුමෙන් පිටවීම සඳහා තට්ටු කරන්න."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"ටෙදරින් හෝ හොට්ස්පොට් සක්‍රීයයි"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"පිහිටුවීමට තට්ටු කරන්න."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"ටෙදරින් අබල කර ඇත"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"විස්තර සඳහා ඔබගේ පරිපාලක අමතන්න"</string>
     <string name="back_button_label" msgid="4078224038025043387">"ආපසු"</string>
     <string name="next_button_label" msgid="6040209156399907780">"මීලඟ"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"මඟ හරින්න"</string>
@@ -2006,6 +2002,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"බෙදුම් තිරය ටොගල කරන්න"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"අගුලු තිරය"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"තිර රුව"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"උත්පතන කවුළුව තුළ <xliff:g id="APP_NAME">%1$s</xliff:g> යෙදුම."</string>
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index c1eec99..3a81468c 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -192,6 +192,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Aplikácia na správu pracovného profilu buď chýba, alebo je poškodená. Z toho dôvodu bol odstránený pracovný profil aj k nemu priradené dáta. Ak potrebujete pomoc, kontaktujte svojho správcu."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Váš pracovný profil už v tomto zariadení nie je k dispozícii"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Príliš veľa pokusov o zadanie hesla"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Zariadenie je spravované"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Vaša organizácia spravuje toto zariadenie a môže sledovať sieťovú premávku. Klepnutím zobrazíte podrobnosti."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Vaše zariadenie bude vymazané"</string>
@@ -1156,10 +1158,8 @@
     <string name="loading" msgid="3138021523725055037">"Načítava sa…"</string>
     <string name="capital_on" msgid="2770685323900821829">"I"</string>
     <string name="capital_off" msgid="7443704171014626777">"O"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"začiarknuté"</string>
+    <string name="not_checked" msgid="7972320087569023342">"nezačiarknuté"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Dokončiť akciu pomocou aplikácie"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Dokončiť akciu pomocou aplikácie %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Dokončiť akciu"</string>
@@ -1469,10 +1469,6 @@
     <string name="submit" msgid="862795280643405865">"Odoslať"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Aplikácia na šoférovanie je spustená"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Klepnutím ukončíte aplikáciu na šoférovanie"</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Tethering alebo prístupový bod je aktívny"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Klepnutím prejdete na nastavenie."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering je deaktivovaný"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"O podrobnosti požiadajte svojho správcu"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Späť"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Ďalej"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Preskočiť"</string>
@@ -2072,6 +2068,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Prepnúť rozdelenú obrazovku"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Uzamknúť obrazovku"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snímka obrazovky"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> vo vyskakovacom okne."</string>
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index d15d6a9..c28384c 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -192,6 +192,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Skrbniška aplikacija delovnega profila manjka ali pa je poškodovana, zaradi česar je bil delovni profil s povezanimi podatki izbrisan. Za pomoč se obrnite na skrbnika."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Vaš delovni profil ni več na voljo v tej napravi"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Preveč poskusov vnosa gesla"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Naprava je upravljana"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Vaša organizacija upravlja to napravo in lahko nadzira omrežni promet. Dotaknite se za podrobnosti."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Podatki v napravi bodo izbrisani"</string>
@@ -1156,10 +1158,8 @@
     <string name="loading" msgid="3138021523725055037">"Nalaganje …"</string>
     <string name="capital_on" msgid="2770685323900821829">"VKLOPLJENO"</string>
     <string name="capital_off" msgid="7443704171014626777">"IZKLOPLJENO"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"potrjeno"</string>
+    <string name="not_checked" msgid="7972320087569023342">"ni potrjeno"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Dokončanje dejanja z"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Dokončanje dejanja z aplikacijo %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Izvedba dejanja"</string>
@@ -1469,10 +1469,6 @@
     <string name="submit" msgid="862795280643405865">"Pošlji"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Aplikacija za vožnjo se izvaja"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Dotaknite se, če želite zapreti aplikacijo za vožnjo."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Aktivna povezava z internetom ali dostopna točka sta aktivni"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Dotaknite se, če želite nastaviti."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Povezava z internetom prek mobilnega telefona je onemogočena"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Za podrobnosti se obrnite na skrbnika"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Nazaj"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Naprej"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Preskoči"</string>
@@ -2072,6 +2068,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Preklop razdeljenega zaslona"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaklenjen zaslon"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Posnetek zaslona"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v pojavnem oknu."</string>
 </resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 6bf8184..39f7377 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Aplikacioni i administratorit të profilit të punës mungon ose është dëmtuar. Si rezultat i kësaj, profili yt i punës dhe të dhënat përkatëse janë fshirë. Kontakto me administratorin për ndihmë."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Profili yt i punës nuk është më i disponueshëm në këtë pajisje"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Shumë përpjekje për fjalëkalimin"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Pajisja është e menaxhuar"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Organizata jote e menaxhon këtë pajisje dhe mund të monitorojë trafikun e rrjetit. Trokit për detaje."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Pajisja do të spastrohet"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Po ngarkohet..."</string>
     <string name="capital_on" msgid="2770685323900821829">"Aktivizuar"</string>
     <string name="capital_off" msgid="7443704171014626777">"Çaktivizuar"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"u përzgjodh"</string>
+    <string name="not_checked" msgid="7972320087569023342">"nuk u përzgjodh"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Përfundo veprimin duke përdorur"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Përfundo veprimin duke përdorur %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Përfundo veprimin"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Dërgo"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Aplikacioni i drejtimit të makinës është në ekzekutim"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Trokit për të dalë nga aplikacioni i drejtimit të makinës."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Lidhja e çiftimit ose ajo e qasjes në zona publike interneti është aktive"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Trokit për ta konfiguruar."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Lidhja e çiftimit është çaktivizuar"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Kontakto me administratorin për detaje"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Prapa"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Përpara"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Kapërce"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Kalo tek ekrani i ndarë"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ekrani i kyçjes"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Pamja e ekranit"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Aplikacioni <xliff:g id="APP_NAME">%1$s</xliff:g> në dritaren kërcyese."</string>
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 37410a7..e93c852 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -190,6 +190,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Апликација за администраторе на профилу за Work недостаје или је оштећена. Због тога су профил за Work и повезани подаци избрисани. Обратите се администратору за помоћ."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Профил за Work више није доступан на овом уређају"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Превише покушаја уноса лозинке"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Уређајем се управља"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Организација управља овим уређајем и може да надгледа мрежни саобраћај. Додирните за детаље."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Уређај ће бити обрисан"</string>
@@ -1136,10 +1138,8 @@
     <string name="loading" msgid="3138021523725055037">"Учитава се…"</string>
     <string name="capital_on" msgid="2770685323900821829">"ДА"</string>
     <string name="capital_off" msgid="7443704171014626777">"НЕ"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"означено је"</string>
+    <string name="not_checked" msgid="7972320087569023342">"није означено"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Довршавање радње помоћу"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Завршите радњу помоћу апликације %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Заврши радњу"</string>
@@ -1449,10 +1449,6 @@
     <string name="submit" msgid="862795280643405865">"Пошаљи"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Апликација за вожњу је покренута"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Додирните да бисте изашли из апликације за вожњу."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Активно повезивање са интернетом преко мобилног уређаја или хотспот"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Додирните да бисте подесили."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Привезивање је онемогућено"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Потражите детаље од администратора"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Назад"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Next"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Прескочи"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index a5b657a..cf0e0bb 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Administratörsappen för jobbprofilen saknas eller är skadad. Det innebär att jobbprofilen och all relaterad data har raderats. Kontakta administratören om du vill ha hjälp."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Jobbprofilen är inte längre tillgänglig på enheten"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"För många försök med lösenord"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Enheten hanteras"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Organisationen hanterar den här enheten och kan övervaka nätverkstrafiken. Tryck om du vill veta mer."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Enheten kommer att rensas"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Läser in …"</string>
     <string name="capital_on" msgid="2770685323900821829">"PÅ"</string>
     <string name="capital_off" msgid="7443704171014626777">"AV"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"markerad"</string>
+    <string name="not_checked" msgid="7972320087569023342">"inte markerad"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Slutför åtgärd genom att använda"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Slutför åtgärden med %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Slutför åtgärd"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Skicka"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Bilkörningsappen körs"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Tryck här om du vill avsluta bilkörningsappen."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Internetdelning eller surfzon aktiverad"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Tryck om du vill konfigurera."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Internetdelning har inaktiverats"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Kontakta administratören om du vill veta mer"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Tillbaka"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Nästa"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Hoppa över"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index d587e25..f8cd19c 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Programu ya msimamizi wa wasifu wa kazini imepotea au ina hitilafu. Kwa sababu hiyo, wasifu wako wa kazini na data husika imefutwa. Wasiliana na msimamizi wako kwa usaidizi."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Wasifu wako wa kazini haupatikani tena kwenye kifaa hiki"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Umejaribu kuweka nenosiri mara nyingi mno"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Kifaa kinadhibitiwa"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Shirika lako linadhibiti kifaa hiki na huenda likafuatilia shughuli kwenye mtandao. Gusa ili upate maelezo zaidi."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Data iliyomo kwenye kifaa chako itafutwa"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Inapakia…"</string>
     <string name="capital_on" msgid="2770685323900821829">"Washa"</string>
     <string name="capital_off" msgid="7443704171014626777">"ZIMA"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"imeteuliwa"</string>
+    <string name="not_checked" msgid="7972320087569023342">"haijateuliwa"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Kamilisha kitendo ukitumia"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Kamilisha kitendo ukitumia %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Kamilisha kitendo"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Wasilisha"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Umewasha programu ya kuendesha gari"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Gusa ili ufunge programu ya kuendesha gari."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Kushiriki au kusambaza intaneti kumewashwa"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Gusa ili uweke mipangilio."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Umezima kipengele cha kusambaza mtandao"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Wasiliana na msimamizi wako ili upate maelezo zaidi"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Nyuma"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Endelea"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Ruka"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Geuza Skrini Iliyogawanywa"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Skrini Iliyofungwa"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Picha ya skrini"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Programu ya <xliff:g id="APP_NAME">%1$s</xliff:g> katika dirisha Ibukizi."</string>
 </resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 90b8bc8..ac284d3 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"பணிக் கணக்கு நிர்வாகி ஆப்ஸ் இல்லை அல்லது அது சிதைந்துள்ளது. இதன் விளைவாக, உங்கள் பணிக் கணக்குமும் அதனுடன் தொடர்புடைய தரவும் நீக்கப்பட்டன. உதவிக்கு, நிர்வாகியைத் தொடர்புகொள்ளவும்."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"இந்தச் சாதனத்தில் இனி பணிக் கணக்கு கிடைக்காது"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"கடவுச்சொல்லை அதிக முறை தவறாக முயற்சித்துவிட்டீர்கள்"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"சாதனம் நிர்வகிக்கப்படுகிறது"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"உங்கள் நிறுவனம் இந்தச் சாதனத்தை நிர்வகிக்கும், அத்துடன் அது நெட்வொர்க் ட்ராஃபிக்கைக் கண்காணிக்கலாம். விவரங்களுக்கு, தட்டவும்."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"சாதனத் தரவு அழிக்கப்படும்"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"ஏற்றுகிறது..."</string>
     <string name="capital_on" msgid="2770685323900821829">"ஆன்"</string>
     <string name="capital_off" msgid="7443704171014626777">"ஆஃப்"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"இயக்கப்பட்டுள்ளது"</string>
+    <string name="not_checked" msgid="7972320087569023342">"முடக்கப்பட்டுள்ளது"</string>
     <string name="whichApplication" msgid="5432266899591255759">"இதைப் பயன்படுத்தி செயலை நிறைவுசெய்"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ஐப் பயன்படுத்தி செயலை முடிக்கவும்"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"செயலை முடி"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"சமர்ப்பி"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"\'வாகனம் ஓட்டும் பயன்முறை’ ஆனில் உள்ளது"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"வாகனம் ஓட்டும் பயன்முறையிலிருந்து வெளியேற, தட்டவும்."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"டெதெரிங்/ஹாட்ஸ்பாட் இயங்குகிறது"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"அமைக்க, தட்டவும்."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"இணைப்பு முறை முடக்கப்பட்டுள்ளது"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"விவரங்களுக்கு, உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்"</string>
     <string name="back_button_label" msgid="4078224038025043387">"முந்தையது"</string>
     <string name="next_button_label" msgid="6040209156399907780">"அடுத்து"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"தவிர்"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"திரைப் பிரிப்பை நிலைமாற்று"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"பூட்டுத் திரை"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ஸ்கிரீன்ஷாட்"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸில் உள்ள பாப் அப் சாளரம்."</string>
 </resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 63821aa..6641c41 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"కార్యాలయ ప్రొఫైల్ నిర్వాహక యాప్ లేదు లేదా పాడైంది. తత్ఫలితంగా, మీ కార్యాలయ ప్రొఫైల్ మరియు సంబంధిత డేటా తొలగించబడ్డాయి. సహాయం కోసం మీ నిర్వాహకులను సంప్రదించండి."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ఈ పరికరంలో మీ కార్యాలయ ప్రొఫైల్ ఇప్పుడు అందుబాటులో లేదు"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"చాలా ఎక్కువ పాస్‌వర్డ్ ప్రయత్నాలు చేసారు"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"పరికరం నిర్వహించబడింది"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"మీ సంస్థ ఈ పరికరాన్ని నిర్వహిస్తుంది మరియు నెట్‌వర్క్ ట్రాఫిక్‌ని పర్యవేక్షించవచ్చు. వివరాల కోసం నొక్కండి."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"మీ పరికరంలోని డేటా తొలగించబడుతుంది"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"లోడ్ చేస్తోంది…"</string>
     <string name="capital_on" msgid="2770685323900821829">"ఆన్‌లో ఉంది"</string>
     <string name="capital_off" msgid="7443704171014626777">"ఆఫ్‌"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"ఎంచుకోబడింది"</string>
+    <string name="not_checked" msgid="7972320087569023342">"ఎంచుకోలేదు"</string>
     <string name="whichApplication" msgid="5432266899591255759">"దీన్ని ఉపయోగించి చర్యను పూర్తి చేయండి"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$sను ఉపయోగించి చర్యను పూర్తి చేయి"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"చర్యను పూర్తి చేయి"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"సమర్పించు"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"డ్రైవింగ్ యాప్ అమలవుతోంది"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"డ్రైవింగ్ యాప్ నుండి నిష్క్రమించడం కోసం నొక్కండి."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"టీథర్ చేయబడినది లేదా హాట్‌స్పాట్ సక్రియంగా ఉండేది"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"సెటప్ చేయడానికి నొక్కండి."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"టెథెరింగ్ నిలిపివేయబడింది"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"వివరాల కోసం మీ నిర్వాహకులను సంప్రదించండి"</string>
     <string name="back_button_label" msgid="4078224038025043387">"వెనుకకు"</string>
     <string name="next_button_label" msgid="6040209156399907780">"తర్వాత"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"దాటవేయి"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"స్క్రీన్ విభజనను టోగుల్ చేయి"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"స్క్రీన్‌ను లాక్ చేయి"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"స్క్రీన్‌షాట్"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"పాప్-అప్ విండోలో <xliff:g id="APP_NAME">%1$s</xliff:g> యాప్ ఉంది."</string>
 </resources>
diff --git a/core/res/res/values-television/config.xml b/core/res/res/values-television/config.xml
index 655d4dd..3ecb1dd 100644
--- a/core/res/res/values-television/config.xml
+++ b/core/res/res/values-television/config.xml
@@ -42,8 +42,4 @@
 
     <!-- Allow SystemUI to show the shutdown dialog -->
     <bool name="config_showSysuiShutdown">true</bool>
-
-    <!-- The time in milliseconds of prolonged user inactivity after which device goes to sleep,
-         even if wakelocks are held. On TVs, this defaults to 4 hours. -->
-    <integer name="config_attentiveTimeout">14400000</integer>
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index d4646b9..bc4b79e 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"แอปผู้ดูแลระบบโปรไฟล์งานไม่มีอยู่หรือเสียหาย ระบบจึงทำการลบโปรไฟล์งานและข้อมูลที่เกี่ยวข้องของคุณออก โปรดติดต่อผู้ดูแลระบบเพื่อรับความช่วยเหลือ"</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"โปรไฟล์งานของคุณไม่สามารถใช้ในอุปกรณ์นี้อีกต่อไป"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"ลองป้อนรหัสผ่านหลายครั้งเกินไป"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"อุปกรณ์มีการจัดการ"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"องค์กรของคุณจัดการอุปกรณ์นี้และอาจตรวจสอบการจราจรของข้อมูลในเครือข่าย แตะเพื่อดูรายละเอียด"</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"ระบบจะลบข้อมูลในอุปกรณ์ของคุณ"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"กำลังโหลด..."</string>
     <string name="capital_on" msgid="2770685323900821829">"เปิด"</string>
     <string name="capital_off" msgid="7443704171014626777">"ปิด"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"เลือกไว้"</string>
+    <string name="not_checked" msgid="7972320087569023342">"ยังไม่เลือก"</string>
     <string name="whichApplication" msgid="5432266899591255759">"ทำงานให้เสร็จโดยใช้"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"ดำเนินการให้เสร็จสมบูรณ์โดยใช้ %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"ทำงานให้เสร็จสิ้น"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"ส่ง"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"แอปสำหรับการขับขี่ทำงานอยู่"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"แตะเพื่อออกจากแอปสำหรับการขับขี่"</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"การปล่อยสัญญาณหรือฮอตสปอตทำงานอยู่"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"แตะเพื่อตั้งค่า"</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"ปิดใช้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือแล้ว"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"ติดต่อผู้ดูแลระบบเพื่อขอรายละเอียด"</string>
     <string name="back_button_label" msgid="4078224038025043387">"กลับ"</string>
     <string name="next_button_label" msgid="6040209156399907780">"ถัดไป"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"ข้าม"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"เปิด/ปิดการแบ่งหน้าจอ"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"หน้าจอล็อก"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ภาพหน้าจอ"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"แอป <xliff:g id="APP_NAME">%1$s</xliff:g> ในหน้าต่างป๊อปอัป"</string>
 </resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 93ec517..b24e95a 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Nawawala o nasira ang admin app ng profile sa trabaho. Dahil dito, na-delete ang profile mo sa trabaho at nauugnay na data. Makipag-ugnayan sa iyong admin para sa tulong."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Hindi na available sa device na ito ang iyong profile sa trabaho"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Masyadong maraming pagsubok sa password"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Pinamamahalaan ang device"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Pinamamahalaan ng iyong organisasyon ang device na ito, at maaari nitong subaybayan ang trapiko sa network. I-tap para sa mga detalye."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Buburahin ang iyong device"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Naglo-load…"</string>
     <string name="capital_on" msgid="2770685323900821829">"I-ON"</string>
     <string name="capital_off" msgid="7443704171014626777">"I-OFF"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"nilagyan ng check"</string>
+    <string name="not_checked" msgid="7972320087569023342">"hindi nilagyan ng check"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Kumpletuhin ang pagkilos gamit ang"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Tapusin ang pagkilos gamit ang %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Gawin ang pagkilos"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Isumite"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Tumatakbo ang driving app"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Mag-tap para lumabas sa app sa pagmamaneho."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Pagsasama o aktibong hotspot"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"I-tap upang i-set up."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Naka-disable ang pag-tether"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Makipag-ugnayan sa iyong admin para sa mga detalye"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Bumalik"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Susunod"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Laktawan"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"I-toggle ang Split Screen"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"<xliff:g id="APP_NAME">%1$s</xliff:g> app sa Pop-up na window."</string>
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 1a4d532..326ace9 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"İş profili yönetici uygulaması eksik ya da bozuk. Bunun sonucunda iş profiliniz ve ilgili veriler silindi. Yardım almak için yöneticiniz ile iletişim kurun."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"İş profiliniz arık bu cihazda kullanılamıyor"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Çok fazla şifre denemesi yapıldı"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Cihaz yönetiliyor"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Kuruluşunuz bu cihazı yönetmekte olup ağ trafiğini izleyebilir. Ayrıntılar için dokunun."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Cihazınız silinecek"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Yükleniyor..."</string>
     <string name="capital_on" msgid="2770685323900821829">"AÇIK"</string>
     <string name="capital_off" msgid="7443704171014626777">"KAPALI"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"işaretli"</string>
+    <string name="not_checked" msgid="7972320087569023342">"işaretli değil"</string>
     <string name="whichApplication" msgid="5432266899591255759">"İşlemi şunu kullanarak tamamla"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"İşlemi %1$s kullanarak tamamla"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"İşlemi tamamla"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Gönder"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Sürüş uygulaması çalışıyor"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Sürüş uygulamasından çıkmak için dokunun."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Tethering veya hotspot etkin"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Ayarlamak için dokunun."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering devre dışı bırakıldı"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Ayrıntılı bilgi için yöneticinize başvurun"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Geri"</string>
     <string name="next_button_label" msgid="6040209156399907780">"İleri"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Atla"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Bölünmüş Ekranı aç/kapat"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Kilit Ekranı"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekran görüntüsü"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Pop-up pencerede <xliff:g id="APP_NAME">%1$s</xliff:g> uygulaması."</string>
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index b785e06..8007f9e 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -192,6 +192,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Додаток адміністратора в робочому профілі відсутній або пошкоджений. У результаті ваш робочий профіль і пов’язані з ним дані видалено. Зверніться до свого адміністратора по допомогу."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Робочий профіль більше не доступний на цьому пристрої"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Забагато спроб ввести пароль"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Пристрій контролюється"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Адміністратор вашої організації контролює цей пристрій і відстежує мережевий трафік. Торкніться, щоб дізнатися більше."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"З вашого пристрою буде стерто всі дані"</string>
@@ -1156,10 +1158,8 @@
     <string name="loading" msgid="3138021523725055037">"Завантаження..."</string>
     <string name="capital_on" msgid="2770685323900821829">"УВІМК"</string>
     <string name="capital_off" msgid="7443704171014626777">"ВИМК"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"вибрано"</string>
+    <string name="not_checked" msgid="7972320087569023342">"не вибрано"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Завершити дію за доп."</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Завершити дію за допомогою %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Завершити дію"</string>
@@ -1469,10 +1469,6 @@
     <string name="submit" msgid="862795280643405865">"Надіслати"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Працює додаток для автомобілів"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Торкніться, щоб вийти з додатка для автомобілів."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Прив\'язка чи точка дост. активна"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Торкніться, щоб налаштувати."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Використання телефона в режимі модема вимкнено"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Щоб дізнатися більше, зв’яжіться з адміністратором"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Назад"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Далі"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Пропустити"</string>
@@ -2072,6 +2068,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Розділити екран"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заблокувати екран"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Знімок екрана"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> у спливаючому вікні."</string>
 </resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index b54653e..312aed7d 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"دفتری پروفائل کی منتظم ایپ یا تو غائب ہے یا خراب ہے۔ اس کی وجہ سے، آپ کا دفتری پروفائل اور متعلقہ ڈیٹا حذف کر دیے گئے ہیں۔ مدد کیلئے اپنے منتظم سے رابطہ کریں۔"</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"آپ کا دفتری پروفائل اس آلہ پر مزید دستیاب نہیں ہے"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"پاس ورڈ کی بہت ساری کوششیں"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"آلہ زیر انتظام ہے"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"آپ کی تنظیم اس آلے کا نظم کرتی ہے اور وہ نیٹ ورک ٹریفک کی نگرانی کر سکتی ہے۔ تفاصیل کیلئے تھپتھپائیں۔"</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"آپ کا آلہ صاف کر دیا جائے گا"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"لوڈ ہو رہا ہے…"</string>
     <string name="capital_on" msgid="2770685323900821829">"آن"</string>
     <string name="capital_off" msgid="7443704171014626777">"آف"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"چیک کیا گیا"</string>
+    <string name="not_checked" msgid="7972320087569023342">"چیک نہیں کیا گیا"</string>
     <string name="whichApplication" msgid="5432266899591255759">"اس کا استعمال کرکے کارروائی مکمل کریں"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"‏%1$s کا استعمال کر کے کارروائی مکمل کریں"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"کارروائی مکمل کریں"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"جمع کرائیں"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ڈرائیونگ ایپ چل رہی ہے"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ڈرائیونگ ایپ سے باہر نکلنے کے لئے تھپتھپائيں۔"</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"ٹیدرنگ یا ہاٹ اسپاٹ فعال"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"سیٹ اپ کرنے کیلئے تھپتھپائیں۔"</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"ٹیدرنگ غیر فعال ہے"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"تفصیلات کے لئے اپنے منتظم سے رابطہ کریں"</string>
     <string name="back_button_label" msgid="4078224038025043387">"واپس جائیں"</string>
     <string name="next_button_label" msgid="6040209156399907780">"اگلا"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"نظر انداز کریں"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"اسپلٹ اسکرین ٹوگل کریں"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"مقفل اسکرین"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"اسکرین شاٹ"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"پوپ-اپ ونڈو میں <xliff:g id="APP_NAME">%1$s</xliff:g> ایپ۔"</string>
 </resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index c440e53..c7987d1 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Ishchi profilning administrator ilovasi yo‘q yoki buzilgan. Shuning uchun, ishchi profilingiz va unga aloqador ma’lumotlar o‘chirib tashlandi. Yordam olish uchun administratoringizga murojaat qiling."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Bu qurilmada endi ishchi profilingiz mavjud emas"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Parol ko‘p marta xato kiritildi"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Bu – boshqariladigan qurilma"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Tashkilotingiz bu qurilmani boshqaradi va tarmoq trafigini nazorat qilishi mumkin. Tafsilotlar uchun bosing."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Qurilmangizdagi ma’lumotlar o‘chirib tashlanadi"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Yuklanmoqda…"</string>
     <string name="capital_on" msgid="2770685323900821829">"I"</string>
     <string name="capital_off" msgid="7443704171014626777">"O"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"belgilandi"</string>
+    <string name="not_checked" msgid="7972320087569023342">"belgilanmadi"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Ilovani tanlang"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"“%1$s” bilan ochish"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Amalni bajarish"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Yuborish"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Avtomobil ilovasi ishlayapti"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Avtomobil ilovasidan chiqish uchun bosing"</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Modem rejimi yoniq"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Sozlash uchun bosing."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Modem rejimi faolsizlantirildi"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Tafsilotlari uchun administratoringizga murojaat qiling"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Orqaga"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Keyingisi"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Tashlab o‘tish"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index e362382..13c75f6 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Ứng dụng quản trị hồ sơ công việc bị thiếu hoặc hỏng. Do vậy, hồ sơ công việc của bạn và dữ liệu liên quan đã bị xóa. Hãy liên hệ với quản trị viên của bạn để được trợ giúp."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Hồ sơ công việc của bạn không có sẵn trên thiết bị này nữa"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Quá nhiều lần nhập mật khẩu"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Thiết bị được quản lý"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Tổ chức của bạn sẽ quản lý thiết bị này và có thể theo dõi lưu lượng truy cập mạng. Nhấn để biết chi tiết."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Thiết bị của bạn sẽ bị xóa"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Đang tải…"</string>
     <string name="capital_on" msgid="2770685323900821829">"BẬT"</string>
     <string name="capital_off" msgid="7443704171014626777">"TẮT"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"đã chọn"</string>
+    <string name="not_checked" msgid="7972320087569023342">"chưa chọn"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Hoàn tất tác vụ đang sử dụng"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Hoàn tất tác vụ bằng %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Hoàn thành tác vụ"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Gửi"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Ứng dụng lái xe đang chạy"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Nhấn để thoát khỏi ứng dụng lái xe."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Chức năng điểm truy cập Internet hoặc điểm phát sóng đang hoạt động"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Nhấn để thiết lập."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Đã tắt tính năng chia sẻ kết nối"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Hãy liên hệ với quản trị viên của bạn để biết chi tiết"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Quay lại"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Tiếp theo"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Bỏ qua"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Bật/tắt chế độ chia đôi màn hình"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Khóa màn hình"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Chụp ảnh màn hình"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Ứng dụng <xliff:g id="APP_NAME">%1$s</xliff:g> trong Cửa sổ bật lên."</string>
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 6df232a..1df2a40 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"工作资料管理应用缺失或损坏,因此系统已删除您的工作资料及相关数据。如需帮助,请与您的管理员联系。"</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"您的工作资料已不在此设备上"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"密码尝试次数过多"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"设备为受管理设备"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"贵单位会管理该设备,且可能会监控网络流量。点按即可了解详情。"</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"系统将清空您的设备"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"正在加载..."</string>
     <string name="capital_on" msgid="2770685323900821829">"开启"</string>
     <string name="capital_off" msgid="7443704171014626777">"关闭"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"已勾选"</string>
+    <string name="not_checked" msgid="7972320087569023342">"未勾选"</string>
     <string name="whichApplication" msgid="5432266899591255759">"选择要使用的应用:"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"使用%1$s完成操作"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"完成操作"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"提交"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"驾驶应用正在运行"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"点按即可退出驾驶应用。"</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"网络共享或热点已启用"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"点按即可进行设置。"</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"网络共享已停用"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"请与您的管理员联系以了解详情"</string>
     <string name="back_button_label" msgid="4078224038025043387">"上一步"</string>
     <string name="next_button_label" msgid="6040209156399907780">"下一步"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"跳过"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"开启/关闭分屏"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"锁定屏幕"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"屏幕截图"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"以弹出式窗口形式打开的<xliff:g id="APP_NAME">%1$s</xliff:g>应用。"</string>
 </resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 41dcbed..d4d1f7c 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"工作設定檔管理員應用程式已遺失或損毀。因此,您的工作設定檔和相關資料已刪除。請聯絡您的管理員以取得協助。"</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"您的工作設定檔無法再在此裝置上使用"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"密碼輸入錯誤的次數過多"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"裝置已受管理"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"您的機構會管理此裝置,並可能會監控網絡流量。輕按即可瞭解詳情。"</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"您的裝置將被清除"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"正在載入..."</string>
     <string name="capital_on" msgid="2770685323900821829">"開啟"</string>
     <string name="capital_off" msgid="7443704171014626777">"關"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"已勾選"</string>
+    <string name="not_checked" msgid="7972320087569023342">"未勾選"</string>
     <string name="whichApplication" msgid="5432266899591255759">"完成操作需使用"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"完成操作需使用 %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"完成操作"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"提交"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"駕駛應用程式執行中"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"輕按即可退出駕駛應用程式。"</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"已啟用網絡共享或熱點"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"輕按即可設定。"</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"網絡共享已停用"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"請聯絡您的管理員以瞭解詳情"</string>
     <string name="back_button_label" msgid="4078224038025043387">"返回"</string>
     <string name="next_button_label" msgid="6040209156399907780">"繼續"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"略過"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"切換分割螢幕"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"將畫面上鎖"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"螢幕截圖"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」應用程式在彈出式視窗中顯示。"</string>
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index d49df97..9997b68 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"工作資料夾管理員應用程式遺失或已毀損,因此系統刪除了你的工作資料夾和相關資料。如需協助,請與你的管理員聯絡。"</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"你的工作資料夾已不在這個裝置上"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"密碼輸入錯誤的次數過多"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"裝置受到管理"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"貴機構會管理這個裝置,且可能監控網路流量。輕觸即可瞭解詳情。"</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"你的裝置資料將遭到清除"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"載入中…"</string>
     <string name="capital_on" msgid="2770685323900821829">"開啟"</string>
     <string name="capital_off" msgid="7443704171014626777">"關閉"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"已勾選"</string>
+    <string name="not_checked" msgid="7972320087569023342">"未勾選"</string>
     <string name="whichApplication" msgid="5432266899591255759">"選擇要使用的應用程式"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"完成操作需使用 %1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"完成操作"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"提交"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"行車應用程式執行中"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"輕觸即可結束行車應用程式。"</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"網路共用或無線基地台已啟用"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"輕觸即可進行設定。"</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"數據連線已停用"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"詳情請洽你的管理員"</string>
     <string name="back_button_label" msgid="4078224038025043387">"返回"</string>
     <string name="next_button_label" msgid="6040209156399907780">"繼續"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"略過"</string>
@@ -2004,6 +2000,5 @@
     <string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"切換分割畫面模式"</string>
     <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"螢幕鎖定"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"擷取螢幕畫面"</string>
-    <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
-    <skip />
+    <string name="accessibility_freeform_caption" msgid="7873194416838321119">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」應用程式顯示在彈出式視窗中。"</string>
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index e99b592..5838a93 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -188,6 +188,8 @@
     <string name="work_profile_deleted_details" msgid="3773706828364418016">"Uhlelo lokusebenza lokulawula lephrofayela yomsebenzi kungenzeka alukho noma lonakele. Njengomphumela, iphrofayela yakho yomsebenzi nedatha ehlobene isusiwe. Xhumana nomlawuli wakho ukuze uthole usizo."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Iphrofayela yakho yomsebenzi ayisatholakali kule divayisi"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Imizamo yamaphasiwedi eminingi kakhulu"</string>
+    <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+    <skip />
     <string name="network_logging_notification_title" msgid="554983187553845004">"Idivayisi iphethwe"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Inhlangano yakho iphethe le divayisi futhi kungenzeka ingaqaphi ithrafikhi yenethiwekhi. Thephela imininingwane."</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Idivayisi yakho izosulwa"</string>
@@ -1116,10 +1118,8 @@
     <string name="loading" msgid="3138021523725055037">"Iyalayisha…"</string>
     <string name="capital_on" msgid="2770685323900821829">"VULIWE"</string>
     <string name="capital_off" msgid="7443704171014626777">"VALIWE"</string>
-    <!-- no translation found for checked (9179896827054513119) -->
-    <skip />
-    <!-- no translation found for not_checked (7972320087569023342) -->
-    <skip />
+    <string name="checked" msgid="9179896827054513119">"kuhloliwe"</string>
+    <string name="not_checked" msgid="7972320087569023342">"akuhloliwe"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Qedela isenzo usebenzisa"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Qedela isenzo usebenzisa i-%1$s"</string>
     <string name="whichApplicationLabel" msgid="7852182961472531728">"Qedela isenzo"</string>
@@ -1429,10 +1429,6 @@
     <string name="submit" msgid="862795280643405865">"Hambisa"</string>
     <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Uhlelo lokusebenza lokushayela luyasebenza"</string>
     <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Thepha ukuze uphume kuhlelo lokusebenza lokushayela."</string>
-    <string name="tethered_notification_title" msgid="2700523927485687353">"Ukusebenzisa njengemodemu noma i-hotspot ephathekayo kuvuliwe"</string>
-    <string name="tethered_notification_message" msgid="6228080755828019453">"Thepha ukuze usethe."</string>
-    <string name="disable_tether_notification_title" msgid="7158047514545848391">"Ukusebenzisa ifoni njengemodemu kukhutshaziwe"</string>
-    <string name="disable_tether_notification_message" msgid="98281313984014775">"Xhumana nomphathi wakho ukuze uthole imininingwane"</string>
     <string name="back_button_label" msgid="4078224038025043387">"Emuva"</string>
     <string name="next_button_label" msgid="6040209156399907780">"Okulandelayo"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Yeqa"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 234ffee..38d3e9c 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3750,6 +3750,14 @@
              </p>
          -->
         <attr name="canRequestFingerprintGestures" format="boolean" />
+
+        <!-- Animated image of the accessibility service purpose or behavior, to help users
+             understand how the service can help them.-->
+        <attr name="animatedImageDrawable" format="reference"/>
+        <!-- Html description of the accessibility service, to help users understand
+             how the service can help them.-->
+        <attr name="htmlDescription" format="string"/>
+
         <!-- Short description of the accessibility service purpose or behavior.-->
         <attr name="description" />
         <!-- Brief summary of the accessibility service purpose or behavior. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6741fea..bfbd959 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -508,7 +508,7 @@
         -->
     <string translatable="false" name="config_mobile_hotspot_provision_app_no_ui"></string>
     <!-- Sent in response to a provisioning check. The caller must hold the
-         permission android.permission.CONNECTIVITY_INTERNAL for Settings to
+         permission android.permission.TETHER_PRIVILEGED for Settings to
          receive this response.
 
          See config_mobile_hotspot_provision_response
@@ -2148,8 +2148,6 @@
     <integer name="config_dreamsBatteryLevelDrainCutoff">5</integer>
     <!-- Limit of how long the device can remain unlocked due to attention checking.  -->
     <integer name="config_attentionMaximumExtension">330000</integer> <!-- 5 minutes and 30 sec.-->
-    <!-- How long we should wait until we give up on receiving an attention API callback.  -->
-    <integer name="config_attentionApiTimeout">2000</integer> <!-- 2 seconds -->
 
     <!-- ComponentName of a dream to show whenever the system would otherwise have
          gone to sleep.  When the PowerManager is asked to go to sleep, it will instead
@@ -2363,9 +2361,11 @@
          1 (0b001) - enforce (only install system packages if they are whitelisted)
          2 (0b010) - log (log when a non-whitelisted package is run)
          4 (0b100) - treat any package not mentioned in the whitelist file as implicitly whitelisted
+         8 (0b1000) - ignore OTAs (don't install system packages during OTAs)
         Note: This list must be kept current with PACKAGE_WHITELIST_MODE_PROP in
         frameworks/base/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java -->
-    <integer name="config_userTypePackageWhitelistMode">5</integer> <!-- 0b101 -->
+    <integer name="config_userTypePackageWhitelistMode">13</integer> <!-- 0b1101 -->
+    <!-- TODO(b/143200798): Change to value 5, i.e. 0b0101, when b/143200798 is resolved. -->
 
     <!-- Whether UI for multi user should be shown -->
     <bool name="config_enableMultiUserUI">false</bool>
@@ -2851,9 +2851,6 @@
     <!-- String array containing numbers that shouldn't be logged. Country-specific. -->
     <string-array name="unloggable_phone_numbers" />
 
-    <!-- Flag specifying whether or not IMS will use the dynamic ImsResolver -->
-    <bool name="config_dynamic_bind_ims">false</bool>
-
     <!-- Cellular data service package name to bind to by default. If none is specified in an overlay, an
          empty string is passed in -->
     <string name="config_wwan_data_service_package" translatable="false">com.android.phone</string>
@@ -3523,8 +3520,9 @@
          protection level. Note, framework by default support multiple telephony apps, each package
          name is separated by comma.
          Example: "com.android.phone,com.android.stk,com.android.providers.telephony"
+         (Note: shell is included for testing purposes)
      -->
-    <string name="config_telephonyPackages" translatable="false">"com.android.phone,com.android.stk,com.android.providers.telephony,com.android.ons,com.android.cellbroadcastservice"</string>
+    <string name="config_telephonyPackages" translatable="false">"com.android.phone,com.android.stk,com.android.providers.telephony,com.android.ons,com.android.cellbroadcastservice,com.android.cellbroadcastreceiver,com.android.shell"</string>
 
     <!-- The component name for the default system attention service.
          This service must be trusted, as it can be activated without explicit consent of the user.
@@ -3695,6 +3693,8 @@
          instead of 'Emergency calls only' when SIM is unready. -->
     <string-array translatable="false" name="config_display_no_service_when_sim_unready">
         <item>"DE"</item>
+        <item>"GB"</item>
+        <item>"JP"</item>
     </string-array>
 
     <!-- Class names of device specific services inheriting com.android.server.SystemService. The
@@ -4179,4 +4179,10 @@
     <string-array name="config_integrityRuleProviderPackages" translatable="false">
         <!-- Add packages here -->
     </string-array>
+
+    <!-- When true, enables the whitelisted app to handle bug reports from power menu short press. -->
+    <bool name="config_bugReportHandlerEnabled">false</bool>
+
+    <!-- The package name for the default bug report handler app from power menu short press. This app must be whitelisted. -->
+    <string name="config_defaultBugReportHandlerApp" translatable="false"></string>
 </resources>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index b52f535..ddd9ba4 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -220,4 +220,7 @@
 
   <!-- Accessibility action identifier for {@link android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_TAKE_SCREENSHOT}. -->
   <item type="id" name="accessibilitySystemActionTakeScreenshot" />
+
+  <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PRESS_AND_HOLD}. -->
+  <item type="id" name="accessibilityActionPressAndHold" />
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index cde95aa..78c4efe 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3002,6 +3002,8 @@
       <public name="forceQueryable" />
       <!-- @hide @SystemApi -->
       <public name="resourcesMap" />
+      <public name="animatedImageDrawable"/>
+      <public name="htmlDescription"/>
     </public-group>
 
     <public-group type="drawable" first-id="0x010800b5">
@@ -3013,6 +3015,7 @@
     </public-group>
 
     <public-group type="id" first-id="0x0102004a">
+      <public name="accessibilityActionPressAndHold" />
     </public-group>
 
     <public-group type="string" first-id="0x01040025">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a0aa186..0f5da39 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1014,23 +1014,29 @@
     <string name="permdesc_readContacts" product="tablet">Allows the app to read
       data about your contacts stored on your tablet, including the frequency
       with which you\'ve called, emailed, or communicated in other ways with
-      specific individuals. This permission allows apps to save your contact
+      specific individuals. Apps will also have access to the accounts on your
+      tablet that have created contacts. This may include accounts created by
+      apps you have installed. This permission allows apps to save your contact
       data, and malicious apps may share contact data without your
       knowledge.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readContacts" product="tv">Allows the app to read
       data about your contacts stored on your Android TV device, including the frequency
       with which you\'ve called, emailed, or communicated in other ways with
-      specific individuals. This permission allows apps to save your contact
-      data, and malicious apps may share contact data without your
+      specific individuals. Apps will also have access to the accounts on your
+      Android TV device that have created contacts. This may include accounts
+      created by apps you have installed. This permission allows apps to save
+      your contact data, and malicious apps may share contact data without your
       knowledge.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readContacts" product="default">Allows the app to
       read data about your contacts stored on your phone, including the
       frequency with which you\'ve called, emailed, or communicated in other ways
-      with specific individuals. This permission allows apps to save your
-      contact data, and malicious apps may share contact data without your
-      knowledge.</string>
+      with specific individuals. Apps will also have access to the accounts
+      on your phone that have created contacts. This may include accounts
+      created by apps you have installed. This permission allows apps to
+      save your contact data, and malicious apps may share contact data
+      without your knowledge.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_writeContacts">modify your contacts</string>
@@ -3838,18 +3844,6 @@
     <string name="car_mode_disable_notification_title">Driving app is running</string>
     <string name="car_mode_disable_notification_message">Tap to exit driving app.</string>
 
-    <!-- Strings for tethered notification -->
-    <!-- Shown when the device is tethered -->
-    <string name="tethered_notification_title">Tethering or hotspot active</string>
-    <string name="tethered_notification_message">Tap to set up.</string>
-
-    <!-- Strings for tether disabling notification -->
-    <!-- This notification is shown when tethering has been disabled on a user's device.
-    The device is managed by the user's employer. Tethering can't be turned on unless the
-    IT administrator allows it. The noun "admin" is another reference for "IT administrator." -->
-    <string name="disable_tether_notification_title">Tethering is disabled</string>
-    <string name="disable_tether_notification_message">Contact your admin for details</string>
-
     <!--  Strings for possible PreferenceActivity Back/Next buttons -->
     <string name="back_button_label">Back</string>
     <string name="next_button_label">Next</string>
@@ -5083,11 +5077,14 @@
          data (for example, username, password and credit card info) [CHAR LIMIT=NONE] -->
     <string name="autofill_update_title_with_3types">Update these items in <b><xliff:g id="label" example="MyPass">%4$s</xliff:g></b>: <xliff:g id="type" example="Username">%1$s</xliff:g>, <xliff:g id="type" example="Password">%2$s</xliff:g>, and <xliff:g id="type" example="Credit Card">%3$s</xliff:g> ?</string>
 
-
     <!-- Label for the autofill save button [CHAR LIMIT=NONE] -->
     <string name="autofill_save_yes">Save</string>
     <!-- Label for the autofill cancel button [CHAR LIMIT=NONE] -->
     <string name="autofill_save_no">No thanks</string>
+    <!-- Label for the autofill cancel button, saying not to save the filled data at this moment. [CHAR LIMIT=NONE] -->
+    <string name="autofill_save_notnow">Not now</string>
+    <!-- Label for the autofill reject button, saying never to save the filled data. [CHAR LIMIT=NONE] -->
+    <string name="autofill_save_never">Never</string>
     <!-- Label for the autofill update button [CHAR LIMIT=NONE] -->
     <string name="autofill_update_yes">Update</string>
     <!-- Label for the autofill continue button [CHAR LIMIT=NONE] -->
@@ -5333,5 +5330,5 @@
     <string name="accessibility_system_action_screenshot_label">Screenshot</string>
 
     <!-- Accessibility description of caption view -->
-    <string name="accessibility_freeform_caption"><xliff:g id="app_name">%1$s</xliff:g> app in Pop-up window.</string>
+    <string name="accessibility_freeform_caption">Caption bar of <xliff:g id="app_name">%1$s</xliff:g>.</string>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e93c9bd..ee9287c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -294,7 +294,6 @@
   <java-symbol type="bool" name="config_hotswapCapable" />
   <java-symbol type="bool" name="config_mms_content_disposition_support" />
   <java-symbol type="string" name="config_ims_package" />
-  <java-symbol type="bool" name="config_dynamic_bind_ims" />
   <java-symbol type="string" name="config_wwan_network_service_package" />
   <java-symbol type="string" name="config_wlan_network_service_package" />
   <java-symbol type="string" name="config_wwan_network_service_class" />
@@ -1893,9 +1892,6 @@
   <java-symbol type="drawable" name="stat_sys_battery_charge" />
   <java-symbol type="drawable" name="stat_sys_battery_unknown" />
   <java-symbol type="drawable" name="stat_sys_data_usb" />
-  <java-symbol type="drawable" name="stat_sys_tether_bluetooth" />
-  <java-symbol type="drawable" name="stat_sys_tether_general" />
-  <java-symbol type="drawable" name="stat_sys_tether_usb" />
   <java-symbol type="drawable" name="stat_sys_throttled" />
   <java-symbol type="drawable" name="vpn_connected" />
   <java-symbol type="drawable" name="vpn_disconnected" />
@@ -2071,10 +2067,6 @@
   <java-symbol type="string" name="select_keyboard_layout_notification_message" />
   <java-symbol type="string" name="smv_application" />
   <java-symbol type="string" name="smv_process" />
-  <java-symbol type="string" name="tethered_notification_message" />
-  <java-symbol type="string" name="tethered_notification_title" />
-  <java-symbol type="string" name="disable_tether_notification_message" />
-  <java-symbol type="string" name="disable_tether_notification_title" />
   <java-symbol type="string" name="adb_debugging_notification_channel_tv" />
   <java-symbol type="string" name="usb_accessory_notification_title" />
   <java-symbol type="string" name="usb_mtp_notification_title" />
@@ -3248,6 +3240,8 @@
   <java-symbol type="string" name="autofill_save_title_with_3types" />
   <java-symbol type="string" name="autofill_save_yes" />
   <java-symbol type="string" name="autofill_save_no" />
+  <java-symbol type="string" name="autofill_save_notnow" />
+  <java-symbol type="string" name="autofill_save_never" />
   <java-symbol type="string" name="autofill_save_type_password" />
   <java-symbol type="string" name="autofill_save_type_address" />
   <java-symbol type="string" name="autofill_save_type_credit_card" />
@@ -3650,7 +3644,6 @@
 
   <!-- For Attention Service -->
   <java-symbol type="integer" name="config_attentionMaximumExtension" />
-  <java-symbol type="integer" name="config_attentionApiTimeout" />
 
   <java-symbol type="string" name="config_incidentReportApproverPackage" />
   <java-symbol type="array" name="config_restrictedImagesServices" />
@@ -3757,6 +3750,10 @@
 
   <java-symbol type="bool" name="config_showBuiltinWirelessChargingAnim" />
 
+  <!-- For bug report handler -->
+  <java-symbol type="bool" name="config_bugReportHandlerEnabled" />
+  <java-symbol type="string" name="config_defaultBugReportHandlerApp" />
+
   <java-symbol type="string" name="usb_device_resolve_prompt_warn" />
 
   <!-- For Accessibility system actions -->
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 0c52029..cef21db 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -1735,6 +1735,7 @@
         <item name="colorBackground">@color/background_device_default_light</item>
         <item name="colorBackgroundFloating">@color/background_device_default_light</item>
         <item name="layout_gravity">center</item>
+        <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
     </style>
 
     <style name="Theme.DeviceDefault.Notification" parent="@style/Theme.Material.Notification">
diff --git a/core/tests/ConnectivityManagerTest/AndroidManifest.xml b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
index a391e1f..796d7e8 100644
--- a/core/tests/ConnectivityManagerTest/AndroidManifest.xml
+++ b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
@@ -73,9 +73,9 @@
     <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
-    <!-- This permission is added for API call setAirplaneMode() in ConnectivityManager -->
-    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
     <uses-permission android:name="android.permission.TETHER_PRIVILEGED" />
+    <!-- This permission is added for API call setAirplaneMode() in ConnectivityManager -->
+    <uses-permission android:name="android.permission.NETWORK_SETTINGS" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.DEVICE_POWER" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
diff --git a/core/tests/ResourceLoaderTests/src/android/content/res/loader/test/ResourceLoaderChangesTest.kt b/core/tests/ResourceLoaderTests/src/android/content/res/loader/test/ResourceLoaderChangesTest.kt
index e01e254..0c3d34e 100644
--- a/core/tests/ResourceLoaderTests/src/android/content/res/loader/test/ResourceLoaderChangesTest.kt
+++ b/core/tests/ResourceLoaderTests/src/android/content/res/loader/test/ResourceLoaderChangesTest.kt
@@ -31,7 +31,6 @@
 import androidx.test.runner.lifecycle.Stage
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
-import org.junit.Assume
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
@@ -43,7 +42,6 @@
 import java.util.concurrent.FutureTask
 import java.util.concurrent.TimeUnit
 
-// @Ignore("UiAutomation is crashing with not connected, not sure why")
 @RunWith(Parameterized::class)
 class ResourceLoaderChangesTest : ResourceLoaderTestBase() {
 
@@ -75,7 +73,7 @@
     @Before
     @After
     fun disableOverlay() {
-//        enableOverlay(OVERLAY_PACKAGE, false)
+        enableOverlay(OVERLAY_PACKAGE, false)
     }
 
     @Test
@@ -156,25 +154,32 @@
 
     // All these tests assert for the exact same loaders/values, so extract that logic out
     private fun verifySameBeforeAndAfter(block: () -> Resources) {
-        // TODO(chiuwinson): atest doesn't work with @Ignore, UiAutomation not connected error
-        Assume.assumeFalse(true)
+        fun Resources.resource() = this.getString(android.R.string.cancel)
+        fun Resources.asset() = this.assets.open("Asset.txt").reader().readText()
 
-        val originalValue = resources.getString(android.R.string.cancel)
+        val originalResource = resources.resource()
+        val originalAsset = resources.asset()
 
-        val loader = "stringOne".openLoader()
-        addLoader(loader)
+        val loaderResource = "stringOne".openLoader()
+        val loaderAsset = "assetOne".openLoader(dataType = DataType.ASSET)
+        addLoader(loaderResource)
+        addLoader(loaderAsset)
 
         val oldLoaders = resources.loaders
-        val oldValue = resources.getString(android.R.string.cancel)
+        val oldResource = resources.resource()
+        val oldAsset = resources.asset()
 
-        assertThat(oldValue).isNotEqualTo(originalValue)
+        assertThat(oldResource).isNotEqualTo(originalResource)
+        assertThat(oldAsset).isNotEqualTo(originalAsset)
 
         val newResources = block()
 
         val newLoaders = newResources.loaders
-        val newValue = newResources.getString(android.R.string.cancel)
+        val newResource = newResources.resource()
+        val newAsset = newResources.asset()
 
-        assertThat(newValue).isEqualTo(oldValue)
+        assertThat(newResource).isEqualTo(oldResource)
+        assertThat(newAsset).isEqualTo(oldAsset)
         assertThat(newLoaders).isEqualTo(oldLoaders)
     }
 
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index a4c504b..c009f58 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -74,7 +74,6 @@
         ":FrameworksCoreTests_install_loc_internal",
         ":FrameworksCoreTests_install_loc_sdcard",
         ":FrameworksCoreTests_install_loc_unspecified",
-        ":FrameworksCoreTests_install_multi_package",
         ":FrameworksCoreTests_install_split_base",
         ":FrameworksCoreTests_install_split_feature_a",
         ":FrameworksCoreTests_install_use_perm_good",
diff --git a/core/tests/coretests/apks/install_multi_package/Android.bp b/core/tests/coretests/apks/install_multi_package/Android.bp
deleted file mode 100644
index 249242e..0000000
--- a/core/tests/coretests/apks/install_multi_package/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-android_test_helper_app {
-    name: "FrameworksCoreTests_install_multi_package",
-    defaults: ["FrameworksCoreTests_apks_defaults"],
-
-    srcs: ["**/*.java"],
-}
diff --git a/core/tests/coretests/apks/install_multi_package/AndroidManifest.xml b/core/tests/coretests/apks/install_multi_package/AndroidManifest.xml
deleted file mode 100644
index 5164cae..0000000
--- a/core/tests/coretests/apks/install_multi_package/AndroidManifest.xml
+++ /dev/null
@@ -1,104 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 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.frameworks.coretests.install_multi_package">
-
-<!--
-     This manifest is has child packages with components.
--->
-
-    <uses-feature
-        android:name="com.android.frameworks.coretests.nonexistent" />
-    <uses-configuration
-        android:reqFiveWayNav="false" />
-
-    <instrumentation
-        android:name="android.test.InstrumentationTestRunner"
-        android:targetPackage="com.android.frameworks.coretests"
-        android:label="Frameworks Core Tests" />
-
-    <permission
-        android:label="test permission"
-        android:name="test_permission"
-        android:protectionLevel="normal" />
-    <uses-permission android:name="android.permission.INTERNET" />
-
-<!--
-     NOTE: This declares a child package, application, then another child
-     package, to test potential bugs that are order-dependent. Also, each
-     one varies the order.
--->
-
-    <package package="com.android.frameworks.coretests.install_multi_package.first_child">
-        <uses-permission android:name="android.permission.NFC" />
-        <!-- NOTE: A declared permission is ignored since the tag is not whitelisted. -->
-        <permission
-            android:label="test permission"
-            android:name="first_child_permission"
-            android:protectionLevel="signature" />
-        <application
-            android:hasCode="true">
-            <activity
-                android:name="com.android.frameworks.coretests.FirstChildTestActivity">
-            </activity>
-            <provider
-                android:name="com.android.frameworks.coretests.FirstChildTestProvider"
-                android:authorities="com.android.frameworks.coretests.testprovider" />
-            <receiver
-                android:name="com.android.frameworks.coretests.FirstChildTestReceiver" />
-            <service
-                android:name="com.android.frameworks.coretests.FirstChildTestService" />
-        </application>
-    </package>
-
-    <application
-        android:hasCode="true">
-        <service
-            android:name="com.android.frameworks.coretests.TestService" />
-        <activity
-            android:name="com.android.frameworks.coretests.TestActivity">
-        </activity>
-        <provider
-            android:name="com.android.frameworks.coretests.TestProvider"
-            android:authorities="com.android.frameworks.coretests.testprovider" />
-        <receiver
-            android:name="com.android.frameworks.coretests.TestReceiver" />
-    </application>
-
-    <package package="com.android.frameworks.coretests.blah.second_child">
-        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-        <uses-permission-sdk-23 android:name="android.permission.READ_CONTACTS" />
-        <!-- NOTE: A declared permission is ignored since the tag is not whitelisted. -->
-        <permission
-            android:label="test permission"
-            android:name="second_child_permission"
-            android:protectionLevel="dangerous" />
-        <application
-            android:hasCode="true">
-            <receiver
-                android:name="com.android.frameworks.coretests.SecondChildTestReceiver" />
-            <service
-                android:name="com.android.frameworks.coretests.SecondChildTestService" />
-            <activity
-                android:name="com.android.frameworks.coretests.SecondChildTestActivity">
-            </activity>
-            <provider
-                android:name="com.android.frameworks.coretests.SecondChildTestProvider"
-                android:authorities="com.android.frameworks.coretests.testprovider" />
-        </application>
-    </package>
-</manifest>
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestActivity.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestActivity.java
deleted file mode 100644
index 57afcb0..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestActivity.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2011 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.frameworks.coretests;
-
-import android.app.Activity;
-
-public class FirstChildTestActivity extends Activity {
-
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestProvider.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestProvider.java
deleted file mode 100644
index 2816865..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestProvider.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 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.frameworks.coretests;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class FirstChildTestProvider extends ContentProvider {
-
-    @Override
-    public boolean onCreate() {
-        return false;
-    }
-
-    @Override
-    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
-            String sortOrder) {
-        return null;
-    }
-
-    @Override
-    public String getType(Uri uri) {
-        return null;
-    }
-
-    @Override
-    public Uri insert(Uri uri, ContentValues values) {
-        return null;
-    }
-
-    @Override
-    public int delete(Uri uri, String selection, String[] selectionArgs) {
-        return 0;
-    }
-
-    @Override
-    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
-        return 0;
-    }
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestReceiver.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestReceiver.java
deleted file mode 100644
index ffe84b7..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestReceiver.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 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.frameworks.coretests;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class FirstChildTestReceiver extends ContentProvider {
-
-    @Override
-    public boolean onCreate() {
-        return false;
-    }
-
-    @Override
-    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
-            String sortOrder) {
-        return null;
-    }
-
-    @Override
-    public String getType(Uri uri) {
-        return null;
-    }
-
-    @Override
-    public Uri insert(Uri uri, ContentValues values) {
-        return null;
-    }
-
-    @Override
-    public int delete(Uri uri, String selection, String[] selectionArgs) {
-        return 0;
-    }
-
-    @Override
-    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
-        return 0;
-    }
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestService.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestService.java
deleted file mode 100644
index faa6e9c..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestService.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2011 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.frameworks.coretests;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
-
-public class FirstChildTestService extends Service {
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        return null;
-    }
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestActivity.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestActivity.java
deleted file mode 100644
index e89f264..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestActivity.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2011 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.frameworks.coretests;
-
-import android.app.Activity;
-
-public class SecondChildTestActivity extends Activity {
-
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestProvider.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestProvider.java
deleted file mode 100644
index 2bd40a5..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestProvider.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 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.frameworks.coretests;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class SecondChildTestProvider extends ContentProvider {
-
-    @Override
-    public boolean onCreate() {
-        return false;
-    }
-
-    @Override
-    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
-            String sortOrder) {
-        return null;
-    }
-
-    @Override
-    public String getType(Uri uri) {
-        return null;
-    }
-
-    @Override
-    public Uri insert(Uri uri, ContentValues values) {
-        return null;
-    }
-
-    @Override
-    public int delete(Uri uri, String selection, String[] selectionArgs) {
-        return 0;
-    }
-
-    @Override
-    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
-        return 0;
-    }
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestReceiver.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestReceiver.java
deleted file mode 100644
index a6c4ddc..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestReceiver.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 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.frameworks.coretests;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class SecondChildTestReceiver extends ContentProvider {
-
-    @Override
-    public boolean onCreate() {
-        return false;
-    }
-
-    @Override
-    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
-            String sortOrder) {
-        return null;
-    }
-
-    @Override
-    public String getType(Uri uri) {
-        return null;
-    }
-
-    @Override
-    public Uri insert(Uri uri, ContentValues values) {
-        return null;
-    }
-
-    @Override
-    public int delete(Uri uri, String selection, String[] selectionArgs) {
-        return 0;
-    }
-
-    @Override
-    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
-        return 0;
-    }
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestService.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestService.java
deleted file mode 100644
index 1e721aa..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestService.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2011 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.frameworks.coretests;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
-
-public class SecondChildTestService extends Service {
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        return null;
-    }
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestActivity.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestActivity.java
deleted file mode 100644
index 10d0551..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestActivity.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2011 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.frameworks.coretests;
-
-import android.app.Activity;
-
-public class TestActivity extends Activity {
-
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestProvider.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestProvider.java
deleted file mode 100644
index 59f9f10..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestProvider.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 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.frameworks.coretests;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class TestProvider extends ContentProvider {
-
-    @Override
-    public boolean onCreate() {
-        return false;
-    }
-
-    @Override
-    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
-            String sortOrder) {
-        return null;
-    }
-
-    @Override
-    public String getType(Uri uri) {
-        return null;
-    }
-
-    @Override
-    public Uri insert(Uri uri, ContentValues values) {
-        return null;
-    }
-
-    @Override
-    public int delete(Uri uri, String selection, String[] selectionArgs) {
-        return 0;
-    }
-
-    @Override
-    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
-        return 0;
-    }
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestReceiver.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestReceiver.java
deleted file mode 100644
index 21f6263..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestReceiver.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 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.frameworks.coretests;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-public class TestReceiver extends ContentProvider {
-
-    @Override
-    public boolean onCreate() {
-        return false;
-    }
-
-    @Override
-    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
-            String sortOrder) {
-        return null;
-    }
-
-    @Override
-    public String getType(Uri uri) {
-        return null;
-    }
-
-    @Override
-    public Uri insert(Uri uri, ContentValues values) {
-        return null;
-    }
-
-    @Override
-    public int delete(Uri uri, String selection, String[] selectionArgs) {
-        return 0;
-    }
-
-    @Override
-    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
-        return 0;
-    }
-}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestService.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestService.java
deleted file mode 100644
index b330e75..0000000
--- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestService.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2011 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.frameworks.coretests;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
-
-public class TestService extends Service {
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        return null;
-    }
-}
diff --git a/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java
new file mode 100644
index 0000000..de6f8f7
--- /dev/null
+++ b/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.timedetector;
+
+import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
+import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.util.TimestampedValue;
+
+import org.junit.Test;
+
+public class ManualTimeSuggestionTest {
+
+    private static final TimestampedValue<Long> ARBITRARY_TIME =
+            new TimestampedValue<>(1111L, 2222L);
+
+    @Test
+    public void testEquals() {
+        ManualTimeSuggestion one = new ManualTimeSuggestion(ARBITRARY_TIME);
+        assertEquals(one, one);
+
+        ManualTimeSuggestion two = new ManualTimeSuggestion(ARBITRARY_TIME);
+        assertEquals(one, two);
+        assertEquals(two, one);
+
+        TimestampedValue<Long> differentTime = new TimestampedValue<>(
+                ARBITRARY_TIME.getReferenceTimeMillis() + 1,
+                ARBITRARY_TIME.getValue());
+        ManualTimeSuggestion three = new ManualTimeSuggestion(differentTime);
+        assertNotEquals(one, three);
+        assertNotEquals(three, one);
+
+        // DebugInfo must not be considered in equals().
+        one.addDebugInfo("Debug info 1");
+        two.addDebugInfo("Debug info 2");
+        assertEquals(one, two);
+    }
+
+    @Test
+    public void testParcelable() {
+        ManualTimeSuggestion suggestion = new ManualTimeSuggestion(ARBITRARY_TIME);
+        assertRoundTripParcelable(suggestion);
+
+        // DebugInfo should also be stored (but is not checked by equals()
+        suggestion.addDebugInfo("This is debug info");
+        ManualTimeSuggestion rtSuggestion = roundTripParcelable(suggestion);
+        assertEquals(suggestion.getDebugInfo(), rtSuggestion.getDebugInfo());
+    }
+}
diff --git a/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
index 1b5ad88..bee270e 100644
--- a/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
@@ -16,11 +16,12 @@
 
 package android.app.timedetector;
 
+import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
+import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 
-import android.os.Parcel;
-import android.os.Parcelable;
 import android.util.TimestampedValue;
 
 import org.junit.Test;
@@ -30,46 +31,67 @@
 
     @Test
     public void testEquals() {
-        PhoneTimeSuggestion one =
-                new PhoneTimeSuggestion(PHONE_ID, new TimestampedValue<>(1111L, 2222L));
-        assertEquals(one, one);
+        PhoneTimeSuggestion.Builder builder1 = new PhoneTimeSuggestion.Builder(PHONE_ID);
+        {
+            PhoneTimeSuggestion one = builder1.build();
+            assertEquals(one, one);
+        }
 
-        PhoneTimeSuggestion two =
-                new PhoneTimeSuggestion(PHONE_ID, new TimestampedValue<>(1111L, 2222L));
-        assertEquals(one, two);
-        assertEquals(two, one);
+        PhoneTimeSuggestion.Builder builder2 = new PhoneTimeSuggestion.Builder(PHONE_ID);
+        {
+            PhoneTimeSuggestion one = builder1.build();
+            PhoneTimeSuggestion two = builder2.build();
+            assertEquals(one, two);
+            assertEquals(two, one);
+        }
 
-        PhoneTimeSuggestion three =
-                new PhoneTimeSuggestion(PHONE_ID + 1, new TimestampedValue<>(1111L, 2222L));
-        assertNotEquals(one, three);
-        assertNotEquals(three, one);
+        builder1.setUtcTime(new TimestampedValue<>(1111L, 2222L));
+        {
+            PhoneTimeSuggestion one = builder1.build();
+            assertEquals(one, one);
+        }
+
+        builder2.setUtcTime(new TimestampedValue<>(1111L, 2222L));
+        {
+            PhoneTimeSuggestion one = builder1.build();
+            PhoneTimeSuggestion two = builder2.build();
+            assertEquals(one, two);
+            assertEquals(two, one);
+        }
+
+        PhoneTimeSuggestion.Builder builder3 = new PhoneTimeSuggestion.Builder(PHONE_ID + 1);
+        builder3.setUtcTime(new TimestampedValue<>(1111L, 2222L));
+        {
+            PhoneTimeSuggestion one = builder1.build();
+            PhoneTimeSuggestion three = builder3.build();
+            assertNotEquals(one, three);
+            assertNotEquals(three, one);
+        }
 
         // DebugInfo must not be considered in equals().
-        one.addDebugInfo("Debug info 1");
-        two.addDebugInfo("Debug info 2");
-        assertEquals(one, two);
+        builder1.addDebugInfo("Debug info 1");
+        builder2.addDebugInfo("Debug info 2");
+        {
+            PhoneTimeSuggestion one = builder1.build();
+            PhoneTimeSuggestion two = builder2.build();
+            assertEquals(one, two);
+        }
     }
 
     @Test
     public void testParcelable() {
-        PhoneTimeSuggestion one =
-                new PhoneTimeSuggestion(PHONE_ID, new TimestampedValue<>(1111L, 2222L));
-        assertEquals(one, roundTripParcelable(one));
+        PhoneTimeSuggestion.Builder builder = new PhoneTimeSuggestion.Builder(PHONE_ID);
+        assertRoundTripParcelable(builder.build());
+
+        builder.setUtcTime(new TimestampedValue<>(1111L, 2222L));
+        assertRoundTripParcelable(builder.build());
 
         // DebugInfo should also be stored (but is not checked by equals()
-        one.addDebugInfo("This is debug info");
-        PhoneTimeSuggestion two = roundTripParcelable(one);
-        assertEquals(one.getDebugInfo(), two.getDebugInfo());
-    }
-
-    @SuppressWarnings("unchecked")
-    private static <T extends Parcelable> T roundTripParcelable(T one) {
-        Parcel parcel = Parcel.obtain();
-        parcel.writeTypedObject(one, 0);
-        parcel.setDataPosition(0);
-
-        T toReturn = (T) parcel.readTypedObject(PhoneTimeSuggestion.CREATOR);
-        parcel.recycle();
-        return toReturn;
+        {
+            PhoneTimeSuggestion suggestion1 = builder.build();
+            builder.addDebugInfo("This is debug info");
+            PhoneTimeSuggestion rtSuggestion1 = roundTripParcelable(suggestion1);
+            assertEquals(suggestion1.getDebugInfo(), rtSuggestion1.getDebugInfo());
+        }
     }
 }
diff --git a/core/tests/coretests/src/android/app/timezonedetector/ManualTimeZoneSuggestionTest.java b/core/tests/coretests/src/android/app/timezonedetector/ManualTimeZoneSuggestionTest.java
new file mode 100644
index 0000000..02ed0ed
--- /dev/null
+++ b/core/tests/coretests/src/android/app/timezonedetector/ManualTimeZoneSuggestionTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.timezonedetector;
+
+import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
+import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import org.junit.Test;
+
+public class ManualTimeZoneSuggestionTest {
+
+    private static final String ARBITRARY_ZONE_ID1 = "Europe/London";
+    private static final String ARBITRARY_ZONE_ID2 = "Europe/Paris";
+
+    @Test
+    public void testEquals() {
+        ManualTimeZoneSuggestion one = new ManualTimeZoneSuggestion(ARBITRARY_ZONE_ID1);
+        assertEquals(one, one);
+
+        ManualTimeZoneSuggestion two = new ManualTimeZoneSuggestion(ARBITRARY_ZONE_ID1);
+        assertEquals(one, two);
+        assertEquals(two, one);
+
+        ManualTimeZoneSuggestion three = new ManualTimeZoneSuggestion(ARBITRARY_ZONE_ID2);
+        assertNotEquals(one, three);
+        assertNotEquals(three, one);
+
+        // DebugInfo must not be considered in equals().
+        one.addDebugInfo("Debug info 1");
+        two.addDebugInfo("Debug info 2");
+        assertEquals(one, two);
+    }
+
+    @Test
+    public void testParcelable() {
+        ManualTimeZoneSuggestion suggestion = new ManualTimeZoneSuggestion(ARBITRARY_ZONE_ID1);
+        assertRoundTripParcelable(suggestion);
+
+        // DebugInfo should also be stored (but is not checked by equals()
+        suggestion.addDebugInfo("This is debug info");
+        ManualTimeZoneSuggestion rtSuggestion = roundTripParcelable(suggestion);
+        assertEquals(suggestion.getDebugInfo(), rtSuggestion.getDebugInfo());
+    }
+}
diff --git a/core/tests/coretests/src/android/app/timezonedetector/ParcelableTestSupport.java b/core/tests/coretests/src/android/app/timezonedetector/ParcelableTestSupport.java
new file mode 100644
index 0000000..0073d86
--- /dev/null
+++ b/core/tests/coretests/src/android/app/timezonedetector/ParcelableTestSupport.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.timezonedetector;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.reflect.Field;
+
+/** Utility methods related to {@link Parcelable} objects used in several tests. */
+public final class ParcelableTestSupport {
+
+    private ParcelableTestSupport() {}
+
+    /** Returns the result of parceling and unparceling the argument. */
+    @SuppressWarnings("unchecked")
+    public static <T extends Parcelable> T roundTripParcelable(T parcelable) {
+        Parcel parcel = Parcel.obtain();
+        parcel.writeTypedObject(parcelable, 0);
+        parcel.setDataPosition(0);
+
+        Parcelable.Creator<T> creator;
+        try {
+            Field creatorField = parcelable.getClass().getField("CREATOR");
+            creator = (Parcelable.Creator<T>) creatorField.get(null);
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+            throw new AssertionError(e);
+        }
+        T toReturn = parcel.readTypedObject(creator);
+        parcel.recycle();
+        return toReturn;
+    }
+
+    public static <T extends Parcelable> void assertRoundTripParcelable(T instance) {
+        assertEquals(instance, roundTripParcelable(instance));
+    }
+}
diff --git a/core/tests/coretests/src/android/app/timezonedetector/PhoneTimeZoneSuggestionTest.java b/core/tests/coretests/src/android/app/timezonedetector/PhoneTimeZoneSuggestionTest.java
new file mode 100644
index 0000000..0108a0b
--- /dev/null
+++ b/core/tests/coretests/src/android/app/timezonedetector/PhoneTimeZoneSuggestionTest.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.timezonedetector;
+
+import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
+import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class PhoneTimeZoneSuggestionTest {
+    private static final int PHONE_ID = 99999;
+
+    @Test
+    public void testEquals() {
+        PhoneTimeZoneSuggestion.Builder builder1 = new PhoneTimeZoneSuggestion.Builder(PHONE_ID);
+        {
+            PhoneTimeZoneSuggestion one = builder1.build();
+            assertEquals(one, one);
+        }
+
+        PhoneTimeZoneSuggestion.Builder builder2 = new PhoneTimeZoneSuggestion.Builder(PHONE_ID);
+        {
+            PhoneTimeZoneSuggestion one = builder1.build();
+            PhoneTimeZoneSuggestion two = builder2.build();
+            assertEquals(one, two);
+            assertEquals(two, one);
+        }
+
+        PhoneTimeZoneSuggestion.Builder builder3 =
+                new PhoneTimeZoneSuggestion.Builder(PHONE_ID + 1);
+        {
+            PhoneTimeZoneSuggestion one = builder1.build();
+            PhoneTimeZoneSuggestion three = builder3.build();
+            assertNotEquals(one, three);
+            assertNotEquals(three, one);
+        }
+
+        builder1.setZoneId("Europe/London");
+        builder1.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY);
+        builder1.setQuality(PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
+        {
+            PhoneTimeZoneSuggestion one = builder1.build();
+            PhoneTimeZoneSuggestion two = builder2.build();
+            assertNotEquals(one, two);
+        }
+
+        builder2.setZoneId("Europe/Paris");
+        builder2.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY);
+        builder2.setQuality(PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
+        {
+            PhoneTimeZoneSuggestion one = builder1.build();
+            PhoneTimeZoneSuggestion two = builder2.build();
+            assertNotEquals(one, two);
+        }
+
+        builder1.setZoneId("Europe/Paris");
+        {
+            PhoneTimeZoneSuggestion one = builder1.build();
+            PhoneTimeZoneSuggestion two = builder2.build();
+            assertEquals(one, two);
+        }
+
+        builder1.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID);
+        builder2.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY);
+        {
+            PhoneTimeZoneSuggestion one = builder1.build();
+            PhoneTimeZoneSuggestion two = builder2.build();
+            assertNotEquals(one, two);
+        }
+
+        builder1.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY);
+        {
+            PhoneTimeZoneSuggestion one = builder1.build();
+            PhoneTimeZoneSuggestion two = builder2.build();
+            assertEquals(one, two);
+        }
+
+        builder1.setQuality(PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
+        builder2.setQuality(PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS);
+        {
+            PhoneTimeZoneSuggestion one = builder1.build();
+            PhoneTimeZoneSuggestion two = builder2.build();
+            assertNotEquals(one, two);
+        }
+
+        builder1.setQuality(PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS);
+        {
+            PhoneTimeZoneSuggestion one = builder1.build();
+            PhoneTimeZoneSuggestion two = builder2.build();
+            assertEquals(one, two);
+        }
+
+        // DebugInfo must not be considered in equals().
+        {
+            PhoneTimeZoneSuggestion one = builder1.build();
+            PhoneTimeZoneSuggestion two = builder2.build();
+            one.addDebugInfo("Debug info 1");
+            two.addDebugInfo("Debug info 2");
+            assertEquals(one, two);
+        }
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void testBuilderValidates_emptyZone_badMatchType() {
+        PhoneTimeZoneSuggestion.Builder builder = new PhoneTimeZoneSuggestion.Builder(PHONE_ID);
+        // No zone ID, so match type should be left unset.
+        builder.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET);
+        builder.build();
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void testBuilderValidates_zoneSet_badMatchType() {
+        PhoneTimeZoneSuggestion.Builder builder = new PhoneTimeZoneSuggestion.Builder(PHONE_ID);
+        builder.setZoneId("Europe/London");
+        builder.setQuality(PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
+        builder.build();
+    }
+
+    @Test
+    public void testParcelable() {
+        PhoneTimeZoneSuggestion.Builder builder = new PhoneTimeZoneSuggestion.Builder(PHONE_ID);
+        assertRoundTripParcelable(builder.build());
+
+        builder.setZoneId("Europe/London");
+        builder.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID);
+        builder.setQuality(PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
+        PhoneTimeZoneSuggestion suggestion1 = builder.build();
+        assertRoundTripParcelable(suggestion1);
+
+        // DebugInfo should also be stored (but is not checked by equals()
+        String debugString = "This is debug info";
+        suggestion1.addDebugInfo(debugString);
+        PhoneTimeZoneSuggestion suggestion1_2 = roundTripParcelable(suggestion1);
+        assertEquals(suggestion1, suggestion1_2);
+        assertTrue(suggestion1_2.getDebugInfo().contains(debugString));
+    }
+}
diff --git a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
deleted file mode 100644
index cc48239..0000000
--- a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
+++ /dev/null
@@ -1,136 +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 android.content.pm;
-
-import static android.content.pm.PackageBuilder.builder;
-import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_BASE;
-import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER;
-
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Test for {@link AndroidHidlUpdater}
- */
-@SmallTest
-@RunWith(JUnit4.class)
-public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest {
-
-    private static final String OTHER_LIBRARY = "other.library";
-
-    @Test
-    public void targeted_at_P() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.P);
-
-        // no change, not system
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void targeted_at_P_system() {
-        PackageBuilder before = builder().asSystemApp()
-                .targetSdkVersion(Build.VERSION_CODES.P);
-
-        // Should add both HIDL libraries
-        PackageBuilder after = builder().asSystemApp()
-                .targetSdkVersion(Build.VERSION_CODES.P)
-                .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void targeted_at_P_not_empty_usesLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.P)
-                .requiredLibraries(OTHER_LIBRARY);
-
-        // no change, not system
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void targeted_at_P_not_empty_usesLibraries_system() {
-        PackageBuilder before = builder().asSystemApp()
-                .targetSdkVersion(Build.VERSION_CODES.P)
-                .requiredLibraries(OTHER_LIBRARY);
-
-        // The hidl jars should be added at the start of the list because it
-        // is not on the bootclasspath and the package targets pre-P.
-        PackageBuilder after = builder().asSystemApp()
-                .targetSdkVersion(Build.VERSION_CODES.P)
-                .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE, OTHER_LIBRARY);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void targeted_at_P_in_usesLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.P)
-                .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE);
-
-        PackageBuilder after = builder()
-                .targetSdkVersion(Build.VERSION_CODES.P);
-
-        // Libraries are removed because they are not available for non-system apps
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void targeted_at_P_in_usesLibraries_system() {
-        PackageBuilder before = builder().asSystemApp()
-                .targetSdkVersion(Build.VERSION_CODES.P)
-                .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE);
-
-        // No change is required because the package explicitly requests the HIDL libraries
-        // and is targeted at the current version so does not need backwards compatibility.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void in_usesLibraries() {
-        PackageBuilder before = builder().requiredLibraries(ANDROID_HIDL_BASE);
-
-        // Dependency is removed, it is not available.
-        PackageBuilder after = builder();
-
-        // Libraries are removed because they are not available for apps targetting Q+
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void in_usesOptionalLibraries() {
-        PackageBuilder before = builder().optionalLibraries(ANDROID_HIDL_BASE);
-
-        // Dependency is removed, it is not available.
-        PackageBuilder after = builder();
-
-        // Libraries are removed because they are not available for apps targetting Q+
-        checkBackwardsCompatibility(before, after);
-    }
-
-    private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
-        checkBackwardsCompatibility(before, after, AndroidHidlUpdater::new);
-    }
-}
diff --git a/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java
deleted file mode 100644
index 03108ce..0000000
--- a/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java
+++ /dev/null
@@ -1,110 +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 android.content.pm;
-
-import static android.content.pm.PackageBuilder.builder;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE;
-
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Test for {@link AndroidTestBaseUpdater}
- */
-@SmallTest
-@RunWith(OptionalClassRunner.class)
-@OptionalClassRunner.OptionalClass("android.content.pm.AndroidTestBaseUpdater")
-public class AndroidTestBaseUpdaterTest extends PackageSharedLibraryUpdaterTest {
-
-    private static final String OTHER_LIBRARY = "other.library";
-
-    @Test
-    public void targeted_at_Q() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.Q);
-
-        // Should add org.apache.http.legacy.
-        PackageBuilder after = builder()
-                .targetSdkVersion(Build.VERSION_CODES.Q)
-                .requiredLibraries(ANDROID_TEST_BASE);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void targeted_at_Q_not_empty_usesLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.Q)
-                .requiredLibraries(OTHER_LIBRARY);
-
-        // The org.apache.http.legacy jar should be added at the start of the list because it
-        // is not on the bootclasspath and the package targets pre-Q.
-        PackageBuilder after = builder()
-                .targetSdkVersion(Build.VERSION_CODES.Q)
-                .requiredLibraries(ANDROID_TEST_BASE, OTHER_LIBRARY);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void targeted_at_Q_in_usesLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.Q)
-                .requiredLibraries(ANDROID_TEST_BASE);
-
-        // No change is required because although org.apache.http.legacy has been removed from
-        // the bootclasspath the package explicitly requests it.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void targeted_at_Q_in_usesOptionalLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.Q)
-                .optionalLibraries(ANDROID_TEST_BASE);
-
-        // No change is required because although org.apache.http.legacy has been removed from
-        // the bootclasspath the package explicitly requests it.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void in_usesLibraries() {
-        PackageBuilder before = builder().requiredLibraries(ANDROID_TEST_BASE);
-
-        // No change is required because the package explicitly requests org.apache.http.legacy
-        // and is targeted at the current version so does not need backwards compatibility.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void in_usesOptionalLibraries() {
-        PackageBuilder before = builder().optionalLibraries(ANDROID_TEST_BASE);
-
-        // No change is required because the package explicitly requests org.apache.http.legacy
-        // and is targeted at the current version so does not need backwards compatibility.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
-        checkBackwardsCompatibility(before, after, AndroidTestBaseUpdater::new);
-    }
-}
diff --git a/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java
deleted file mode 100644
index 7f817d6..0000000
--- a/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java
+++ /dev/null
@@ -1,64 +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 android.content.pm;
-
-import static android.content.pm.PackageBuilder.builder;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_MOCK;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER;
-
-import android.content.pm.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Test for {@link AndroidTestRunnerSplitUpdater}
- */
-@SmallTest
-@RunWith(JUnit4.class)
-public class AndroidTestRunnerSplitUpdaterTest extends PackageSharedLibraryUpdaterTest {
-
-    @Test
-    public void android_test_runner_in_usesOptionalLibraries() {
-        PackageBuilder before = builder().optionalLibraries(ANDROID_TEST_RUNNER);
-
-        PackageBuilder after = builder()
-                .optionalLibraries(ANDROID_TEST_MOCK, ANDROID_TEST_RUNNER);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void android_test_runner_in_usesLibraries_android_test_mock_in_usesOptionalLibraries() {
-        PackageBuilder before = builder()
-                .requiredLibraries(ANDROID_TEST_RUNNER)
-                .optionalLibraries(ANDROID_TEST_MOCK);
-
-        PackageBuilder after = builder()
-                .requiredLibraries(ANDROID_TEST_RUNNER)
-                .optionalLibraries(ANDROID_TEST_MOCK);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
-        checkBackwardsCompatibility(before, after, AndroidTestRunnerSplitUpdater::new);
-    }
-}
diff --git a/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java b/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java
deleted file mode 100644
index 834a0bb..0000000
--- a/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java
+++ /dev/null
@@ -1,110 +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 android.content.pm;
-
-import static android.content.pm.PackageBuilder.builder;
-import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
-
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Test for {@link OrgApacheHttpLegacyUpdater}
- */
-@SmallTest
-@RunWith(OptionalClassRunner.class)
-@OptionalClassRunner.OptionalClass("android.content.pm.OrgApacheHttpLegacyUpdater")
-public class OrgApacheHttpLegacyUpdaterTest extends PackageSharedLibraryUpdaterTest {
-
-    private static final String OTHER_LIBRARY = "other.library";
-
-    @Test
-    public void targeted_at_O() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O);
-
-        // Should add org.apache.http.legacy.
-        PackageBuilder after = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .requiredLibraries(ORG_APACHE_HTTP_LEGACY);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void targeted_at_O_not_empty_usesLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .requiredLibraries(OTHER_LIBRARY);
-
-        // The org.apache.http.legacy jar should be added at the start of the list because it
-        // is not on the bootclasspath and the package targets pre-P.
-        PackageBuilder after = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .requiredLibraries(ORG_APACHE_HTTP_LEGACY, OTHER_LIBRARY);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void targeted_at_O_in_usesLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .requiredLibraries(ORG_APACHE_HTTP_LEGACY);
-
-        // No change is required because although org.apache.http.legacy has been removed from
-        // the bootclasspath the package explicitly requests it.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void targeted_at_O_in_usesOptionalLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .optionalLibraries(ORG_APACHE_HTTP_LEGACY);
-
-        // No change is required because although org.apache.http.legacy has been removed from
-        // the bootclasspath the package explicitly requests it.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void in_usesLibraries() {
-        PackageBuilder before = builder().requiredLibraries(ORG_APACHE_HTTP_LEGACY);
-
-        // No change is required because the package explicitly requests org.apache.http.legacy
-        // and is targeted at the current version so does not need backwards compatibility.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void in_usesOptionalLibraries() {
-        PackageBuilder before = builder().optionalLibraries(ORG_APACHE_HTTP_LEGACY);
-
-        // No change is required because the package explicitly requests org.apache.http.legacy
-        // and is targeted at the current version so does not need backwards compatibility.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
-        checkBackwardsCompatibility(before, after, OrgApacheHttpLegacyUpdater::new);
-    }
-}
diff --git a/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java b/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java
deleted file mode 100644
index ad9814b..0000000
--- a/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import static android.content.pm.PackageBuilder.builder;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_MOCK;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER;
-import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
-
-import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Assume;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@SmallTest
-@RunWith(JUnit4.class)
-public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdaterTest {
-
-    @Test
-    public void null_usesLibraries_and_usesOptionalLibraries() {
-        PackageBuilder before = builder();
-        PackageBuilder after = builder();
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    /**
-     * Detect when the android.test.base is not on the bootclasspath.
-     *
-     * <p>This test will be ignored when org.apache.http.legacy is not on the bootclasspath and
-     * succeed otherwise. This allows a developer to ensure that the tests are being run in the
-     * correct environment.
-     */
-    @Test
-    public void detectWhenATBisOnBCP() {
-        Assume.assumeTrue(PackageBackwardCompatibility.bootClassPathContainsATB());
-    }
-
-    /**
-     * Ensures that the {@link PackageBackwardCompatibility} uses {@link OrgApacheHttpLegacyUpdater}
-     * and {@link AndroidTestBaseUpdater} when necessary.
-     *
-     * <p>More comprehensive tests for that class can be found in
-     * {@link OrgApacheHttpLegacyUpdaterTest}.
-     */
-    @Test
-    public void targeted_at_O() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O);
-
-        List<String> expected = new ArrayList<>();
-        if (!PackageBackwardCompatibility.bootClassPathContainsATB()) {
-            expected.add(ANDROID_TEST_BASE);
-        }
-        expected.add(ORG_APACHE_HTTP_LEGACY);
-
-        PackageBuilder after = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .requiredLibraries(expected);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    /**
-     * Ensures that the {@link PackageBackwardCompatibility} uses
-     * {@link RemoveUnnecessaryAndroidTestBaseLibrary}
-     * when necessary.
-     *
-     * <p>More comprehensive tests for that class can be found in
-     * {@link RemoveUnnecessaryAndroidTestBaseLibraryTest}.
-     */
-    @Test
-    public void android_test_base_in_usesLibraries() {
-        Assume.assumeTrue("Test requires that "
-                        + ANDROID_TEST_BASE + " is on the bootclasspath",
-                PackageBackwardCompatibility.bootClassPathContainsATB());
-
-        PackageBuilder before = builder()
-                .requiredLibraries(ANDROID_TEST_BASE);
-
-        // android.test.base should be removed from the libraries because it is provided
-        // on the bootclasspath and providing both increases start up cost unnecessarily.
-        PackageBuilder after = builder();
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    /**
-     * Ensures that the {@link PackageBackwardCompatibility} uses a
-     * {@link PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater}.
-     *
-     * <p>More comprehensive tests for that class can be found in
-     * {@link AndroidTestRunnerSplitUpdaterTest}.
-     */
-    @Test
-    public void android_test_runner_in_usesLibraries() {
-        PackageBuilder before = builder().requiredLibraries(ANDROID_TEST_RUNNER);
-
-        List<String> expected = new ArrayList<>();
-        if (!PackageBackwardCompatibility.bootClassPathContainsATB()) {
-            expected.add(ANDROID_TEST_BASE);
-        }
-        expected.add(ANDROID_TEST_MOCK);
-        expected.add(ANDROID_TEST_RUNNER);
-
-        PackageBuilder after = builder()
-                .requiredLibraries(expected);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
-        checkBackwardsCompatibility(before, after, PackageBackwardCompatibility::getInstance);
-    }
-}
diff --git a/core/tests/coretests/src/android/content/pm/PackageBuilder.java b/core/tests/coretests/src/android/content/pm/PackageBuilder.java
deleted file mode 100644
index f7544af..0000000
--- a/core/tests/coretests/src/android/content/pm/PackageBuilder.java
+++ /dev/null
@@ -1,104 +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 android.content.pm;
-
-import static org.junit.Assert.assertEquals;
-
-import android.os.Build;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Test support for building {@link PackageParser.Package} instances.
- */
-class PackageBuilder {
-
-    private int mTargetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
-
-    private int mFlags = 0;
-
-    private ArrayList<String> mRequiredLibraries;
-
-    private ArrayList<String> mOptionalLibraries;
-
-    public static PackageBuilder builder() {
-        return new PackageBuilder();
-    }
-
-    public PackageParser.Package build() {
-        PackageParser.Package pkg = new PackageParser.Package("org.package.name");
-        pkg.applicationInfo.targetSdkVersion = mTargetSdkVersion;
-        pkg.applicationInfo.flags = mFlags;
-        pkg.usesLibraries = mRequiredLibraries;
-        pkg.usesOptionalLibraries = mOptionalLibraries;
-        return pkg;
-    }
-
-    PackageBuilder targetSdkVersion(int version) {
-        this.mTargetSdkVersion = version;
-        return this;
-    }
-
-    PackageBuilder asSystemApp() {
-        this.mFlags |= ApplicationInfo.FLAG_SYSTEM;
-        return this;
-    }
-
-    PackageBuilder requiredLibraries(String... names) {
-        this.mRequiredLibraries = arrayListOrNull(names);
-        return this;
-    }
-
-    PackageBuilder requiredLibraries(List<String> names) {
-        this.mRequiredLibraries = arrayListOrNull(names.toArray(new String[names.size()]));
-        return this;
-    }
-
-    PackageBuilder optionalLibraries(String... names) {
-        this.mOptionalLibraries = arrayListOrNull(names);
-        return this;
-    }
-
-    /**
-     * Check that this matches the supplied {@link PackageParser.Package}.
-     *
-     * @param pkg the instance to compare with this.
-     */
-    public void check(PackageParser.Package pkg) {
-        assertEquals("targetSdkVersion should not be changed",
-                mTargetSdkVersion,
-                pkg.applicationInfo.targetSdkVersion);
-        assertEquals("usesLibraries not updated correctly",
-                mRequiredLibraries,
-                pkg.usesLibraries);
-        assertEquals("usesOptionalLibraries not updated correctly",
-                mOptionalLibraries,
-                pkg.usesOptionalLibraries);
-    }
-
-    private static ArrayList<String> arrayListOrNull(String... strings) {
-        if (strings == null || strings.length == 0) {
-            return null;
-        }
-        ArrayList<String> list = new ArrayList<>();
-        Collections.addAll(list, strings);
-        return list;
-    }
-
-}
diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
index 5c7f2af..4402190 100644
--- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
@@ -23,26 +23,26 @@
 
 import android.apex.ApexInfo;
 import android.content.Context;
-import android.content.pm.PackageParser.Component;
-import android.content.pm.PackageParser.Package;
-import android.content.pm.PackageParser.Permission;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ParsedPackage;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.FileUtils;
-import android.os.SystemProperties;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.frameworks.coretests.R;
+import com.android.internal.util.ArrayUtils;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.io.File;
 import java.io.InputStream;
-import java.util.Arrays;
 import java.util.function.Function;
 
 @SmallTest
@@ -59,8 +59,8 @@
     private static final String PRE_RELEASE_WITH_FINGERPRINT = "B.fingerprint";
     private static final String NEWER_PRE_RELEASE_WITH_FINGERPRINT = "C.fingerprint";
 
-    private static final String[] CODENAMES_RELEASED = { /* empty */ };
-    private static final String[] CODENAMES_PRE_RELEASE = { PRE_RELEASE };
+    private static final String[] CODENAMES_RELEASED = { /* empty */};
+    private static final String[] CODENAMES_PRE_RELEASE = {PRE_RELEASE};
 
     private static final int OLDER_VERSION = 10;
     private static final int PLATFORM_VERSION = 20;
@@ -300,10 +300,6 @@
         assertEquals(0x0083, finalConfigChanges); // Should be 10000011.
     }
 
-    Package parsePackage(String apkFileName, int apkResourceId) throws Exception {
-        return parsePackage(apkFileName, apkResourceId, p -> p);
-    }
-
     /**
      * Copies a specified {@code resourceId} to a file. Returns a non-null file if the copy
      * succeeded, or {@code null} otherwise.
@@ -331,16 +327,17 @@
      *
      * APKs are put into coretests/apks/packageparser_*.
      *
-     * @param apkFileName temporary file name to store apk extracted from resources
+     * @param apkFileName   temporary file name to store apk extracted from resources
      * @param apkResourceId identifier of the apk as a resource
      */
-    Package parsePackage(String apkFileName, int apkResourceId,
-            Function<Package, Package> converter) throws Exception {
+    ParsedPackage parsePackage(String apkFileName, int apkResourceId,
+            Function<ParsedPackage, ParsedPackage> converter) throws Exception {
         // Copy the resource to a file.
         File outFile = null;
         try {
             outFile = copyRawResourceToFile(apkFileName, apkResourceId);
-            return converter.apply(new PackageParser().parsePackage(outFile, 0 /* flags */));
+            return converter.apply(
+                    new PackageParser().parseParsedPackage(outFile, 0 /* flags */, false));
         } finally {
             if (outFile != null) {
                 outFile.delete();
@@ -351,40 +348,35 @@
     /**
      * Asserts basic properties about a component.
      */
-    private void assertComponent(String className, String packageName, int numIntents,
-            Component<?> component) {
+    private void assertComponent(String className, int numIntents, ParsedComponent<?> component) {
         assertEquals(className, component.className);
-        assertEquals(packageName, component.owner.packageName);
         assertEquals(numIntents, component.intents.size());
     }
 
     /**
      * Asserts four regularly-named components of each type: one Activity, one Service, one
      * Provider, and one Receiver.
+     *
      * @param template templated string with %s subbed with Activity, Service, Provider, Receiver
      */
-    private void assertOneComponentOfEachType(String template, Package p) {
-        String packageName = p.packageName;
-
-        assertEquals(1, p.activities.size());
+    private void assertOneComponentOfEachType(String template, AndroidPackage p) {
+        assertEquals(1, p.getActivities().size());
         assertComponent(String.format(template, "Activity"),
-                packageName, 0 /* intents */, p.activities.get(0));
-        assertEquals(1, p.services.size());
+                0 /* intents */, p.getActivities().get(0));
+        assertEquals(1, p.getServices().size());
         assertComponent(String.format(template, "Service"),
-                packageName, 0 /* intents */, p.services.get(0));
-        assertEquals(1, p.providers.size());
+                0 /* intents */, p.getServices().get(0));
+        assertEquals(1, p.getProviders().size());
         assertComponent(String.format(template, "Provider"),
-                packageName, 0 /* intents */, p.providers.get(0));
-        assertEquals(1, p.receivers.size());
+                0 /* intents */, p.getProviders().get(0));
+        assertEquals(1, p.getReceivers().size());
         assertComponent(String.format(template, "Receiver"),
-                packageName, 0 /* intents */, p.receivers.get(0));
+                0 /* intents */, p.getReceivers().get(0));
     }
 
-    private void assertPermission(String name, String packageName, int protectionLevel,
-            Permission permission) {
-        assertEquals(packageName, permission.owner.packageName);
-        assertEquals(name, permission.info.name);
-        assertEquals(protectionLevel, permission.info.protectionLevel);
+    private void assertPermission(String name, int protectionLevel, ParsedPermission permission) {
+        assertEquals(name, permission.getName());
+        assertEquals(protectionLevel, permission.getProtection());
     }
 
     private void assertMetadata(Bundle b, String... keysAndValues) {
@@ -416,25 +408,25 @@
     }
 
     private void checkPackageWithComponents(
-            Function<Package, Package> converter) throws Exception {
-        Package p = parsePackage(
+            Function<ParsedPackage, ParsedPackage> converter) throws Exception {
+        ParsedPackage p = parsePackage(
                 "install_complete_package_info.apk", R.raw.install_complete_package_info,
                 converter);
         String packageName = "com.android.frameworks.coretests.install_complete_package_info";
 
-        assertEquals(packageName, p.packageName);
-        assertEquals(1, p.permissions.size());
+        assertEquals(packageName, p.getPackageName());
+        assertEquals(1, p.getPermissions().size());
         assertPermission(
                 "com.android.frameworks.coretests.install_complete_package_info.test_permission",
-                packageName, PermissionInfo.PROTECTION_NORMAL, p.permissions.get(0));
+                PermissionInfo.PROTECTION_NORMAL, p.getPermissions().get(0));
 
         // Hidden "app details" activity is added to every package.
         boolean foundAppDetailsActivity = false;
-        for (int i = 0; i < p.activities.size(); i++) {
-            if (p.activities.get(i).className.equals(
+        for (int i = 0; i < ArrayUtils.size(p.getActivities()); i++) {
+            if (p.getActivities().get(i).className.equals(
                     PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME)) {
                 foundAppDetailsActivity = true;
-                p.activities.remove(i);
+                p.getActivities().remove(i);
                 break;
             }
         }
@@ -442,72 +434,23 @@
 
         assertOneComponentOfEachType("com.android.frameworks.coretests.Test%s", p);
 
-        assertMetadata(p.mAppMetaData,
+        assertMetadata(p.getAppMetaData(),
                 "key1", "value1",
                 "key2", "this_is_app");
-        assertMetadata(p.activities.get(0).metaData,
+        assertMetadata(p.getActivities().get(0).getMetaData(),
                 "key1", "value1",
                 "key2", "this_is_activity");
-        assertMetadata(p.services.get(0).metaData,
+        assertMetadata(p.getServices().get(0).getMetaData(),
                 "key1", "value1",
                 "key2", "this_is_service");
-        assertMetadata(p.receivers.get(0).metaData,
+        assertMetadata(p.getReceivers().get(0).getMetaData(),
                 "key1", "value1",
                 "key2", "this_is_receiver");
-        assertMetadata(p.providers.get(0).metaData,
+        assertMetadata(p.getProviders().get(0).getMetaData(),
                 "key1", "value1",
                 "key2", "this_is_provider");
     }
 
-    /**
-     * Determines if the current device supports multi-package APKs.
-     */
-    private boolean supportsMultiPackageApk() {
-        return SystemProperties.getBoolean("persist.sys.child_packages_enabled", false);
-    }
-
-    @Test
-    public void testMultiPackageComponents() throws Exception {
-        // TODO(gboyer): Remove once we decide to launch multi-package APKs.
-        if (!supportsMultiPackageApk()) {
-            return;
-        }
-        String parentName = "com.android.frameworks.coretests.install_multi_package";
-        String firstChildName =
-                "com.android.frameworks.coretests.install_multi_package.first_child";
-        String secondChildName =  // NOTE: intentionally inconsistent!
-                "com.android.frameworks.coretests.blah.second_child";
-
-        Package parent = parsePackage("install_multi_package.apk", R.raw.install_multi_package);
-        assertEquals(parentName, parent.packageName);
-        assertEquals(2, parent.childPackages.size());
-        assertOneComponentOfEachType("com.android.frameworks.coretests.Test%s", parent);
-        assertEquals(1, parent.permissions.size());
-        assertPermission(parentName + ".test_permission", parentName,
-                PermissionInfo.PROTECTION_NORMAL, parent.permissions.get(0));
-        assertEquals(Arrays.asList("android.permission.INTERNET"),
-                parent.requestedPermissions);
-
-        Package firstChild = parent.childPackages.get(0);
-        assertEquals(firstChildName, firstChild.packageName);
-        assertOneComponentOfEachType(
-                "com.android.frameworks.coretests.FirstChildTest%s", firstChild);
-        assertEquals(0, firstChild.permissions.size());  // Child APKs cannot declare permissions.
-        assertEquals(Arrays.asList("android.permission.NFC"),
-                firstChild.requestedPermissions);
-
-        Package secondChild = parent.childPackages.get(1);
-        assertEquals(secondChildName, secondChild.packageName);
-        assertOneComponentOfEachType(
-                "com.android.frameworks.coretests.SecondChildTest%s", secondChild);
-        assertEquals(0, secondChild.permissions.size());  // Child APKs cannot declare permissions.
-        assertEquals(
-                Arrays.asList(
-                        "android.permission.ACCESS_NETWORK_STATE",
-                        "android.permission.READ_CONTACTS"),
-                secondChild.requestedPermissions);
-    }
-
     @Test
     public void testApexPackageInfoGeneration() throws Exception {
         String apexModuleName = "com.android.tzdata.apex";
@@ -522,7 +465,7 @@
         int flags = PackageManager.GET_META_DATA | PackageManager.GET_SIGNING_CERTIFICATES;
 
         PackageParser pp = new PackageParser();
-        Package p = pp.parsePackage(apexFile, flags, false);
+        PackageParser.Package p = pp.parsePackage(apexFile, flags, false);
         PackageParser.collectCertificates(p, false);
         PackageInfo pi = PackageParser.generatePackageInfo(p, apexInfo, flags);
 
diff --git a/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java b/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java
deleted file mode 100644
index 71a0e5e..0000000
--- a/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java
+++ /dev/null
@@ -1,32 +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 android.content.pm;
-
-import java.util.function.Supplier;
-
-/**
- * Helper for classes that test {@link PackageSharedLibraryUpdater}.
- */
-abstract class PackageSharedLibraryUpdaterTest {
-
-    static void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after,
-            Supplier<PackageSharedLibraryUpdater> updaterSupplier) {
-        PackageParser.Package pkg = before.build();
-        updaterSupplier.get().updatePackage(pkg);
-        after.check(pkg);
-    }
-}
diff --git a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java b/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
deleted file mode 100644
index 216b0c8..0000000
--- a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
+++ /dev/null
@@ -1,133 +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 android.content.pm;
-
-import static android.content.pm.PackageBuilder.builder;
-import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE;
-
-import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Test for {@link RemoveUnnecessaryAndroidTestBaseLibrary}
- */
-@SmallTest
-@RunWith(JUnit4.class)
-public class RemoveUnnecessaryAndroidTestBaseLibraryTest
-        extends PackageSharedLibraryUpdaterTest {
-
-    private static final String OTHER_LIBRARY = "other.library";
-
-    @Test
-    public void targeted_at_O() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O);
-
-        // No change required.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void targeted_at_O_not_empty_usesLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .requiredLibraries(OTHER_LIBRARY);
-
-        // No change required.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void targeted_at_O_in_usesLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .requiredLibraries(ANDROID_TEST_BASE);
-
-        // android.test.base should be removed from the libraries because it is provided
-        // on the bootclasspath and providing both increases start up cost unnecessarily.
-        PackageBuilder after = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void targeted_at_O_in_usesOptionalLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .optionalLibraries(ANDROID_TEST_BASE);
-
-        // android.test.base should be removed from the libraries because it is provided
-        // on the bootclasspath and providing both increases start up cost unnecessarily.
-        PackageBuilder after = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void in_usesLibraries() {
-        PackageBuilder before = builder().requiredLibraries(ANDROID_TEST_BASE);
-
-        // android.test.base should be removed from the libraries because it is provided
-        // on the bootclasspath and providing both increases start up cost unnecessarily.
-        PackageBuilder after = builder();
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void in_usesOptionalLibraries() {
-        PackageBuilder before = builder().optionalLibraries(ANDROID_TEST_BASE);
-
-        // android.test.base should be removed from the libraries because it is provided
-        // on the bootclasspath and providing both increases start up cost unnecessarily.
-        PackageBuilder after = builder();
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void in_bothLibraries() {
-        PackageBuilder before = builder()
-                .requiredLibraries(ANDROID_TEST_BASE)
-                .optionalLibraries(ANDROID_TEST_BASE);
-
-        // android.test.base should be removed from the libraries because it is provided
-        // on the bootclasspath and providing both increases start up cost unnecessarily.
-        PackageBuilder after = builder();
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
-        // TODO(b/72538146) - Cannot use constructor reference here because it is also used in
-        // PackageBackwardCompatibility and that seems to create a package-private lambda in
-        // android.content.pm which this then tries to reuse but fails because it cannot access
-        // package-private classes/members because the test is loaded by a different ClassLoader
-        // than the lambda.
-        checkBackwardsCompatibility(before, after,
-                () -> new RemoveUnnecessaryAndroidTestBaseLibrary());
-    }
-
-}
diff --git a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java b/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
deleted file mode 100644
index fc60980..0000000
--- a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
+++ /dev/null
@@ -1,132 +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 android.content.pm;
-
-import static android.content.pm.PackageBuilder.builder;
-import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
-
-import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary;
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Test for {@link RemoveUnnecessaryOrgApacheHttpLegacyLibrary}
- */
-@SmallTest
-@RunWith(JUnit4.class)
-public class RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest
-        extends PackageSharedLibraryUpdaterTest {
-
-    private static final String OTHER_LIBRARY = "other.library";
-
-    @Test
-    public void targeted_at_O() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O);
-
-        // No change required.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void targeted_at_O_not_empty_usesLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .requiredLibraries(OTHER_LIBRARY);
-
-        // No change required.
-        checkBackwardsCompatibility(before, before);
-    }
-
-    @Test
-    public void targeted_at_O_in_usesLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .requiredLibraries(ORG_APACHE_HTTP_LEGACY);
-
-        // org.apache.http.legacy should be removed from the libraries because it is provided
-        // on the bootclasspath and providing both increases start up cost unnecessarily.
-        PackageBuilder after = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void targeted_at_O_in_usesOptionalLibraries() {
-        PackageBuilder before = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O)
-                .optionalLibraries(ORG_APACHE_HTTP_LEGACY);
-
-        // org.apache.http.legacy should be removed from the libraries because it is provided
-        // on the bootclasspath and providing both increases start up cost unnecessarily.
-        PackageBuilder after = builder()
-                .targetSdkVersion(Build.VERSION_CODES.O);
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void in_usesLibraries() {
-        PackageBuilder before = builder().requiredLibraries(ORG_APACHE_HTTP_LEGACY);
-
-        // org.apache.http.legacy should be removed from the libraries because it is provided
-        // on the bootclasspath and providing both increases start up cost unnecessarily.
-        PackageBuilder after = builder();
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void in_usesOptionalLibraries() {
-        PackageBuilder before = builder().optionalLibraries(ORG_APACHE_HTTP_LEGACY);
-
-        // org.apache.http.legacy should be removed from the libraries because it is provided
-        // on the bootclasspath and providing both increases start up cost unnecessarily.
-        PackageBuilder after = builder();
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    @Test
-    public void in_bothLibraries() {
-        PackageBuilder before = builder()
-                .requiredLibraries(ORG_APACHE_HTTP_LEGACY)
-                .optionalLibraries(ORG_APACHE_HTTP_LEGACY);
-
-        // org.apache.http.legacy should be removed from the libraries because it is provided
-        // on the bootclasspath and providing both increases start up cost unnecessarily.
-        PackageBuilder after = builder();
-
-        checkBackwardsCompatibility(before, after);
-    }
-
-    private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) {
-        // TODO(b/72538146) - Cannot use constructor reference here because it is also used in
-        // PackageBackwardCompatibility and that seems to create a package-private lambda in
-        // android.content.pm which this then tries to reuse but fails because it cannot access
-        // package-private classes/members because the test is loaded by a different ClassLoader
-        // than the lambda.
-        checkBackwardsCompatibility(before, after,
-                () -> new RemoveUnnecessaryOrgApacheHttpLegacyLibrary());
-    }
-}
diff --git a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
index 49849ee..1e0bfb0 100644
--- a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
+++ b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
@@ -25,9 +25,9 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.ApkLite;
-import android.content.pm.PackageParser.Package;
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.parsing.ParsedPackage;
 import android.os.FileUtils;
 
 import androidx.test.InstrumentationRegistry;
@@ -36,7 +36,6 @@
 
 import com.android.frameworks.coretests.R;
 
-import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
@@ -95,13 +94,13 @@
     public void testParsePackageWithDmFileValid() throws IOException, PackageParserException {
         copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
         createDexMetadataFile("install_split_base.apk");
-        Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */);
+        ParsedPackage pkg = new PackageParser().parseParsedPackage(mTmpDir, 0 /* flags */, false);
 
         Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg);
         assertEquals(1, packageDexMetadata.size());
-        String baseDexMetadata = packageDexMetadata.get(pkg.baseCodePath);
+        String baseDexMetadata = packageDexMetadata.get(pkg.getBaseCodePath());
         assertNotNull(baseDexMetadata);
-        assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.baseCodePath));
+        assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.getBaseCodePath()));
     }
 
     @Test
@@ -111,17 +110,17 @@
         copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a);
         createDexMetadataFile("install_split_base.apk");
         createDexMetadataFile("install_split_feature_a.apk");
-        Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */);
+        ParsedPackage pkg = new PackageParser().parseParsedPackage(mTmpDir, 0 /* flags */, false);
 
         Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg);
         assertEquals(2, packageDexMetadata.size());
-        String baseDexMetadata = packageDexMetadata.get(pkg.baseCodePath);
+        String baseDexMetadata = packageDexMetadata.get(pkg.getBaseCodePath());
         assertNotNull(baseDexMetadata);
-        assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.baseCodePath));
+        assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.getBaseCodePath()));
 
-        String splitDexMetadata = packageDexMetadata.get(pkg.splitCodePaths[0]);
+        String splitDexMetadata = packageDexMetadata.get(pkg.getSplitCodePaths()[0]);
         assertNotNull(splitDexMetadata);
-        assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.splitCodePaths[0]));
+        assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.getSplitCodePaths()[0]));
     }
 
     @Test
@@ -130,14 +129,14 @@
         copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
         copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a);
         createDexMetadataFile("install_split_feature_a.apk");
-        Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */);
+        ParsedPackage pkg = new PackageParser().parseParsedPackage(mTmpDir, 0 /* flags */, false);
 
         Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg);
         assertEquals(1, packageDexMetadata.size());
 
-        String splitDexMetadata = packageDexMetadata.get(pkg.splitCodePaths[0]);
+        String splitDexMetadata = packageDexMetadata.get(pkg.getSplitCodePaths()[0]);
         assertNotNull(splitDexMetadata);
-        assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.splitCodePaths[0]));
+        assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.getSplitCodePaths()[0]));
     }
 
     @Test
@@ -146,7 +145,8 @@
         File invalidDmFile = new File(mTmpDir, "install_split_base.dm");
         Files.createFile(invalidDmFile.toPath());
         try {
-            PackageParser.Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */);
+            ParsedPackage pkg = new PackageParser()
+                    .parseParsedPackage(mTmpDir, 0 /* flags */, false);
             DexMetadataHelper.validatePackageDexMetadata(pkg);
         } catch (PackageParserException e) {
             assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
@@ -163,7 +163,8 @@
         Files.createFile(invalidDmFile.toPath());
 
         try {
-            PackageParser.Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */);
+            ParsedPackage pkg = new PackageParser()
+                    .parseParsedPackage(mTmpDir, 0 /* flags */, false);
             DexMetadataHelper.validatePackageDexMetadata(pkg);
         } catch (PackageParserException e) {
             assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidHidlUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidHidlUpdaterTest.java
new file mode 100644
index 0000000..21479c0
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidHidlUpdaterTest.java
@@ -0,0 +1,191 @@
+/*
+ * 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.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_BASE;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_MANAGER;
+
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test for {@link AndroidHidlUpdater}
+ */
+@SmallTest
+@RunWith(JUnit4.class)
+public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest {
+
+    private static final String OTHER_LIBRARY = "other.library";
+
+    @Test
+    public void targeted_at_P() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // no change, not system
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_P_system() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .hideAsParsed()
+                .setSystem(true);
+
+        // Should add both HIDL libraries
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .addUsesLibrary(ANDROID_HIDL_MANAGER)
+                .addUsesLibrary(ANDROID_HIDL_BASE)
+                .hideAsParsed()
+                .setSystem(true)
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_P_not_empty_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // no change, not system
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_P_not_empty_usesLibraries_system() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed()
+                .setSystem(true);
+
+        // The hidl jars should be added at the start of the list because it
+        // is not on the bootclasspath and the package targets pre-P.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .addUsesLibrary(ANDROID_HIDL_MANAGER)
+                .addUsesLibrary(ANDROID_HIDL_BASE)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed()
+                .setSystem(true)
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_P_in_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .addUsesLibrary(ANDROID_HIDL_MANAGER)
+                .addUsesLibrary(ANDROID_HIDL_BASE)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // Libraries are removed because they are not available for non-system apps
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_P_in_usesLibraries_system() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .addUsesLibrary(ANDROID_HIDL_MANAGER)
+                .addUsesLibrary(ANDROID_HIDL_BASE)
+                .hideAsParsed()
+                .setSystem(true);
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.P)
+                .addUsesLibrary(ANDROID_HIDL_MANAGER)
+                .addUsesLibrary(ANDROID_HIDL_BASE)
+                .hideAsParsed()
+                .setSystem(true)
+                .hideAsFinal();
+
+        // No change is required because the package explicitly requests the HIDL libraries
+        // and is targeted at the current version so does not need backwards compatibility.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ANDROID_HIDL_BASE)
+                .hideAsParsed();
+
+        // Dependency is removed, it is not available.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // Libraries are removed because they are not available for apps targeting Q+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesOptionalLibrary(ANDROID_HIDL_BASE)
+                .hideAsParsed();
+
+        // Dependency is removed, it is not available.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // Libraries are removed because they are not available for apps targeting Q+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
+        checkBackwardsCompatibility(before, after, AndroidHidlUpdater::new);
+    }
+}
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestBaseUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestBaseUpdaterTest.java
new file mode 100644
index 0000000..65ae219
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestBaseUpdaterTest.java
@@ -0,0 +1,152 @@
+/*
+ * 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.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
+
+import android.content.pm.OptionalClassRunner;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test for {@link AndroidTestBaseUpdater}
+ */
+@SmallTest
+@RunWith(OptionalClassRunner.class)
+@OptionalClassRunner.OptionalClass("android.content.pm.parsing.library.AndroidTestBaseUpdater")
+public class AndroidTestBaseUpdaterTest extends PackageSharedLibraryUpdaterTest {
+
+    private static final String OTHER_LIBRARY = "other.library";
+
+    @Test
+    public void targeted_at_Q() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.Q)
+                .hideAsParsed();
+
+        // Should add org.apache.http.legacy.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.Q)
+                .addUsesLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_Q_not_empty_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.Q)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed();
+
+        // The org.apache.http.legacy jar should be added at the start of the list because it
+        // is not on the bootclasspath and the package targets pre-Q.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.Q)
+                .addUsesLibrary(ANDROID_TEST_BASE)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_Q_in_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.Q)
+                .addUsesLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.Q)
+                .addUsesLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change is required because although org.apache.http.legacy has been removed from
+        // the bootclasspath the package explicitly requests it.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_Q_in_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.Q)
+                .addUsesOptionalLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.Q)
+                .addUsesOptionalLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change is required because although org.apache.http.legacy has been removed from
+        // the bootclasspath the package explicitly requests it.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change is required because the package explicitly requests org.apache.http.legacy
+        // and is targeted at the current version so does not need backwards compatibility.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesOptionalLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesOptionalLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change is required because the package explicitly requests org.apache.http.legacy
+        // and is targeted at the current version so does not need backwards compatibility.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
+        checkBackwardsCompatibility(before, after, AndroidTestBaseUpdater::new);
+    }
+}
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
new file mode 100644
index 0000000..38755b9
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
+
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.library.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test for {@link AndroidTestRunnerSplitUpdater}
+ */
+@SmallTest
+@RunWith(JUnit4.class)
+public class AndroidTestRunnerSplitUpdaterTest extends PackageSharedLibraryUpdaterTest {
+
+    @Test
+    public void android_test_runner_in_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesOptionalLibrary(ANDROID_TEST_RUNNER)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesOptionalLibrary(ANDROID_TEST_MOCK)
+                .addUsesOptionalLibrary(ANDROID_TEST_RUNNER)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void android_test_runner_in_usesLibraries_android_test_mock_in_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ANDROID_TEST_RUNNER)
+                .addUsesOptionalLibrary(ANDROID_TEST_MOCK)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ANDROID_TEST_RUNNER)
+                .addUsesOptionalLibrary(ANDROID_TEST_MOCK)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
+        checkBackwardsCompatibility(before, after, AndroidTestRunnerSplitUpdater::new);
+    }
+}
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
new file mode 100644
index 0000000..4c7899b
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
@@ -0,0 +1,152 @@
+/*
+ * 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.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
+
+import android.content.pm.OptionalClassRunner;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test for {@link OrgApacheHttpLegacyUpdater}
+ */
+@SmallTest
+@RunWith(OptionalClassRunner.class)
+@OptionalClassRunner.OptionalClass("android.content.pm.parsing.library.OrgApacheHttpLegacyUpdater")
+public class OrgApacheHttpLegacyUpdaterTest extends PackageSharedLibraryUpdaterTest {
+
+    private static final String OTHER_LIBRARY = "other.library";
+
+    @Test
+    public void targeted_at_O() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .hideAsParsed();
+
+        // Should add org.apache.http.legacy.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_not_empty_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed();
+
+        // The org.apache.http.legacy jar should be added at the start of the list because it
+        // is not on the bootclasspath and the package targets pre-P.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_in_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change is required because although org.apache.http.legacy has been removed from
+        // the bootclasspath the package explicitly requests it.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_in_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change is required because although org.apache.http.legacy has been removed from
+        // the bootclasspath the package explicitly requests it.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change is required because the package explicitly requests org.apache.http.legacy
+        // and is targeted at the current version so does not need backwards compatibility.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change is required because the package explicitly requests org.apache.http.legacy
+        // and is targeted at the current version so does not need backwards compatibility.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
+        checkBackwardsCompatibility(before, after, OrgApacheHttpLegacyUpdater::new);
+    }
+}
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/PackageBackwardCompatibilityTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/PackageBackwardCompatibilityTest.java
new file mode 100644
index 0000000..00d468d
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/PackageBackwardCompatibilityTest.java
@@ -0,0 +1,151 @@
+/*
+ * 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.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK;
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
+import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
+
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@SmallTest
+@RunWith(JUnit4.class)
+public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdaterTest {
+
+    @Test
+    public void null_usesLibraries_and_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    /**
+     * Detect when the android.test.base is not on the bootclasspath.
+     *
+     * <p>This test will be ignored when org.apache.http.legacy is not on the bootclasspath and
+     * succeed otherwise. This allows a developer to ensure that the tests are being run in the
+     * correct environment.
+     */
+    @Test
+    public void detectWhenATBisOnBCP() {
+        Assume.assumeTrue(PackageBackwardCompatibility.bootClassPathContainsATB());
+    }
+
+    /**
+     * Ensures that the {@link PackageBackwardCompatibility} uses {@link OrgApacheHttpLegacyUpdater}
+     * and {@link AndroidTestBaseUpdater} when necessary.
+     *
+     * <p>More comprehensive tests for that class can be found in
+     * {@link OrgApacheHttpLegacyUpdaterTest}.
+     */
+    @Test
+    public void targeted_at_O() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .hideAsParsed();
+
+        ParsingPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .setTargetSdkVersion(Build.VERSION_CODES.O);
+
+        if (!PackageBackwardCompatibility.bootClassPathContainsATB()) {
+            after.addUsesLibrary(ANDROID_TEST_BASE);
+        }
+        after.addUsesLibrary(ORG_APACHE_HTTP_LEGACY);
+
+        checkBackwardsCompatibility(before, after.hideAsParsed().hideAsFinal());
+    }
+
+    /**
+     * Ensures that the {@link PackageBackwardCompatibility} uses
+     * {@link RemoveUnnecessaryAndroidTestBaseLibrary}
+     * when necessary.
+     *
+     * <p>More comprehensive tests for that class can be found in
+     * {@link RemoveUnnecessaryAndroidTestBaseLibraryTest}.
+     */
+    @Test
+    public void android_test_base_in_usesLibraries() {
+        Assume.assumeTrue("Test requires that "
+                        + ANDROID_TEST_BASE + " is on the bootclasspath",
+                PackageBackwardCompatibility.bootClassPathContainsATB());
+
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed();
+
+        // android.test.base should be removed from the libraries because it is provided
+        // on the bootclasspath and providing both increases start up cost unnecessarily.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    /**
+     * Ensures that the {@link PackageBackwardCompatibility} uses a
+     * {@link PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater}.
+     *
+     * <p>More comprehensive tests for that class can be found in
+     * {@link AndroidTestRunnerSplitUpdaterTest}.
+     */
+    @Test
+    public void android_test_runner_in_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ANDROID_TEST_RUNNER)
+                .hideAsParsed();
+
+        ParsingPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT);
+        if (!PackageBackwardCompatibility.bootClassPathContainsATB()) {
+            after.addUsesLibrary(ANDROID_TEST_BASE);
+        }
+        after.addUsesLibrary(ANDROID_TEST_MOCK);
+        after.addUsesLibrary(ANDROID_TEST_RUNNER);
+
+        checkBackwardsCompatibility(before, after.hideAsParsed().hideAsFinal());
+    }
+
+    private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
+        checkBackwardsCompatibility(before, after, PackageBackwardCompatibility::getInstance);
+    }
+}
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/PackageSharedLibraryUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/PackageSharedLibraryUpdaterTest.java
new file mode 100644
index 0000000..e7a80e1a
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/PackageSharedLibraryUpdaterTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.content.pm.parsing.library;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ParsedPackage;
+
+import java.util.function.Supplier;
+
+/**
+ * Helper for classes that test {@link PackageSharedLibraryUpdater}.
+ */
+abstract class PackageSharedLibraryUpdaterTest {
+
+    protected static final String PACKAGE_NAME = "org.package.name";
+
+    static void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after,
+            Supplier<PackageSharedLibraryUpdater> updaterSupplier) {
+        updaterSupplier.get().updatePackage(before);
+        check(before.hideAsFinal(), after);
+    }
+
+    private static void check(AndroidPackage before, AndroidPackage after) {
+        assertEquals("targetSdkVersion should not be changed",
+                after.getTargetSdkVersion(),
+                before.getTargetSdkVersion());
+        assertEquals("usesLibraries not updated correctly",
+                after.getUsesLibraries(),
+                before.getUsesLibraries());
+        assertEquals("usesOptionalLibraries not updated correctly",
+                after.getUsesOptionalLibraries(),
+                before.getUsesOptionalLibraries());
+    }
+}
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
new file mode 100644
index 0000000..fd3ba2b
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
@@ -0,0 +1,169 @@
+/*
+ * 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.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
+
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test for {@link RemoveUnnecessaryAndroidTestBaseLibrary}
+ */
+@SmallTest
+@RunWith(JUnit4.class)
+public class RemoveUnnecessaryAndroidTestBaseLibraryTest
+        extends PackageSharedLibraryUpdaterTest {
+
+    private static final String OTHER_LIBRARY = "other.library";
+
+    @Test
+    public void targeted_at_O() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change required.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_not_empty_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change required.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_in_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed();
+
+        // android.test.base should be removed from the libraries because it is provided
+        // on the bootclasspath and providing both increases start up cost unnecessarily.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_in_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesOptionalLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed();
+
+        // android.test.base should be removed from the libraries because it is provided
+        // on the bootclasspath and providing both increases start up cost unnecessarily.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .addUsesLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed();
+
+        // android.test.base should be removed from the libraries because it is provided
+        // on the bootclasspath and providing both increases start up cost unnecessarily.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesOptionalLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed();
+
+        // android.test.base should be removed from the libraries because it is provided
+        // on the bootclasspath and providing both increases start up cost unnecessarily.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_bothLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ANDROID_TEST_BASE)
+                .addUsesOptionalLibrary(ANDROID_TEST_BASE)
+                .hideAsParsed();
+
+        // android.test.base should be removed from the libraries because it is provided
+        // on the bootclasspath and providing both increases start up cost unnecessarily.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
+        // TODO(b/72538146) - Cannot use constructor reference here because it is also used in
+        // PackageBackwardCompatibility and that seems to create a package-private lambda in
+        // android.content.pm which this then tries to reuse but fails because it cannot access
+        // package-private classes/members because the test is loaded by a different ClassLoader
+        // than the lambda.
+        checkBackwardsCompatibility(before, after,
+                () -> new RemoveUnnecessaryAndroidTestBaseLibrary());
+    }
+
+}
diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
new file mode 100644
index 0000000..d3494d9
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
@@ -0,0 +1,168 @@
+/*
+ * 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.content.pm.parsing.library;
+
+import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
+
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test for {@link RemoveUnnecessaryOrgApacheHttpLegacyLibrary}
+ */
+@SmallTest
+@RunWith(JUnit4.class)
+public class RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest
+        extends PackageSharedLibraryUpdaterTest {
+
+    private static final String OTHER_LIBRARY = "other.library";
+
+    @Test
+    public void targeted_at_O() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change required.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_not_empty_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed();
+
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary(OTHER_LIBRARY)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        // No change required.
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_in_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed();
+
+        // org.apache.http.legacy should be removed from the libraries because it is provided
+        // on the bootclasspath and providing both increases start up cost unnecessarily.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_O_in_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed();
+
+        // org.apache.http.legacy should be removed from the libraries because it is provided
+        // on the bootclasspath and providing both increases start up cost unnecessarily.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.O)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_usesLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed();
+
+        // org.apache.http.legacy should be removed from the libraries because it is provided
+        // on the bootclasspath and providing both increases start up cost unnecessarily.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_usesOptionalLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed();
+
+        // org.apache.http.legacy should be removed from the libraries because it is provided
+        // on the bootclasspath and providing both increases start up cost unnecessarily.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void in_bothLibraries() {
+        ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .addUsesLibrary(ORG_APACHE_HTTP_LEGACY)
+                .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY)
+                .hideAsParsed();
+
+        // org.apache.http.legacy should be removed from the libraries because it is provided
+        // on the bootclasspath and providing both increases start up cost unnecessarily.
+        AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+                .hideAsParsed()
+                .hideAsFinal();
+
+        checkBackwardsCompatibility(before, after);
+    }
+
+    private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
+        // TODO(b/72538146) - Cannot use constructor reference here because it is also used in
+        // PackageBackwardCompatibility and that seems to create a package-private lambda in
+        // android.content.pm which this then tries to reuse but fails because it cannot access
+        // package-private classes/members because the test is loaded by a different ClassLoader
+        // than the lambda.
+        checkBackwardsCompatibility(before, after,
+                () -> new RemoveUnnecessaryOrgApacheHttpLegacyLibrary());
+    }
+}
diff --git a/core/tests/coretests/src/android/content/res/ConfigurationTest.java b/core/tests/coretests/src/android/content/res/ConfigurationTest.java
index c231e61..2c956c9 100644
--- a/core/tests/coretests/src/android/content/res/ConfigurationTest.java
+++ b/core/tests/coretests/src/android/content/res/ConfigurationTest.java
@@ -96,7 +96,7 @@
                 .setExtension('u', "nu-latn").build();
         Configuration write = new Configuration();
         write.setLocales(new LocaleList(arabic, urdu, urduExtension));
-        writeToProto(proto, write);
+        dumpDebug(proto, write);
         assertTrue("Failed to write configs to proto.", proto.exists());
 
         final Configuration read = new Configuration();
@@ -148,13 +148,13 @@
         assertEquals(SMALLEST_SCREEN_WIDTH_DP_UNDEFINED, config.smallestScreenWidthDp);
     }
 
-    private void writeToProto(File f, Configuration config) throws Exception {
+    private void dumpDebug(File f, Configuration config) throws Exception {
         final AtomicFile af = new AtomicFile(f);
         FileOutputStream fos = af.startWrite();
         try {
             final ProtoOutputStream protoOut = new ProtoOutputStream(fos);
             final long token = protoOut.start(IntervalStatsProto.CONFIGURATIONS);
-            config.writeToProto(protoOut, IntervalStatsProto.Configuration.CONFIG, false, false);
+            config.dumpDebug(protoOut, IntervalStatsProto.Configuration.CONFIG, false, false);
             protoOut.end(token);
             protoOut.flush();
             af.finishWrite(fos);
diff --git a/core/tests/coretests/src/android/service/controls/ControlActionTest.java b/core/tests/coretests/src/android/service/controls/ControlActionTest.java
new file mode 100644
index 0000000..ef4912f
--- /dev/null
+++ b/core/tests/coretests/src/android/service/controls/ControlActionTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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;
+
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ControlActionTest {
+
+    private static final String TEST_ID = "TEST_ID";
+
+    @Test
+    public void testUnparcelingCorrectClass_boolean() {
+        ControlAction toParcel = new BooleanAction(TEST_ID, true);
+
+        ControlAction fromParcel = parcelAndUnparcel(toParcel);
+
+        assertEquals(ControlAction.TYPE_BOOLEAN, fromParcel.getActionType());
+        assertTrue(fromParcel instanceof BooleanAction);
+    }
+
+    @Test
+    public void testUnparcelingCorrectClass_float() {
+        ControlAction toParcel = new FloatAction(TEST_ID, 1);
+
+        ControlAction fromParcel = parcelAndUnparcel(toParcel);
+
+        assertEquals(ControlAction.TYPE_FLOAT, fromParcel.getActionType());
+        assertTrue(fromParcel instanceof FloatAction);
+    }
+
+    private ControlAction parcelAndUnparcel(ControlAction toParcel) {
+        Parcel parcel = Parcel.obtain();
+
+        assertNotNull(parcel);
+
+        parcel.setDataPosition(0);
+        toParcel.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+
+        return ControlAction.CREATOR.createFromParcel(parcel);
+    }
+}
diff --git a/core/tests/coretests/src/android/service/controls/ControlTemplateTest.java b/core/tests/coretests/src/android/service/controls/ControlTemplateTest.java
new file mode 100644
index 0000000..4fa4e1d
--- /dev/null
+++ b/core/tests/coretests/src/android/service/controls/ControlTemplateTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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;
+
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.annotation.DrawableRes;
+import android.graphics.drawable.Icon;
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.frameworks.coretests.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+import java.security.InvalidParameterException;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ControlTemplateTest {
+
+    private static final String PACKAGE_NAME = "com.android.frameworks.coretests";
+    private static final @DrawableRes int TEST_ICON_ID = R.drawable.box;
+    private static final String TEST_ID = "TEST_ID";
+    private static final CharSequence TEST_CONTENT_DESCRIPTION = "TEST_CONTENT_DESCRIPTION";
+    private Icon mIcon;
+    private ControlButton mControlButton;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mIcon = Icon.createWithResource(PACKAGE_NAME, TEST_ICON_ID);
+        mControlButton = new ControlButton(true, mIcon, TEST_CONTENT_DESCRIPTION);
+    }
+
+    @Test
+    public void testUnparcelingCorrectClass_none() {
+        ControlTemplate toParcel = ControlTemplate.NO_TEMPLATE;
+
+        ControlTemplate fromParcel = parcelAndUnparcel(toParcel);
+
+        assertEquals(ControlTemplate.NO_TEMPLATE, fromParcel);
+    }
+
+    @Test
+    public void testUnparcelingCorrectClass_toggle() {
+        ControlTemplate toParcel = new ToggleTemplate(TEST_ID, mControlButton);
+
+        ControlTemplate fromParcel = parcelAndUnparcel(toParcel);
+
+        assertEquals(ControlTemplate.TYPE_TOGGLE, fromParcel.getTemplateType());
+        assertTrue(fromParcel instanceof ToggleTemplate);
+    }
+
+    @Test
+    public void testUnparcelingCorrectClass_range() {
+        ControlTemplate toParcel = new RangeTemplate(TEST_ID, 0, 2, 1, 1, "%f");
+
+        ControlTemplate fromParcel = parcelAndUnparcel(toParcel);
+
+        assertEquals(ControlTemplate.TYPE_RANGE, fromParcel.getTemplateType());
+        assertTrue(fromParcel instanceof RangeTemplate);
+    }
+
+    @Test(expected = InvalidParameterException.class)
+    public void testRangeParameters_minMax() {
+        RangeTemplate range = new RangeTemplate(TEST_ID, 2, 0, 1, 1, "%f");
+    }
+
+    @Test(expected = InvalidParameterException.class)
+    public void testRangeParameters_minCurrent() {
+        RangeTemplate range = new RangeTemplate(TEST_ID, 0, 2, -1, 1, "%f");
+    }
+
+    @Test(expected = InvalidParameterException.class)
+    public void testRangeParameters_maxCurrent() {
+        RangeTemplate range = new RangeTemplate(TEST_ID, 0, 2, 3, 1, "%f");
+    }
+
+    @Test(expected = InvalidParameterException.class)
+    public void testRangeParameters_negativeStep() {
+        RangeTemplate range = new RangeTemplate(TEST_ID, 0, 2, 1, -1, "%f");
+    }
+
+    @Test
+    public void testUnparcelingCorrectClass_thumbnail() {
+        ControlTemplate toParcel = new ThumbnailTemplate(TEST_ID, mIcon, TEST_CONTENT_DESCRIPTION);
+
+        ControlTemplate fromParcel = parcelAndUnparcel(toParcel);
+
+        assertEquals(ControlTemplate.TYPE_THUMBNAIL, fromParcel.getTemplateType());
+        assertTrue(fromParcel instanceof ThumbnailTemplate);
+    }
+
+    @Test
+    public void testUnparcelingCorrectClass_discreteToggle() {
+        ControlTemplate toParcel =
+                new DiscreteToggleTemplate(TEST_ID, mControlButton, mControlButton);
+
+        ControlTemplate fromParcel = parcelAndUnparcel(toParcel);
+
+        assertEquals(ControlTemplate.TYPE_DISCRETE_TOGGLE, fromParcel.getTemplateType());
+        assertTrue(fromParcel instanceof DiscreteToggleTemplate);
+    }
+
+    private ControlTemplate parcelAndUnparcel(ControlTemplate toParcel) {
+        Parcel parcel = Parcel.obtain();
+
+        assertNotNull(parcel);
+
+        parcel.setDataPosition(0);
+        toParcel.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+
+        return ControlTemplate.CREATOR.createFromParcel(parcel);
+    }
+}
diff --git a/core/tests/coretests/src/android/util/LocalLogTest.java b/core/tests/coretests/src/android/util/LocalLogTest.java
index 6cdcb5e..d4861cd 100644
--- a/core/tests/coretests/src/android/util/LocalLogTest.java
+++ b/core/tests/coretests/src/android/util/LocalLogTest.java
@@ -29,14 +29,24 @@
 @LargeTest
 public class LocalLogTest extends TestCase {
 
-    public void testA() {
+    public void testA_localTimestamps() {
+        boolean localTimestamps = true;
+        doTestA(localTimestamps);
+    }
+
+    public void testA_nonLocalTimestamps() {
+        boolean localTimestamps = false;
+        doTestA(localTimestamps);
+    }
+
+    private void doTestA(boolean localTimestamps) {
         String[] lines = {
-            "foo",
-            "bar",
-            "baz"
+                "foo",
+                "bar",
+                "baz"
         };
         String[] want = lines;
-        testcase(new LocalLog(10), lines, want);
+        testcase(new LocalLog(10, localTimestamps), lines, want);
     }
 
     public void testB() {
diff --git a/core/tests/coretests/src/android/util/StatsEventTest.java b/core/tests/coretests/src/android/util/StatsEventTest.java
index 93f11db..097bada 100644
--- a/core/tests/coretests/src/android/util/StatsEventTest.java
+++ b/core/tests/coretests/src/android/util/StatsEventTest.java
@@ -53,8 +53,8 @@
         final ByteBuffer buffer =
                 ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN);
 
-        assertWithMessage("Root element in buffer is not TYPE_ERRORS")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_ERRORS);
+        assertWithMessage("Root element in buffer is not TYPE_OBJECT")
+                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT);
 
         assertWithMessage("Incorrect number of elements in root object")
                 .that(buffer.get()).isEqualTo(3);
@@ -71,6 +71,9 @@
         assertWithMessage("Incorrect atom id")
                 .that(buffer.getInt()).isEqualTo(expectedAtomId);
 
+        assertWithMessage("Third element is not errors type")
+                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_ERRORS);
+
         final int errorMask = buffer.getInt();
 
         assertWithMessage("ERROR_NO_ATOM_ID should be the only error in the error mask")
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
index 17fe61d..deb0f18 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
@@ -548,8 +548,10 @@
     }
 
     @Test
-    public void testSuggetsConversationActions_deduplicate() {
-        if (isTextClassifierDisabled()) return;
+    public void testSuggestConversationActions_deduplicate() {
+        Context context = new FakeContextBuilder()
+                .setIntentComponent(Intent.ACTION_SENDTO, FakeContextBuilder.DEFAULT_COMPONENT)
+                .build();
         ConversationActions.Message message =
                 new ConversationActions.Message.Builder(
                         ConversationActions.Message.PERSON_USER_OTHERS)
@@ -560,7 +562,8 @@
                         .setMaxSuggestions(3)
                         .build();
 
-        ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
+        TextClassifier classifier = new TextClassifierImpl(context, TC_CONSTANTS);
+        ConversationActions conversationActions = classifier.suggestConversationActions(request);
 
         Truth.assertThat(conversationActions.getConversationActions()).isEmpty();
     }
diff --git a/core/tests/coretests/src/android/widget/EditorTouchStateTest.java b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
new file mode 100644
index 0000000..6d50e3a
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
@@ -0,0 +1,229 @@
+/*
+ * 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.widget;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+import android.view.InputDevice;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+import android.widget.EditorTouchState.MultiTapStatus;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+@SmallTest
+public class EditorTouchStateTest {
+
+    private EditorTouchState mTouchState;
+    private ViewConfiguration mConfig;
+
+    @Before
+    public void before() throws Exception {
+        mTouchState = new EditorTouchState();
+        mConfig = new ViewConfiguration();
+    }
+
+    @Test
+    public void testUpdate_singleTap() throws Exception {
+        // Simulate an ACTION_DOWN event.
+        long event1Time = 1000;
+        MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f);
+        mTouchState.update(event1, mConfig);
+        assertSingleTap(mTouchState, 20f, 30f, 0, 0);
+
+        // Simulate an ACTION_UP event.
+        long event2Time = 1001;
+        MotionEvent event2 = upEvent(event1Time, event2Time, 20f, 30f);
+        mTouchState.update(event2, mConfig);
+        assertSingleTap(mTouchState, 20f, 30f, 20f, 30f);
+
+        // Generate an ACTION_DOWN event whose time is after the double-tap timeout.
+        long event3Time = event2Time + ViewConfiguration.getDoubleTapTimeout() + 1;
+        MotionEvent event3 = downEvent(event3Time, event3Time, 22f, 33f);
+        mTouchState.update(event3, mConfig);
+        assertSingleTap(mTouchState, 22f, 33f, 20f, 30f);
+    }
+
+    @Test
+    public void testUpdate_doubleTap_sameArea() throws Exception {
+        // Simulate an ACTION_DOWN event.
+        long event1Time = 1000;
+        MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f);
+        mTouchState.update(event1, mConfig);
+        assertSingleTap(mTouchState, 20f, 30f, 0, 0);
+
+        // Simulate an ACTION_UP event.
+        long event2Time = 1001;
+        MotionEvent event2 = upEvent(event1Time, event2Time, 20f, 30f);
+        mTouchState.update(event2, mConfig);
+        assertSingleTap(mTouchState, 20f, 30f, 20f, 30f);
+
+        // Generate an ACTION_DOWN event whose time is within the double-tap timeout.
+        long event3Time = 1002;
+        MotionEvent event3 = downEvent(event3Time, event3Time, 22f, 33f);
+        mTouchState.update(event3, mConfig);
+        assertTap(mTouchState, 22f, 33f, 20f, 30f,
+                MultiTapStatus.DOUBLE_TAP, true);
+    }
+
+    @Test
+    public void testUpdate_doubleTap_notSameArea() throws Exception {
+        // Simulate an ACTION_DOWN event.
+        long event1Time = 1000;
+        MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f);
+        mTouchState.update(event1, mConfig);
+        assertSingleTap(mTouchState, 20f, 30f, 0, 0);
+
+        // Simulate an ACTION_UP event.
+        long event2Time = 1001;
+        MotionEvent event2 = upEvent(event1Time, event2Time, 20f, 30f);
+        mTouchState.update(event2, mConfig);
+        assertSingleTap(mTouchState, 20f, 30f, 20f, 30f);
+
+        // Generate an ACTION_DOWN event whose time is within the double-tap timeout.
+        long event3Time = 1002;
+        MotionEvent event3 = downEvent(event3Time, event3Time, 200f, 300f);
+        mTouchState.update(event3, mConfig);
+        assertTap(mTouchState, 200f, 300f, 20f, 30f,
+                MultiTapStatus.DOUBLE_TAP, false);
+
+        // Simulate an ACTION_UP event.
+        long event4Time = 1003;
+        MotionEvent event4 = upEvent(event3Time, event4Time, 200f, 300f);
+        mTouchState.update(event4, mConfig);
+        assertTap(mTouchState, 200f, 300f, 200f, 300f,
+                MultiTapStatus.DOUBLE_TAP, false);
+    }
+
+    @Test
+    public void testUpdate_tripleClick_mouse() throws Exception {
+        // Simulate an ACTION_DOWN event.
+        long event1Time = 1000;
+        MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f);
+        event1.setSource(InputDevice.SOURCE_MOUSE);
+        mTouchState.update(event1, mConfig);
+        assertSingleTap(mTouchState, 20f, 30f, 0, 0);
+
+        // Simulate an ACTION_UP event.
+        long event2Time = 1001;
+        MotionEvent event2 = upEvent(event1Time, event2Time, 20f, 30f);
+        event2.setSource(InputDevice.SOURCE_MOUSE);
+        mTouchState.update(event2, mConfig);
+        assertSingleTap(mTouchState, 20f, 30f, 20f, 30f);
+
+        // Generate a second ACTION_DOWN event whose time is within the double-tap timeout.
+        long event3Time = 1002;
+        MotionEvent event3 = downEvent(event3Time, event3Time, 21f, 31f);
+        event3.setSource(InputDevice.SOURCE_MOUSE);
+        mTouchState.update(event3, mConfig);
+        assertTap(mTouchState, 21f, 31f, 20f, 30f,
+                MultiTapStatus.DOUBLE_TAP, true);
+
+        // Simulate an ACTION_UP event.
+        long event4Time = 1003;
+        MotionEvent event4 = upEvent(event3Time, event4Time, 21f, 31f);
+        event4.setSource(InputDevice.SOURCE_MOUSE);
+        mTouchState.update(event4, mConfig);
+        assertTap(mTouchState, 21f, 31f, 21f, 31f,
+                MultiTapStatus.DOUBLE_TAP, true);
+
+        // Generate a third ACTION_DOWN event whose time is within the double-tap timeout.
+        long event5Time = 1004;
+        MotionEvent event5 = downEvent(event5Time, event5Time, 22f, 32f);
+        event5.setSource(InputDevice.SOURCE_MOUSE);
+        mTouchState.update(event5, mConfig);
+        assertTap(mTouchState, 22f, 32f, 21f, 31f,
+                MultiTapStatus.TRIPLE_CLICK, true);
+    }
+
+    @Test
+    public void testUpdate_tripleClick_touch() throws Exception {
+        // Simulate an ACTION_DOWN event.
+        long event1Time = 1000;
+        MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f);
+        mTouchState.update(event1, mConfig);
+        assertSingleTap(mTouchState, 20f, 30f, 0, 0);
+
+        // Simulate an ACTION_UP event.
+        long event2Time = 1001;
+        MotionEvent event2 = upEvent(event1Time, event2Time, 20f, 30f);
+        mTouchState.update(event2, mConfig);
+        assertSingleTap(mTouchState, 20f, 30f, 20f, 30f);
+
+        // Generate a second ACTION_DOWN event whose time is within the double-tap timeout.
+        long event3Time = 1002;
+        MotionEvent event3 = downEvent(event3Time, event3Time, 21f, 31f);
+        mTouchState.update(event3, mConfig);
+        assertTap(mTouchState, 21f, 31f, 20f, 30f,
+                MultiTapStatus.DOUBLE_TAP, true);
+
+        // Simulate an ACTION_UP event.
+        long event4Time = 1003;
+        MotionEvent event4 = upEvent(event3Time, event4Time, 21f, 31f);
+        mTouchState.update(event4, mConfig);
+        assertTap(mTouchState, 21f, 31f, 21f, 31f,
+                MultiTapStatus.DOUBLE_TAP, true);
+
+        // Generate a third ACTION_DOWN event whose time is within the double-tap timeout.
+        long event5Time = 1004;
+        MotionEvent event5 = downEvent(event5Time, event5Time, 22f, 32f);
+        mTouchState.update(event5, mConfig);
+        assertTap(mTouchState, 22f, 32f, 21f, 31f,
+                MultiTapStatus.FIRST_TAP, false);
+    }
+
+    private static MotionEvent downEvent(long downTime, long eventTime, float x, float y) {
+        return MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
+    }
+
+    private static MotionEvent upEvent(long downTime, long eventTime, float x, float y) {
+        return MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
+    }
+
+    private static void assertSingleTap(EditorTouchState touchState, float lastDownX,
+            float lastDownY, float lastUpX, float lastUpY) {
+        assertThat(touchState.getLastDownX(), is(lastDownX));
+        assertThat(touchState.getLastDownY(), is(lastDownY));
+        assertThat(touchState.getLastUpX(), is(lastUpX));
+        assertThat(touchState.getLastUpY(), is(lastUpY));
+        assertThat(touchState.isDoubleTap(), is(false));
+        assertThat(touchState.isTripleClick(), is(false));
+        assertThat(touchState.isMultiTap(), is(false));
+        assertThat(touchState.isMultiTapInSameArea(), is(false));
+    }
+
+    private static void assertTap(EditorTouchState touchState,
+            float lastDownX, float lastDownY, float lastUpX, float lastUpY,
+            @MultiTapStatus int multiTapStatus, boolean isMultiTapInSameArea) {
+        assertThat(touchState.getLastDownX(), is(lastDownX));
+        assertThat(touchState.getLastDownY(), is(lastDownY));
+        assertThat(touchState.getLastUpX(), is(lastUpX));
+        assertThat(touchState.getLastUpY(), is(lastUpY));
+        assertThat(touchState.isDoubleTap(), is(multiTapStatus == MultiTapStatus.DOUBLE_TAP));
+        assertThat(touchState.isTripleClick(), is(multiTapStatus == MultiTapStatus.TRIPLE_CLICK));
+        assertThat(touchState.isMultiTap(), is(multiTapStatus == MultiTapStatus.DOUBLE_TAP
+                || multiTapStatus == MultiTapStatus.TRIPLE_CLICK));
+        assertThat(touchState.isMultiTapInSameArea(), is(isMultiTapInSameArea));
+    }
+}
diff --git a/core/tests/systemproperties/src/android/os/PropertyInvalidatedCacheTest.java b/core/tests/systemproperties/src/android/os/PropertyInvalidatedCacheTest.java
new file mode 100644
index 0000000..c4080e8
--- /dev/null
+++ b/core/tests/systemproperties/src/android/os/PropertyInvalidatedCacheTest.java
@@ -0,0 +1,168 @@
+/*
+ * 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.os;
+
+import android.app.PropertyInvalidatedCache;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+public class PropertyInvalidatedCacheTest extends TestCase {
+    private static final String KEY = "sys.testkey";
+    private static final String UNSET_KEY = "Aiw7woh6ie4toh7W";
+
+    private static class TestCache extends PropertyInvalidatedCache<Integer, String> {
+        TestCache() {
+            this(KEY);
+        }
+
+        TestCache(String key) {
+            super(4, key);
+        }
+
+        @Override
+        protected String recompute(Integer qv) {
+            mRecomputeCount += 1;
+            return "foo" + qv.toString();
+        }
+
+        int getRecomputeCount() {
+            return mRecomputeCount;
+        }
+
+        private int mRecomputeCount = 0;
+    }
+
+    @Override
+    protected void setUp() {
+        SystemProperties.set(KEY, "");
+    }
+
+    @SmallTest
+    public void testCacheRecompute() throws Exception {
+        TestCache cache = new TestCache();
+        cache.invalidateCache();
+        assertEquals("foo5", cache.query(5));
+        assertEquals(1, cache.getRecomputeCount());
+        assertEquals("foo5", cache.query(5));
+        assertEquals(1, cache.getRecomputeCount());
+        assertEquals("foo6", cache.query(6));
+        assertEquals(2, cache.getRecomputeCount());
+        cache.invalidateCache();
+        assertEquals("foo5", cache.query(5));
+        assertEquals("foo5", cache.query(5));
+        assertEquals(3, cache.getRecomputeCount());
+    }
+
+    @SmallTest
+    public void testCacheInitialState() throws Exception {
+        TestCache cache = new TestCache();
+        assertEquals("foo5", cache.query(5));
+        assertEquals("foo5", cache.query(5));
+        assertEquals(2, cache.getRecomputeCount());
+        cache.invalidateCache();
+        assertEquals("foo5", cache.query(5));
+        assertEquals("foo5", cache.query(5));
+        assertEquals(3, cache.getRecomputeCount());
+    }
+
+    @SmallTest
+    public void testCachePropertyUnset() throws Exception {
+        TestCache cache = new TestCache(UNSET_KEY);
+        assertEquals("foo5", cache.query(5));
+        assertEquals("foo5", cache.query(5));
+        assertEquals(2, cache.getRecomputeCount());
+    }
+
+    @SmallTest
+    public void testCacheDisableState() throws Exception {
+        TestCache cache = new TestCache();
+        assertEquals("foo5", cache.query(5));
+        assertEquals("foo5", cache.query(5));
+        assertEquals(2, cache.getRecomputeCount());
+        cache.invalidateCache();
+        assertEquals("foo5", cache.query(5));
+        assertEquals("foo5", cache.query(5));
+        assertEquals(3, cache.getRecomputeCount());
+        cache.disableSystemWide();
+        assertEquals("foo5", cache.query(5));
+        assertEquals("foo5", cache.query(5));
+        assertEquals(5, cache.getRecomputeCount());
+        cache.invalidateCache();  // Should not reenable
+        assertEquals("foo5", cache.query(5));
+        assertEquals("foo5", cache.query(5));
+        assertEquals(7, cache.getRecomputeCount());
+    }
+
+    @SmallTest
+    public void testRefreshSameObject() throws Exception {
+        int[] refreshCount = new int[1];
+        TestCache cache = new TestCache() {
+            @Override
+            protected String refresh(String oldResult, Integer query) {
+                refreshCount[0] += 1;
+                return oldResult;
+            }
+        };
+        cache.invalidateCache();
+        String result1 = cache.query(5);
+        assertEquals("foo5", result1);
+        String result2 = cache.query(5);
+        assertSame(result1, result2);
+        assertEquals(1, cache.getRecomputeCount());
+        assertEquals(1, refreshCount[0]);
+        assertEquals("foo5", cache.query(5));
+        assertEquals(2, refreshCount[0]);
+    }
+
+    @SmallTest
+    public void testRefreshInvalidateRace() throws Exception {
+        int[] refreshCount = new int[1];
+        TestCache cache = new TestCache() {
+            @Override
+            protected String refresh(String oldResult, Integer query) {
+                refreshCount[0] += 1;
+                invalidateCache();
+                return new String(oldResult);
+            }
+        };
+        cache.invalidateCache();
+        String result1 = cache.query(5);
+        assertEquals("foo5", result1);
+        String result2 = cache.query(5);
+        assertEquals(result1, result2);
+        assertNotSame(result1, result2);
+        assertEquals(2, cache.getRecomputeCount());
+    }
+
+    @SmallTest
+    public void testLocalProcessDisable() throws Exception {
+        TestCache cache = new TestCache();
+        cache.invalidateCache();
+        assertEquals("foo5", cache.query(5));
+        assertEquals(1, cache.getRecomputeCount());
+        assertEquals("foo5", cache.query(5));
+        assertEquals(1, cache.getRecomputeCount());
+        assertEquals(cache.isDisabledLocal(), false);
+        cache.disableLocal();
+        assertEquals(cache.isDisabledLocal(), true);
+        assertEquals("foo5", cache.query(5));
+        assertEquals("foo5", cache.query(5));
+        assertEquals(3, cache.getRecomputeCount());
+    }
+
+}
diff --git a/core/tests/utiltests/AndroidManifest.xml b/core/tests/utiltests/AndroidManifest.xml
index 4ef4b1f..8e0f1d2 100644
--- a/core/tests/utiltests/AndroidManifest.xml
+++ b/core/tests/utiltests/AndroidManifest.xml
@@ -30,7 +30,6 @@
 
     <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
     <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
-    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.MANAGE_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index dd4f238c..ff521be 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -73,7 +73,7 @@
 
 prebuilt_etc {
     name: "privapp_whitelist_com.android.emergency",
-    product_specific: true,
+    system_ext_specific: true,
     sub_dir: "permissions",
     src: "com.android.emergency.xml",
     filename_from_src: true,
@@ -96,7 +96,7 @@
 
 prebuilt_etc {
     name: "privapp_whitelist_com.android.provision",
-    product_specific: true,
+    system_ext_specific: true,
     sub_dir: "permissions",
     src: "com.android.provision.xml",
     filename_from_src: true,
@@ -104,7 +104,7 @@
 
 prebuilt_etc {
     name: "privapp_whitelist_com.android.settings",
-    product_specific: true,
+    system_ext_specific: true,
     sub_dir: "permissions",
     src: "com.android.settings.xml",
     filename_from_src: true,
diff --git a/data/etc/CleanSpec.mk b/data/etc/CleanSpec.mk
index be10a2c..3fe421e 100644
--- a/data/etc/CleanSpec.mk
+++ b/data/etc/CleanSpec.mk
@@ -45,6 +45,12 @@
 #$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.carrierconfig.xml)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.carrierconfig.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.emergency.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.emergency.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.provision.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.provision.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.settings.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.settings.xml)
 # ******************************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
 # ******************************************************************
diff --git a/data/etc/preinstalled-packages-platform.xml b/data/etc/preinstalled-packages-platform.xml
index 10fc59d..604b407 100644
--- a/data/etc/preinstalled-packages-platform.xml
+++ b/data/etc/preinstalled-packages-platform.xml
@@ -17,7 +17,7 @@
 <!--
 This XML file declares which system packages should be initially installed for new users based on
 their user type. All system packages on the device should ideally have an entry in an xml file
-(keys by its manifest name).
+(keyed by its manifest name).
 
 Base user-types (every user will be at least one of these types) are:
   SYSTEM    (user 0)
@@ -46,7 +46,7 @@
 1. For a system package to be pre-installed only in user 0:
 
    <install-in-user-type package="com.android.example">
-       <install-in user-type="SYSTEM">
+       <install-in user-type="SYSTEM" />
    </install-in-user-type>
 
 
@@ -54,8 +54,8 @@
 installed on any user of type type FULL or PROFILE (since this covers all human users):
 
    <install-in-user-type package="com.android.example">
-       <install-in user-type="FULL">
-       <install-in user-type="PROFILE">
+       <install-in user-type="FULL" />
+       <install-in user-type="PROFILE" />
    </install-in-user-type>
 
 
@@ -63,22 +63,22 @@
 wallpaper app, since profiles cannot display wallpaper):
 
    <install-in-user-type package="com.android.example">
-       <install-in user-type="FULL">
+       <install-in user-type="FULL" />
    </install-in-user-type>
 
 
 Some system packages truly are required to be on all users, regardless of type, in which case use:
    <install-in-user-type package="com.android.example">
        <install-in user-type="SYSTEM">
-       <install-in user-type="FULL">
-       <install-in user-type="PROFILE">
+       <install-in user-type="FULL" />
+       <install-in user-type="PROFILE" />
    </install-in-user-type>
 
 More fine-grained options are also available by specifying individual user types.
 E.g.
    <install-in-user-type package="com.android.example">
-       <install-in user-type="android.os.usertype.profile.MANAGED">
-       <install-in user-type="android.os.usertype.full.GUEST">
+       <install-in user-type="android.os.usertype.profile.MANAGED" />
+       <install-in user-type="android.os.usertype.full.GUEST" />
        <install-in user-type="SYSTEM">
    </install-in-user-type>
 which installs this package on any user whose user type is a managed profile or a guest, or is of
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index f2a6452..322cbd7 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -204,7 +204,7 @@
         <permission name="android.permission.UPDATE_DEVICE_STATS"/>
     </privapp-permissions>
 
-    <privapp-permissions package="com.android.providers.media">
+    <privapp-permissions package="com.android.providers.media.module">
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
         <permission name="android.permission.MANAGE_USERS"/>
         <permission name="android.permission.USE_RESERVED_DISK"/>
@@ -339,8 +339,10 @@
         <permission name="android.permission.SYSTEM_CAMERA" />
         <!-- Permission required to test ExplicitHealthCheckServiceImpl. -->
         <permission name="android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE"/>
-        <!-- Permission required for UiModeManager cts test. -->
+        <!-- Permission required for UiModeManager CTS test. -->
         <permission name="android.permission.ENTER_CAR_MODE_PRIORITIZED"/>
+        <!-- Permission required for Telecom car mode CTS tests. -->
+        <permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
@@ -367,4 +369,7 @@
         <permission name="android.permission.REBOOT"/>
         <permission name="android.permission.MANAGE_DYNAMIC_SYSTEM"/>
     </privapp-permissions>
+    <privapp-permissions package="com.android.settings">
+        <permission name="android.permission.INSTALL_DYNAMIC_SYSTEM"/>
+    </privapp-permissions>
 </permissions>
diff --git a/data/sounds/AudioPackageGo.mk b/data/sounds/AudioPackageGo.mk
index e3b27f2..e3fb45f 100644
--- a/data/sounds/AudioPackageGo.mk
+++ b/data/sounds/AudioPackageGo.mk
@@ -47,3 +47,7 @@
     $(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \
     $(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \
     $(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \
+    $(LOCAL_PATH)/effects/ogg/Lock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \
+    $(LOCAL_PATH)/effects/ogg/Unlock.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \
+    $(LOCAL_PATH)/effects/ogg/Trusted_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \
+
diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java
index fcebad3..041300c 100644
--- a/drm/java/android/drm/DrmManagerClient.java
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -16,6 +16,7 @@
 
 package android.drm;
 
+import android.annotation.NonNull;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
@@ -37,6 +38,8 @@
 import java.io.IOException;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -370,6 +373,17 @@
     }
 
     /**
+     * Retrieves information about all the DRM plug-ins (agents) that are
+     * registered with the DRM framework.
+     *
+     * @return List of all the DRM plug-ins (agents) that are registered with
+     *         the DRM framework.
+     */
+    public @NonNull Collection<DrmSupportInfo> getAvailableDrmSupportInfo() {
+        return Arrays.asList(_getAllSupportInfo(mUniqueId));
+    }
+
+    /**
      * Retrieves constraint information for rights-protected content.
      *
      * @param path Path to the content from which you are retrieving DRM constraints.
diff --git a/graphics/java/android/graphics/Point.java b/graphics/java/android/graphics/Point.java
index 3614f3b..9f71a0f 100644
--- a/graphics/java/android/graphics/Point.java
+++ b/graphics/java/android/graphics/Point.java
@@ -132,7 +132,7 @@
      * @param fieldId           Field Id of the Rect as defined in the parent message
      * @hide
      */
-    public void writeToProto(@NonNull ProtoOutputStream protoOutputStream, long fieldId) {
+    public void dumpDebug(@NonNull ProtoOutputStream protoOutputStream, long fieldId) {
         final long token = protoOutputStream.start(fieldId);
         protoOutputStream.write(PointProto.X, x);
         protoOutputStream.write(PointProto.Y, y);
diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java
index d47f682..9e1946c 100644
--- a/graphics/java/android/graphics/Rect.java
+++ b/graphics/java/android/graphics/Rect.java
@@ -239,7 +239,7 @@
      * @param fieldId           Field Id of the Rect as defined in the parent message
      * @hide
      */
-    public void writeToProto(@NonNull ProtoOutputStream protoOutputStream, long fieldId) {
+    public void dumpDebug(@NonNull ProtoOutputStream protoOutputStream, long fieldId) {
         final long token = protoOutputStream.start(fieldId);
         protoOutputStream.write(RectProto.LEFT, left);
         protoOutputStream.write(RectProto.TOP, top);
diff --git a/graphics/java/android/graphics/RuntimeShader.java b/graphics/java/android/graphics/RuntimeShader.java
new file mode 100644
index 0000000..613ce90
--- /dev/null
+++ b/graphics/java/android/graphics/RuntimeShader.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import libcore.util.NativeAllocationRegistry;
+
+/**
+ * Shader that calculates pixel output with a program (fragment shader) running on a GPU.
+ * @hide
+ */
+public class RuntimeShader extends Shader {
+
+    private static class NoImagePreloadHolder {
+        public static final NativeAllocationRegistry sRegistry =
+                NativeAllocationRegistry.createMalloced(
+                RuntimeShader.class.getClassLoader(), nativeGetFinalizer());
+    }
+
+    private byte[] mUniforms;
+
+    /**
+     * Current native shader factory instance.
+     */
+    private long mNativeInstanceRuntimeShaderFactory;
+
+    /**
+     * Creates a new RuntimeShader.
+     *
+     * @param sksl The text of SKSL program to run on the GPU.
+     * @param uniforms Array of parameters passed by the SKSL shader. Array size depends
+     *                 on number of uniforms declared by sksl.
+     * @param isOpaque True if all pixels have alpha 1.0f.
+     */
+    public RuntimeShader(@NonNull String sksl, @Nullable byte[] uniforms, boolean isOpaque) {
+        this(sksl, uniforms, isOpaque, ColorSpace.get(ColorSpace.Named.SRGB));
+    }
+
+    private RuntimeShader(@NonNull String sksl, @Nullable byte[] uniforms, boolean isOpaque,
+            ColorSpace colorSpace) {
+        super(colorSpace);
+        mUniforms = uniforms;
+        mNativeInstanceRuntimeShaderFactory = nativeCreateShaderFactory(sksl, isOpaque);
+        NoImagePreloadHolder.sRegistry.registerNativeAllocation(this,
+                mNativeInstanceRuntimeShaderFactory);
+    }
+
+    /**
+     * Sets new value for shader parameters.
+     *
+     * @param uniforms Array of parameters passed by the SKSL shader. Array size depends
+     *                 on number of uniforms declared by mSksl.
+     */
+    public void updateUniforms(@Nullable byte[] uniforms) {
+        mUniforms = uniforms;
+        discardNativeInstance();
+    }
+
+    @Override
+    long createNativeInstance(long nativeMatrix) {
+        return nativeCreate(mNativeInstanceRuntimeShaderFactory, nativeMatrix, mUniforms,
+                colorSpace().getNativeInstance());
+    }
+
+    private static native long nativeCreate(long shaderFactory, long matrix, byte[] inputs,
+            long colorSpaceHandle);
+
+    private static native long nativeCreateShaderFactory(String sksl, boolean isOpaque);
+
+    private static native long nativeGetFinalizer();
+}
+
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index f25910b..572fa8c 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -68,6 +68,9 @@
     /** Key prefix for WIFI. */
     public static final String WIFI = "WIFI_";
 
+    /** Key prefix for App Source certificates. */
+    public static final String APP_SOURCE_CERTIFICATE = "FSV_";
+
     /** Key containing suffix of lockdown VPN profile. */
     public static final String LOCKDOWN_VPN = "LOCKDOWN_VPN";
 
@@ -80,6 +83,9 @@
     /** Name of WIFI certificate usage. */
     public static final String CERTIFICATE_USAGE_WIFI = "wifi";
 
+    /** Name of App Source certificate usage. */
+    public static final String CERTIFICATE_USAGE_APP_SOURCE = "appsrc";
+
     /** Data type for public keys. */
     public static final String EXTRA_PUBLIC_KEY = "KEY";
 
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 4f52a88..8765719 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -67,7 +67,6 @@
                 "BackupData.cpp",
                 "BackupHelpers.cpp",
                 "CursorWindow.cpp",
-                "DisplayEventDispatcher.cpp",
             ],
             shared_libs: [
                 "libziparchive",
@@ -75,7 +74,6 @@
                 "libbinder",
                 "liblog",
                 "libcutils",
-                "libgui",
                 "libutils",
                 "libz",
             ],
diff --git a/libs/androidfw/DisplayEventDispatcher.cpp b/libs/androidfw/DisplayEventDispatcher.cpp
deleted file mode 100644
index d8a3f426..0000000
--- a/libs/androidfw/DisplayEventDispatcher.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#define LOG_TAG "DisplayEventDispatcher"
-
-#include <cinttypes>
-#include <cstdint>
-
-#include <androidfw/DisplayEventDispatcher.h>
-#include <gui/DisplayEventReceiver.h>
-#include <utils/Log.h>
-#include <utils/Looper.h>
-
-#include <utils/Timers.h>
-
-namespace android {
-
-// Number of events to read at a time from the DisplayEventDispatcher pipe.
-// The value should be large enough that we can quickly drain the pipe
-// using just a few large reads.
-static const size_t EVENT_BUFFER_SIZE = 100;
-
-DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper,
-        ISurfaceComposer::VsyncSource vsyncSource,
-        ISurfaceComposer::ConfigChanged configChanged) :
-        mLooper(looper), mReceiver(vsyncSource, configChanged), mWaitingForVsync(false) {
-    ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
-}
-
-status_t DisplayEventDispatcher::initialize() {
-    status_t result = mReceiver.initCheck();
-    if (result) {
-        ALOGW("Failed to initialize display event receiver, status=%d", result);
-        return result;
-    }
-
-    int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT,
-            this, NULL);
-    if (rc < 0) {
-        return UNKNOWN_ERROR;
-    }
-    return OK;
-}
-
-void DisplayEventDispatcher::dispose() {
-    ALOGV("dispatcher %p ~ Disposing display event dispatcher.", this);
-
-    if (!mReceiver.initCheck()) {
-        mLooper->removeFd(mReceiver.getFd());
-    }
-}
-
-status_t DisplayEventDispatcher::scheduleVsync() {
-    if (!mWaitingForVsync) {
-        ALOGV("dispatcher %p ~ Scheduling vsync.", this);
-
-        // Drain all pending events.
-        nsecs_t vsyncTimestamp;
-        PhysicalDisplayId vsyncDisplayId;
-        uint32_t vsyncCount;
-        if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
-            ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "",
-                    this, ns2ms(static_cast<nsecs_t>(vsyncTimestamp)));
-        }
-
-        status_t status = mReceiver.requestNextVsync();
-        if (status) {
-            ALOGW("Failed to request next vsync, status=%d", status);
-            return status;
-        }
-
-        mWaitingForVsync = true;
-    }
-    return OK;
-}
-
-int DisplayEventDispatcher::handleEvent(int, int events, void*) {
-    if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
-        ALOGE("Display event receiver pipe was closed or an error occurred.  "
-                "events=0x%x", events);
-        return 0; // remove the callback
-    }
-
-    if (!(events & Looper::EVENT_INPUT)) {
-        ALOGW("Received spurious callback for unhandled poll event.  "
-                "events=0x%x", events);
-        return 1; // keep the callback
-    }
-
-    // Drain all pending events, keep the last vsync.
-    nsecs_t vsyncTimestamp;
-    PhysicalDisplayId vsyncDisplayId;
-    uint32_t vsyncCount;
-    if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
-        ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64 ", displayId=%"
-                ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", count=%d",
-                this, ns2ms(vsyncTimestamp), vsyncDisplayId, vsyncCount);
-        mWaitingForVsync = false;
-        dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
-    }
-
-    return 1; // keep the callback
-}
-
-bool DisplayEventDispatcher::processPendingEvents(
-        nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId, uint32_t* outCount) {
-    bool gotVsync = false;
-    DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
-    ssize_t n;
-    while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
-        ALOGV("dispatcher %p ~ Read %d events.", this, int(n));
-        for (ssize_t i = 0; i < n; i++) {
-            const DisplayEventReceiver::Event& ev = buf[i];
-            switch (ev.header.type) {
-            case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
-                // Later vsync events will just overwrite the info from earlier
-                // ones. That's fine, we only care about the most recent.
-                gotVsync = true;
-                *outTimestamp = ev.header.timestamp;
-                *outDisplayId = ev.header.displayId;
-                *outCount = ev.vsync.count;
-                break;
-            case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
-                dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected);
-                break;
-            case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
-                dispatchConfigChanged(ev.header.timestamp, ev.header.displayId, ev.config.configId);
-                break;
-            default:
-                ALOGW("dispatcher %p ~ ignoring unknown event type %#x", this, ev.header.type);
-                break;
-            }
-        }
-    }
-    if (n < 0) {
-        ALOGW("Failed to get events from display event dispatcher, status=%d", status_t(n));
-    }
-    return gotVsync;
-}
-}
diff --git a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h b/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
deleted file mode 100644
index 8bc2520..0000000
--- a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#include <gui/DisplayEventReceiver.h>
-#include <utils/Log.h>
-#include <utils/Looper.h>
-
-namespace android {
-
-class DisplayEventDispatcher : public LooperCallback {
-public:
-    explicit DisplayEventDispatcher(const sp<Looper>& looper,
-            ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp,
-            ISurfaceComposer::ConfigChanged configChanged = ISurfaceComposer::eConfigChangedSuppress);
-
-    status_t initialize();
-    void dispose();
-    status_t scheduleVsync();
-
-protected:
-    virtual ~DisplayEventDispatcher() = default;
-
-private:
-    sp<Looper> mLooper;
-    DisplayEventReceiver mReceiver;
-    bool mWaitingForVsync;
-
-    virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) = 0;
-    virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId,
-                                 bool connected) = 0;
-    virtual void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
-                                       int32_t configId) = 0;
-
-    virtual int handleEvent(int receiveFd, int events, void* data);
-    bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId,
-                              uint32_t* outCount);
-};
-}
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 217b0c4..cd908354 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -135,8 +135,7 @@
     bool setFillPath = properties.getFillGradient() != nullptr ||
                        properties.getFillColor() != SK_ColorTRANSPARENT;
     if (setFillPath) {
-        SkPath::FillType ft = static_cast<SkPath::FillType>(properties.getFillType());
-        outPath->setFillType(ft);
+        outPath->setFillType(static_cast<SkPathFillType>(properties.getFillType()));
     }
     return *outPath;
 }
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index 9013a96..70abbb3 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -16,9 +16,11 @@
 
 package android.location;
 
+import android.annotation.FloatRange;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.TestApi;
+import android.hardware.gnss.V1_0.IGnssMeasurementCallback.GnssMeasurementFlags;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -37,6 +39,7 @@
     private long mReceivedSvTimeNanos;
     private long mReceivedSvTimeUncertaintyNanos;
     private double mCn0DbHz;
+    private double mBasebandCn0DbHz;
     private double mPseudorangeRateMetersPerSecond;
     private double mPseudorangeRateUncertaintyMetersPerSecond;
     private int mAccumulatedDeltaRangeState;
@@ -51,16 +54,20 @@
     private double mAutomaticGainControlLevelInDb;
     @NonNull private String mCodeType;
 
-    // The following enumerations must be in sync with the values declared in gps.h
+    // The following enumerations must be in sync with the values declared in GNSS HAL.
 
     private static final int HAS_NO_FLAGS = 0;
-    private static final int HAS_SNR = (1<<0);
-    private static final int HAS_CARRIER_FREQUENCY = (1<<9);
-    private static final int HAS_CARRIER_CYCLES = (1<<10);
-    private static final int HAS_CARRIER_PHASE = (1<<11);
-    private static final int HAS_CARRIER_PHASE_UNCERTAINTY = (1<<12);
-    private static final int HAS_AUTOMATIC_GAIN_CONTROL = (1<<13);
+    private static final int HAS_SNR = GnssMeasurementFlags.HAS_SNR;
+    private static final int HAS_CARRIER_FREQUENCY = GnssMeasurementFlags.HAS_CARRIER_FREQUENCY;
+    private static final int HAS_CARRIER_CYCLES = GnssMeasurementFlags.HAS_CARRIER_CYCLES;
+    private static final int HAS_CARRIER_PHASE = GnssMeasurementFlags.HAS_CARRIER_PHASE;
+    private static final int HAS_CARRIER_PHASE_UNCERTAINTY =
+            GnssMeasurementFlags.HAS_CARRIER_PHASE_UNCERTAINTY;
+    private static final int HAS_AUTOMATIC_GAIN_CONTROL =
+            GnssMeasurementFlags.HAS_AUTOMATIC_GAIN_CONTROL;
+
     private static final int HAS_CODE_TYPE = (1 << 14);
+    private static final int HAS_BASEBAND_CN0 = (1 << 15);
 
     /**
      * The status of the multipath indicator.
@@ -240,6 +247,7 @@
         mReceivedSvTimeNanos = measurement.mReceivedSvTimeNanos;
         mReceivedSvTimeUncertaintyNanos = measurement.mReceivedSvTimeUncertaintyNanos;
         mCn0DbHz = measurement.mCn0DbHz;
+        mBasebandCn0DbHz = measurement.mBasebandCn0DbHz;
         mPseudorangeRateMetersPerSecond = measurement.mPseudorangeRateMetersPerSecond;
         mPseudorangeRateUncertaintyMetersPerSecond =
                 measurement.mPseudorangeRateUncertaintyMetersPerSecond;
@@ -788,6 +796,49 @@
     }
 
     /**
+     * Returns {@code true} if {@link #getBasebandCn0DbHz()} is available, {@code false} otherwise.
+     */
+    public boolean hasBasebandCn0DbHz() {
+        return isFlagSet(HAS_BASEBAND_CN0);
+    }
+
+    /**
+     * Gets the baseband carrier-to-noise density in dB-Hz.
+     *
+     * <p>Typical range: 0-50 dB-Hz.
+     *
+     * <p>The value contains the measured C/N0 for the signal at the baseband. This is typically
+     * a few dB weaker than the value estimated for C/N0 at the antenna port, which is reported
+     * in {@link #getCn0DbHz()}.
+     */
+    @FloatRange(from = 0, to = 50)
+    public double getBasebandCn0DbHz() {
+        return mBasebandCn0DbHz;
+    }
+
+    /**
+     * Sets the baseband carrier-to-noise density in dB-Hz.
+     *
+     * @hide
+     */
+    @TestApi
+    public void setBasebandCn0DbHz(double value) {
+        setFlag(HAS_BASEBAND_CN0);
+        mBasebandCn0DbHz = value;
+    }
+
+    /**
+     * Resets the baseband carrier-to-noise density in dB-Hz.
+     *
+     * @hide
+     */
+    @TestApi
+    public void resetBasebandCn0DbHz() {
+        resetFlag(HAS_BASEBAND_CN0);
+        mBasebandCn0DbHz = Double.NaN;
+    }
+
+    /**
      * Gets the Pseudorange rate at the timestamp in m/s.
      *
      * <p>The error estimate for this value is
@@ -1400,6 +1451,7 @@
             gnssMeasurement.mSnrInDb = parcel.readDouble();
             gnssMeasurement.mAutomaticGainControlLevelInDb = parcel.readDouble();
             gnssMeasurement.mCodeType = parcel.readString();
+            gnssMeasurement.mBasebandCn0DbHz = parcel.readDouble();
 
             return gnssMeasurement;
         }
@@ -1433,6 +1485,7 @@
         parcel.writeDouble(mSnrInDb);
         parcel.writeDouble(mAutomaticGainControlLevelInDb);
         parcel.writeString(mCodeType);
+        parcel.writeDouble(mBasebandCn0DbHz);
     }
 
     @Override
@@ -1461,6 +1514,9 @@
 
         builder.append(String.format(format, "Cn0DbHz", mCn0DbHz));
 
+        builder.append(String.format(format, "BasebandCn0DbHz",
+                hasBasebandCn0DbHz() ? mBasebandCn0DbHz : null));
+
         builder.append(String.format(
                 formatWithUncertainty,
                 "PseudorangeRateMetersPerSecond",
@@ -1536,6 +1592,7 @@
         resetSnrInDb();
         resetAutomaticGainControlLevel();
         resetCodeType();
+        resetBasebandCn0DbHz();
     }
 
     private void setFlag(int flag) {
diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java
index 2f1eeda..89a3bc0 100644
--- a/location/java/android/location/GnssStatus.java
+++ b/location/java/android/location/GnssStatus.java
@@ -34,7 +34,7 @@
  */
 public final class GnssStatus {
 
-    // these must match the definitions in gps.h
+    // These must match the definitions in GNSS HAL.
     //
     // Note: these constants are also duplicated in GnssStatusCompat.java in the androidx support
     // library. if adding a constellation, please update that file as well.
@@ -63,9 +63,10 @@
     private static final int SVID_FLAGS_HAS_ALMANAC_DATA = (1 << 1);
     private static final int SVID_FLAGS_USED_IN_FIX = (1 << 2);
     private static final int SVID_FLAGS_HAS_CARRIER_FREQUENCY = (1 << 3);
+    private static final int SVID_FLAGS_HAS_BASEBAND_CN0 = (1 << 4);
 
-    private static final int SVID_SHIFT_WIDTH = 8;
-    private static final int CONSTELLATION_TYPE_SHIFT_WIDTH = 4;
+    private static final int SVID_SHIFT_WIDTH = 12;
+    private static final int CONSTELLATION_TYPE_SHIFT_WIDTH = 8;
     private static final int CONSTELLATION_TYPE_MASK = 0xf;
 
     /**
@@ -123,9 +124,10 @@
      */
     @NonNull
     public static GnssStatus wrap(int svCount, int[] svidWithFlags, float[] cn0DbHzs,
-            float[] elevations, float[] azimuths, float[] carrierFrequencies) {
+            float[] elevations, float[] azimuths, float[] carrierFrequencies,
+            float[] basebandCn0DbHzs) {
         return new GnssStatus(svCount, svidWithFlags, cn0DbHzs, elevations, azimuths,
-                carrierFrequencies);
+                carrierFrequencies, basebandCn0DbHzs);
     }
 
     private final int mSvCount;
@@ -134,15 +136,17 @@
     private final float[] mElevations;
     private final float[] mAzimuths;
     private final float[] mCarrierFrequencies;
+    private final float[] mBasebandCn0DbHzs;
 
     private GnssStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs, float[] elevations,
-            float[] azimuths, float[] carrierFrequencies) {
+            float[] azimuths, float[] carrierFrequencies, float[] basebandCn0DbHzs) {
         mSvCount = svCount;
         mSvidWithFlags = svidWithFlags;
         mCn0DbHzs = cn0DbHzs;
         mElevations = elevations;
         mAzimuths = azimuths;
         mCarrierFrequencies = carrierFrequencies;
+        mBasebandCn0DbHzs = basebandCn0DbHzs;
     }
 
     /**
@@ -284,6 +288,26 @@
     }
 
     /**
+     * Reports whether a valid {@link #getBasebandCn0DbHz(int satelliteIndex)} is available.
+     *
+     * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1
+     */
+    public boolean hasBasebandCn0DbHz(@IntRange(from = 0) int satelliteIndex) {
+        return (mSvidWithFlags[satelliteIndex] & SVID_FLAGS_HAS_BASEBAND_CN0) != 0;
+    }
+
+    /**
+     * Retrieves the baseband carrier-to-noise density of the satellite at the specified index in
+     * dB-Hz.
+     *
+     * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1
+     */
+    @FloatRange(from = 0, to = 63)
+    public float getBasebandCn0DbHz(@IntRange(from = 0) int satelliteIndex) {
+        return mBasebandCn0DbHzs[satelliteIndex];
+    }
+
+    /**
      * Returns the string representation of a constellation type.
      *
      * @param constellationType the constellation type.
@@ -334,6 +358,8 @@
          * @param usedInFix whether the satellite was used in the most recent location fix
          * @param hasCarrierFrequency whether carrier frequency data is available
          * @param carrierFrequency satellite carrier frequency in Hz
+         * @param hasBasebandCn0DbHz whether baseband carrier-to-noise density is available
+         * @param basebandCn0DbHz baseband carrier-to-noise density in dB-Hz
          */
         @NonNull
         public Builder addSatellite(@ConstellationType int constellationType,
@@ -345,9 +371,12 @@
                 boolean hasAlmanac,
                 boolean usedInFix,
                 boolean hasCarrierFrequency,
-                @FloatRange(from = 0) float carrierFrequency) {
+                @FloatRange(from = 0) float carrierFrequency,
+                boolean hasBasebandCn0DbHz,
+                @FloatRange(from = 0, to = 63) float basebandCn0DbHz) {
             mSatellites.add(new GnssSvInfo(constellationType, svid, cn0DbHz, elevation, azimuth,
-                    hasEphemeris, hasAlmanac, usedInFix, hasCarrierFrequency, carrierFrequency));
+                    hasEphemeris, hasAlmanac, usedInFix, hasCarrierFrequency, carrierFrequency,
+                    hasBasebandCn0DbHz, basebandCn0DbHz));
             return this;
         }
 
@@ -371,6 +400,7 @@
             float[] elevations = new float[svCount];
             float[] azimuths = new float[svCount];
             float[] carrierFrequencies = new float[svCount];
+            float[] basebandCn0DbHzs = new float[svCount];
 
             for (int i = 0; i < svidWithFlags.length; i++) {
                 svidWithFlags[i] = mSatellites.get(i).mSvidWithFlags;
@@ -387,9 +417,12 @@
             for (int i = 0; i < carrierFrequencies.length; i++) {
                 carrierFrequencies[i] = mSatellites.get(i).mCarrierFrequency;
             }
+            for (int i = 0; i < basebandCn0DbHzs.length; i++) {
+                basebandCn0DbHzs[i] = mSatellites.get(i).mBasebandCn0DbHz;
+            }
 
             return wrap(svCount, svidWithFlags, cn0DbHzs, elevations, azimuths,
-                    carrierFrequencies);
+                    carrierFrequencies, basebandCn0DbHzs);
         }
     }
 
@@ -400,21 +433,25 @@
         private final float mElevation;
         private final float mAzimuth;
         private final float mCarrierFrequency;
+        private final float mBasebandCn0DbHz;
 
         private GnssSvInfo(int constellationType, int svid, float cn0DbHz,
                 float elevation, float azimuth, boolean hasEphemeris, boolean hasAlmanac,
-                boolean usedInFix, boolean hasCarrierFrequency, float carrierFrequency) {
+                boolean usedInFix, boolean hasCarrierFrequency, float carrierFrequency,
+                boolean hasBasebandCn0DbHz, float basebandCn0DbHz) {
             mSvidWithFlags = (svid << SVID_SHIFT_WIDTH)
                     | ((constellationType & CONSTELLATION_TYPE_MASK)
                     << CONSTELLATION_TYPE_SHIFT_WIDTH)
                     | (hasEphemeris ? SVID_FLAGS_HAS_EPHEMERIS_DATA : SVID_FLAGS_NONE)
                     | (hasAlmanac ? SVID_FLAGS_HAS_ALMANAC_DATA : SVID_FLAGS_NONE)
                     | (usedInFix ? SVID_FLAGS_USED_IN_FIX : SVID_FLAGS_NONE)
-                    | (hasCarrierFrequency ? SVID_FLAGS_HAS_CARRIER_FREQUENCY : SVID_FLAGS_NONE);
+                    | (hasCarrierFrequency ? SVID_FLAGS_HAS_CARRIER_FREQUENCY : SVID_FLAGS_NONE)
+                    | (hasBasebandCn0DbHz ? SVID_FLAGS_HAS_BASEBAND_CN0 : SVID_FLAGS_NONE);
             mCn0DbHz = cn0DbHz;
             mElevation = elevation;
             mAzimuth = azimuth;
             mCarrierFrequency = carrierFrequency;
+            mBasebandCn0DbHz = basebandCn0DbHz;
         }
     }
 }
diff --git a/location/java/android/location/IGnssStatusListener.aidl b/location/java/android/location/IGnssStatusListener.aidl
index d824cb1..1931a00 100644
--- a/location/java/android/location/IGnssStatusListener.aidl
+++ b/location/java/android/location/IGnssStatusListener.aidl
@@ -28,6 +28,6 @@
     void onFirstFix(int ttff);
     void onSvStatusChanged(int svCount, in int[] svidWithFlags, in float[] cn0s,
             in float[] elevations, in float[] azimuths,
-            in float[] carrierFreqs);
+            in float[] carrierFreqs, in float[] basebandCn0s);
     void onNmeaReceived(long timestamp, String nmea);
 }
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 4893496..5496148 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -165,25 +165,52 @@
      * Broadcast intent action when the set of enabled location providers changes. To check the
      * status of a provider, use {@link #isProviderEnabled(String)}. From Android Q and above, will
      * include a string intent extra, {@link #EXTRA_PROVIDER_NAME}, with the name of the provider
-     * whose state has changed.
+     * whose state has changed. From Android R and above, will include a boolean intent extra,
+     * {@link #EXTRA_PROVIDER_ENABLED}, with the enabled state of the provider.
      *
      * @see #EXTRA_PROVIDER_NAME
+     * @see #EXTRA_PROVIDER_ENABLED
+     * @see #isProviderEnabled(String)
      */
     public static final String PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED";
 
     /**
      * Intent extra included with {@link #PROVIDERS_CHANGED_ACTION} broadcasts, containing the name
-     * of the location provider that has changed, to be used with location provider APIs.
+     * of the location provider that has changed.
+     *
+     * @see #PROVIDERS_CHANGED_ACTION
+     * @see #EXTRA_PROVIDER_ENABLED
      */
     public static final String EXTRA_PROVIDER_NAME = "android.location.extra.PROVIDER_NAME";
 
     /**
-     * Broadcast intent action when the device location mode changes. To check the location mode,
-     * use {@link #isLocationEnabled()}.
+     * Intent extra included with {@link #PROVIDERS_CHANGED_ACTION} broadcasts, containing the
+     * boolean enabled state of the location provider that has changed.
+     *
+     * @see #PROVIDERS_CHANGED_ACTION
+     * @see #EXTRA_PROVIDER_NAME
+     */
+    public static final String EXTRA_PROVIDER_ENABLED = "android.location.extra.PROVIDER_ENABLED";
+
+    /**
+     * Broadcast intent action when the device location enabled state changes. From Android R and
+     * above, will include a boolean intent extra, {@link #EXTRA_LOCATION_ENABLED}, with the enabled
+     * state of location.
+     *
+     * @see #EXTRA_LOCATION_ENABLED
+     * @see #isLocationEnabled()
      */
     public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED";
 
     /**
+     * Intent extra included with {@link #MODE_CHANGED_ACTION} broadcasts, containing the boolean
+     * enabled state of location.
+     *
+     * @see #MODE_CHANGED_ACTION
+     */
+    public static final String EXTRA_LOCATION_ENABLED = "android.location.extra.LOCATION_ENABLED";
+
+    /**
      * Broadcast intent action indicating that a high power location requests
      * has either started or stopped being active.  The current state of
      * active location requests should be read from AppOpsManager using
@@ -2819,9 +2846,10 @@
 
             @Override
             public void onSvStatusChanged(int svCount, int[] svidWithFlags, float[] cn0s,
-                    float[] elevations, float[] azimuths, float[] carrierFreqs) {
+                    float[] elevations, float[] azimuths, float[] carrierFreqs,
+                    float[] basebandCn0s) {
                 GnssStatus localStatus = GnssStatus.wrap(svCount, svidWithFlags, cn0s,
-                        elevations, azimuths, carrierFreqs);
+                        elevations, azimuths, carrierFreqs, basebandCn0s);
                 mGnssStatus = localStatus;
                 execute((callback) -> callback.onSatelliteStatusChanged(localStatus));
             }
diff --git a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
index c20dc61..751bb6a 100644
--- a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
+++ b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
@@ -103,10 +103,6 @@
         mPositionAccuracyMeterStatistics = new Statistics();
         mTopFourAverageCn0Statistics = new Statistics();
         mTopFourAverageCn0StatisticsL5 = new Statistics();
-        mNumSvStatus = 0;
-        mNumL5SvStatus = 0;
-        mNumSvStatusUsedInFix = 0;
-        mNumL5SvStatusUsedInFix = 0;
         reset();
     }
 
@@ -410,6 +406,11 @@
         mPositionAccuracyMeterStatistics.reset();
         mTopFourAverageCn0Statistics.reset();
         resetConstellationTypes();
+        mTopFourAverageCn0StatisticsL5.reset();
+        mNumSvStatus = 0;
+        mNumL5SvStatus = 0;
+        mNumSvStatusUsedInFix = 0;
+        mNumL5SvStatusUsedInFix = 0;
     }
 
     /** Resets {@link #mConstellationTypes} as an all-false boolean array. */
diff --git a/location/tests/locationtests/src/android/location/GnssStatusTest.java b/location/tests/locationtests/src/android/location/GnssStatusTest.java
deleted file mode 100644
index 79ea0d6..0000000
--- a/location/tests/locationtests/src/android/location/GnssStatusTest.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.location;
-
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-import java.lang.reflect.Constructor;
-import java.util.ArrayList;
-import java.util.List;
-import junit.framework.TestCase;
-
-/**
- * Unit tests for {@link GnssStatus}.
- */
-@SmallTest
-public class GnssStatusTest extends TestCase {
-
-  private static final String TAG = GnssStatusTest.class.getSimpleName();
-  public void setUp() throws Exception {
-    super.setUp();
-  }
-
-  /*
-   * Create {@link GnssStatus} with default value, verify whether its fields are set correctly.
-   *
-   */
-  public void testEmptyGnssStatus() throws Exception {
-    Log.i(TAG, "testEmptyGnssStatus");
-    List<SatelliteInfo> svInfos = new ArrayList<>();
-    GnssStatus gnssStatus = createGnssStatus(svInfos);
-    verifyGnssStatus(svInfos, gnssStatus);
-  }
-
-  /*
-   * Create {@link GnssStatus} with only one satellite info, verify whether its fields are set
-   * correctly.
-   */
-  public void testOneSatelliteGnssStatus() throws Exception {
-    Log.i(TAG, "testOneSatelliteGnssStatus");
-    List<SatelliteInfo> svInfos = new ArrayList<>();
-    SatelliteInfo svInfo =
-        new SatelliteInfo(100,1, true, true, true, true, 100f, 20.3f, 45.5f, 100.23f);
-    svInfos.add(svInfo);
-    GnssStatus gnssStatus = createGnssStatus(svInfos);
-    verifyGnssStatus(svInfos, gnssStatus);
-  }
-
-  /*
-   * Create {@link GnssStatus} with multiple satellite info, verify whether its fields are set
-   * correctly.
-   */
-  public void testMultipleSatellitesGnssStatus() throws Exception {
-    Log.i(TAG, "testMultipleSatellitesGnssStatus");
-    List<SatelliteInfo> svInfos = new ArrayList<>();
-    SatelliteInfo svInfo1 =
-        new SatelliteInfo(20, 1,true, true, true, true, 10.1f, 20.3f, 45.5f, 111.23f);
-    SatelliteInfo svInfo2 =
-        new SatelliteInfo(50, 2, true, false, true, false, 20.2f, 21.3f, 46.5f, 222.23f);
-    SatelliteInfo svInfo3 =
-        new SatelliteInfo(192, 3, false, true, false, true, 30.3f, 22.3f, 47.5f, 333.23f);
-    SatelliteInfo svInfo4 =
-        new SatelliteInfo(250, 4, false, false, false, false, 40.4f, 23.3f, 48.5f, 444.23f);
-    svInfos.add(svInfo1);
-    svInfos.add(svInfo2);
-    svInfos.add(svInfo3);
-    svInfos.add(svInfo4);
-    GnssStatus gnssStatus = createGnssStatus(svInfos);
-    verifyGnssStatus(svInfos, gnssStatus);
-  }
-
-  private void verifyGnssStatus(List<SatelliteInfo> svInfos, GnssStatus gnssStatus) {
-    Log.i(TAG, String.format("Verifing {0} satellites info.",svInfos.size()));
-    assertEquals(TAG + "::SatelliteCount", svInfos.size(),
-        gnssStatus.getSatelliteCount());
-    for (int i = 0; i< svInfos.size(); i++) {
-      SatelliteInfo svInfo = svInfos.get(i);
-      assertEquals(TAG + "::Svid", svInfo.mSvid, gnssStatus.getSvid(i));
-      assertEquals(TAG + "::ConstellationType", svInfo.mConstellationType,
-          gnssStatus.getConstellationType(i));
-      assertEquals(TAG + "::Cn0DbHz", svInfo.mCn0DbHz, gnssStatus.getCn0DbHz(i));
-      assertEquals(TAG + "::Elevation", svInfo.mElevation,
-          gnssStatus.getElevationDegrees(i));
-      assertEquals(TAG + "::Azimuth", svInfo.mAzimuth, gnssStatus.getAzimuthDegrees(i));
-      assertEquals(TAG + "::CarrierFrequencyHz", svInfo.mCarrierFrequency,
-          gnssStatus.getCarrierFrequencyHz(i));
-      assertEquals(TAG + "::hasEphemerisData", svInfo.mHasEphemris,
-          gnssStatus.hasEphemerisData(i));
-      assertEquals(TAG + "::HasAlmanacData", svInfo.mHasAlmanac,
-          gnssStatus.hasAlmanacData(i));
-      assertEquals(TAG + "::UsedInFix", svInfo.mUsedInFix, gnssStatus.usedInFix(i));
-      assertEquals(TAG + "::HasCarrierFrequencyHz", svInfo.mHasCarriesFrequency,
-          gnssStatus.hasCarrierFrequencyHz(i));
-    }
-  }
-
-  private static GnssStatus createGnssStatus(List<SatelliteInfo> svInfos) throws Exception {
-    Class<?> intClass = Integer.TYPE;
-    Class<?> floatArrayClass = Class.forName("[F");
-    Class<?> intArrayClass = Class.forName("[I");
-    Class[] cArg = new Class[6];
-    cArg[0] = intClass;
-    cArg[1] = intArrayClass;
-    cArg[2] = floatArrayClass;
-    cArg[3] = floatArrayClass;
-    cArg[4] = floatArrayClass;
-    cArg[5] = floatArrayClass;
-    Constructor<GnssStatus>  ctor = GnssStatus.class.getDeclaredConstructor(cArg);
-    ctor.setAccessible(true);
-    return ctor.newInstance(svInfos.size(),
-        SatelliteInfo.getSvidWithFlagsArray(svInfos),
-        SatelliteInfo.getCn0sArray(svInfos),
-        SatelliteInfo.getElevationsArray(svInfos),
-        SatelliteInfo.getAzimuthsArray(svInfos),
-        SatelliteInfo.getCarrierFrequencyArray(svInfos));
-  }
-}
diff --git a/location/tests/locationtests/src/android/location/SatelliteInfo.java b/location/tests/locationtests/src/android/location/SatelliteInfo.java
deleted file mode 100644
index b6453ef..0000000
--- a/location/tests/locationtests/src/android/location/SatelliteInfo.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.location;
-
-import java.util.List;
-
-/*
- * Helper class to store single Satellite info, only used it in the unit test.
- */
-public class SatelliteInfo {
-  private static final int SVID_MAX_BIT_INDEX = 32;
-  private static final int SVID_SHIFT_WIDTH = 8;
-  private static final int CONSTELLATION_TYPE_SHIFT_WIDTH = 4;
-
-  // Index for the bits in mSvidWithFlag
-  private static final int GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA_BIT_INDEX = 0;
-  private static final int GNSS_SV_FLAGS_HAS_ALMANAC_DATA_BIT_INDEX = 1;
-  private static final int GNSS_SV_FLAGS_USED_IN_FIX_BIT_INDEX = 2;
-  private static final int GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY_BIT_INDEX = 3;
-  public int mSvid;
-  public int mSvidWithFlag;
-  public float mCn0DbHz;
-  public float mElevation;
-  public float mAzimuth;
-  public float mCarrierFrequency;
-
-  /*
-   * Flag fields, it stores the same information as svidWithFlag, but in different format, easy for
-   * the unit test.
-   */
-  public int mConstellationType;
-  public boolean mHasEphemris;
-  public boolean mHasAlmanac;
-  public boolean mUsedInFix;
-  public boolean mHasCarriesFrequency;
-
-  public SatelliteInfo(int svid, int constellationType, boolean hasEphemris, boolean hasAlmanac,
-      boolean usedInFix, boolean hasCarriesFrequency, float cn0, float elevation, float azimuth,
-      float carrierFrequency) {
-    mSvidWithFlag =
-        setRange(mSvidWithFlag, constellationType, CONSTELLATION_TYPE_SHIFT_WIDTH, SVID_SHIFT_WIDTH);
-    mSvidWithFlag = setRange(mSvidWithFlag, svid, SVID_SHIFT_WIDTH, SVID_MAX_BIT_INDEX);
-    mSvidWithFlag = setBit(mSvidWithFlag, hasEphemris, GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA_BIT_INDEX);
-    mSvidWithFlag = setBit(mSvidWithFlag, hasAlmanac, GNSS_SV_FLAGS_HAS_ALMANAC_DATA_BIT_INDEX);
-    mSvidWithFlag = setBit(mSvidWithFlag, usedInFix, GNSS_SV_FLAGS_USED_IN_FIX_BIT_INDEX);
-    mSvidWithFlag =
-        setBit(mSvidWithFlag, hasCarriesFrequency, GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY_BIT_INDEX);
-    this.mSvid = svid;
-    this.mConstellationType = constellationType;
-    this.mCn0DbHz = cn0;
-    this.mElevation = elevation;
-    this.mAzimuth = azimuth;
-    this.mCarrierFrequency = carrierFrequency;
-    this.mHasEphemris = hasEphemris;
-    this.mHasAlmanac = hasAlmanac;
-    this.mUsedInFix = usedInFix;
-    this.mHasCarriesFrequency = hasCarriesFrequency;
-  }
-
-  /*
-   * Gernerate svidWithFlags array from svInfos
-   */
-  public static int[] getSvidWithFlagsArray(List<SatelliteInfo> svInfos) {
-    int[] svidWithFlags = new int[svInfos.size()];
-    for (int i = 0; i< svInfos.size(); i++) {
-      svidWithFlags[i] = svInfos.get(i).mSvidWithFlag;
-    }
-    return svidWithFlags;
-  }
-
-  /*
-   * Gernerate cn0s array from svInfos
-   */
-  public static float[] getCn0sArray(List<SatelliteInfo> svInfos) {
-    float[] cn0s = new float[svInfos.size()];
-    for (int i = 0; i< svInfos.size(); i++) {
-      cn0s[i] = svInfos.get(i).mCn0DbHz;
-    }
-    return cn0s;
-  }
-
-  /*
-   * Gernerate elevations array from svInfos
-   */
-  public static float[] getElevationsArray(List<SatelliteInfo> svInfos) {
-    float[] elevations = new float[svInfos.size()];
-    for (int i = 0; i< svInfos.size(); i++) {
-      elevations[i] = svInfos.get(i).mElevation;
-    }
-    return elevations;
-  }
-
-  /*
-   * Gernerate azimuths array from svInfos
-   */
-  public static float[] getAzimuthsArray(List<SatelliteInfo> svInfos) {
-    float[] azimuths = new float[svInfos.size()];
-    for (int i = 0; i< svInfos.size(); i++) {
-      azimuths[i] = svInfos.get(i).mAzimuth;
-    }
-    return azimuths;
-  }
-
-  /*
-   * Gernerate carrierFrequency array from svInfos
-   */
-  public static float[] getCarrierFrequencyArray(List<SatelliteInfo> svInfos) {
-    float[] carrierFrequencies = new float[svInfos.size()];
-    for (int i = 0; i< svInfos.size(); i++) {
-      carrierFrequencies[i] = svInfos.get(i).mCarrierFrequency;
-    }
-    return carrierFrequencies;
-  }
-
-  private int setBit(int targetValue, boolean value, int index) {
-    if (value) {
-      targetValue = targetValue | (1 << index);
-    } else {
-      targetValue = targetValue & ~(1 << index);
-    }
-    return targetValue;
-  }
-
-  /*
-   * Set the bit in the range [fromIndex, toIndex), index start from the lowest bit.
-   * value -> 1 1 0 1 1 0 1 0
-   * index -> 7 6 5 4 3 2 1 0
-   * This function will set the bit in the range to the lowest X bits of the value.
-   */
-  private int setRange(int targetValue, int value, int fromIndex, int toIndex) {
-    int rangeLen = toIndex - fromIndex;
-    int valueMask = (1 << rangeLen) -1;
-    value &= valueMask;
-    value = value << fromIndex;
-    valueMask = valueMask << fromIndex;
-    targetValue &= (~valueMask);
-    targetValue |= value;
-    return targetValue;
-  }
-
-}
\ No newline at end of file
diff --git a/media/Android.bp b/media/Android.bp
index 022fa9b..1912930 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -45,8 +45,8 @@
 filegroup {
     name: "updatable-media-srcs",
     srcs: [
-        ":mediasession2-srcs",
         ":mediaparser-srcs",
+        ":mediasession2-srcs",
     ],
 }
 
@@ -73,7 +73,8 @@
     name: "mediaparser-srcs",
     srcs: [
         "apex/java/android/media/MediaParser.java"
-    ]
+    ],
+    path: "apex/java"
 }
 
 metalava_updatable_media_args = " --error UnhiddenSystemApi " +
diff --git a/media/apex/java/android/media/MediaParser.java b/media/apex/java/android/media/MediaParser.java
index c06e283..8824269 100644
--- a/media/apex/java/android/media/MediaParser.java
+++ b/media/apex/java/android/media/MediaParser.java
@@ -15,10 +15,47 @@
  */
 package android.media;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.Uri;
+import android.text.TextUtils;
 import android.util.Pair;
+import android.util.SparseArray;
 
+import com.google.android.exoplayer2.C;
+import com.google.android.exoplayer2.Format;
+import com.google.android.exoplayer2.extractor.DefaultExtractorInput;
+import com.google.android.exoplayer2.extractor.Extractor;
+import com.google.android.exoplayer2.extractor.ExtractorInput;
+import com.google.android.exoplayer2.extractor.ExtractorOutput;
+import com.google.android.exoplayer2.extractor.PositionHolder;
+import com.google.android.exoplayer2.extractor.SeekMap.SeekPoints;
+import com.google.android.exoplayer2.extractor.TrackOutput;
+import com.google.android.exoplayer2.extractor.amr.AmrExtractor;
+import com.google.android.exoplayer2.extractor.flv.FlvExtractor;
+import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor;
+import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor;
+import com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor;
+import com.google.android.exoplayer2.extractor.mp4.Mp4Extractor;
+import com.google.android.exoplayer2.extractor.ogg.OggExtractor;
+import com.google.android.exoplayer2.extractor.ts.Ac3Extractor;
+import com.google.android.exoplayer2.extractor.ts.Ac4Extractor;
+import com.google.android.exoplayer2.extractor.ts.AdtsExtractor;
+import com.google.android.exoplayer2.extractor.ts.PsExtractor;
+import com.google.android.exoplayer2.extractor.ts.TsExtractor;
+import com.google.android.exoplayer2.extractor.wav.WavExtractor;
+import com.google.android.exoplayer2.upstream.DataSource;
+import com.google.android.exoplayer2.upstream.DataSpec;
+import com.google.android.exoplayer2.upstream.TransferListener;
+import com.google.android.exoplayer2.util.ParsableByteArray;
+
+import java.io.EOFException;
 import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Parses media container formats and extracts contained media samples and metadata.
@@ -32,16 +69,93 @@
  * <p>Users must implement the following to use this class.
  *
  * <ul>
- *   <li>{@link Input}: Provides the media containers bytes to parse.
- *   <li>{@link OutputCallback}: Provides a sink for all extracted data and metadata.
+ *   <li>{@link InputReader}: Provides the media container's bytes to parse.
+ *   <li>{@link OutputConsumer}: Provides a sink for all extracted data and metadata.
  * </ul>
  *
- * TODO: Add usage example here.
+ * <p>The following code snippet includes a usage example:
+ *
+ * <pre>
+ * MyOutputConsumer myOutputConsumer = new MyOutputConsumer();
+ * MyInputReader myInputReader = new MyInputReader("www.example.com");
+ * MediaParser mediaParser = MediaParser.create(myOutputConsumer);
+ *
+ * while (mediaParser.advance(myInputReader)) {}
+ *
+ * mediaParser.release();
+ * mediaParser = null;
+ * </pre>
+ *
+ * <p>The following code snippet provides a rudimentary {@link OutputConsumer} sample implementation
+ * which extracts and publishes all video samples:
+ *
+ * <pre>
+ *
+ * class VideoOutputConsumer implements MediaParser.OutputConsumer {
+ *
+ *     private static final int MAXIMUM_SAMPLE_SIZE = ...;
+ *     private byte[] sampleDataBuffer = new byte[MAXIMUM_SAMPLE_SIZE];
+ *     private int videoTrackIndex = -1;
+ *     private int bytesWrittenCount = 0;
+ *
+ *     \@Override
+ *     public void onSeekMap(int i, @NonNull MediaFormat mediaFormat) { \/* Do nothing. *\/ }
+ *
+ *     \@Override
+ *     public void onFormat(int i, @NonNull MediaFormat mediaFormat) {
+ *       if (videoTrackIndex == -1 && mediaFormat
+ *           .getString(MediaFormat.KEY_MIME, \/* defaultValue= *\/ "").startsWith("video/")) {
+ *         videoTrackIndex = i;
+ *       }
+ *     }
+ *
+ *     \@Override
+ *     public void onSampleData(int trackIndex, @NonNull InputReader inputReader)
+ *         throws IOException, InterruptedException {
+ *       int numberOfBytesToRead = (int) inputReader.getLength();
+ *       if (videoTrackIndex != trackIndex) {
+ *         // Discard contents.
+ *         inputReader.read(\/* bytes= *\/ null, \/* offset= *\/ 0, numberOfBytesToRead);
+ *       }
+ *       int bytesRead = inputReader.read(sampleDataBuffer, bytesWrittenCount, numberOfBytesToRead);
+ *       bytesWrittenCount += bytesRead;
+ *     }
+ *
+ *     \@Override
+ *     public void onSampleCompleted(
+ *         int trackIndex,
+ *         long timeUs,
+ *         int flags,
+ *         int size,
+ *         int offset,
+ *         \@Nullable CryptoInfo cryptoData) {
+ *       if (videoTrackIndex != trackIndex) {
+ *         return; // It's not the video track. Ignore.
+ *       }
+ *       byte[] sampleData = new byte[size];
+ *       System.arraycopy(sampleDataBuffer, bytesWrittenCount - size - offset, sampleData, \/*
+ *       destPos= *\/ 0, size);
+ *       // Place trailing bytes at the start of the buffer.
+ *       System.arraycopy(
+ *           sampleDataBuffer,
+ *           bytesWrittenCount - offset,
+ *           sampleDataBuffer,
+ *           \/* destPos= *\/ 0,
+ *           \/* size= *\/ offset);
+ *       publishSample(sampleData, timeUs, flags);
+ *     }
+ *   }
+ *
+ * </pre>
  */
-// @HiddenApi
 public final class MediaParser {
 
-    /** Maps seek positions to corresponding positions in the stream. */
+    /**
+     * Maps seek positions to {@link SeekPoint SeekPoints} in the stream.
+     *
+     * <p>A {@link SeekPoint} is a position in the stream from which a player may successfully start
+     * playing media samples.
+     */
     public interface SeekMap {
 
         /** Returned by {@link #getDurationUs()} when the duration is unknown. */
@@ -62,13 +176,14 @@
          * <p>{@code getSeekPoints(timeUs).first} contains the latest seek point for samples with
          * timestamp equal to or smaller than {@code timeUs}.
          *
-         * <p>{@code getSeekPoints(timeUs).second} contains the earlies seek point for samples with
+         * <p>{@code getSeekPoints(timeUs).second} contains the earliest seek point for samples with
          * timestamp equal to or greater than {@code timeUs}. If a seek point exists for {@code
          * timeUs}, the returned pair will contain the same {@link SeekPoint} twice.
          *
          * @param timeUs A seek time in microseconds.
          * @return The corresponding {@link SeekPoint SeekPoints}.
          */
+        @NonNull
         Pair<SeekPoint, SeekPoint> getSeekPoints(long timeUs);
     }
 
@@ -76,30 +191,30 @@
     public static final class SeekPoint {
 
         /** A {@link SeekPoint} whose time and byte offset are both set to 0. */
-        public static final SeekPoint START = new SeekPoint(0, 0);
+        public static final @NonNull SeekPoint START = new SeekPoint(0, 0);
 
         /** The time of the seek point, in microseconds. */
-        public final long mTimeUs;
+        public final long timeUs;
 
         /** The byte offset of the seek point. */
-        public final long mPosition;
+        public final long position;
 
         /**
          * @param timeUs The time of the seek point, in microseconds.
          * @param position The byte offset of the seek point.
          */
-        public SeekPoint(long timeUs, long position) {
-            this.mTimeUs = timeUs;
-            this.mPosition = position;
+        private SeekPoint(long timeUs, long position) {
+            this.timeUs = timeUs;
+            this.position = position;
         }
 
         @Override
-        public String toString() {
-            return "[timeUs=" + mTimeUs + ", position=" + mPosition + "]";
+        public @NonNull String toString() {
+            return "[timeUs=" + timeUs + ", position=" + position + "]";
         }
 
         @Override
-        public boolean equals(Object obj) {
+        public boolean equals(@Nullable Object obj) {
             if (this == obj) {
                 return true;
             }
@@ -107,25 +222,26 @@
                 return false;
             }
             SeekPoint other = (SeekPoint) obj;
-            return mTimeUs == other.mTimeUs && mPosition == other.mPosition;
+            return timeUs == other.timeUs && position == other.position;
         }
 
         @Override
         public int hashCode() {
-            int result = (int) mTimeUs;
-            result = 31 * result + (int) mPosition;
+            int result = (int) timeUs;
+            result = 31 * result + (int) position;
             return result;
         }
     }
 
     /** Provides input data to {@link MediaParser}. */
-    public interface Input {
+    public interface InputReader {
 
         /**
          * Reads up to {@code readLength} bytes of data and stores them into {@code buffer},
          * starting at index {@code offset}.
          *
-         * <p>The call will block until at least one byte of data has been read.
+         * <p>This method blocks until at least one byte is read, the end of input is detected, or
+         * an exception is thrown. The read position advances to the first unread byte.
          *
          * @param buffer The buffer into which the read data should be stored.
          * @param offset The start offset into {@code buffer} at which data should be written.
@@ -134,7 +250,7 @@
          *     of the input has been reached.
          * @throws java.io.IOException If an error occurs reading from the source.
          */
-        int read(byte[] buffer, int offset, int readLength)
+        int read(@NonNull byte[] buffer, int offset, int readLength)
                 throws IOException, InterruptedException;
 
         /** Returns the current read position (byte offset) in the stream. */
@@ -144,22 +260,39 @@
         long getLength();
     }
 
-    /** Receives extracted media sample data and metadata from {@link MediaParser}. */
-    public interface OutputCallback {
+    /** {@link InputReader} that allows setting the read position. */
+    public interface SeekableInputReader extends InputReader {
 
         /**
-         * Called when the number of tracks is defined.
+         * Sets the read position at the given {@code position}.
          *
-         * @param numberOfTracks The number of tracks in the stream.
+         * <p>{@link #advance} will immediately return after calling this method.
+         *
+         * @param position The position to seek to, in bytes.
          */
-        void onTracksFound(int numberOfTracks);
+        void seekToPosition(long position);
+    }
+
+    /** Receives extracted media sample data and metadata from {@link MediaParser}. */
+    public interface OutputConsumer {
 
         /**
          * Called when a {@link SeekMap} has been extracted from the stream.
          *
+         * <p>This method is called at least once before any samples are {@link #onSampleCompleted
+         * complete}. May be called multiple times after that in order to add {@link SeekPoint
+         * SeekPoints}.
+         *
          * @param seekMap The extracted {@link SeekMap}.
          */
-        void onSeekMap(SeekMap seekMap);
+        void onSeekMap(@NonNull SeekMap seekMap);
+
+        /**
+         * Called when the number of tracks is found.
+         *
+         * @param numberOfTracks The number of tracks in the stream.
+         */
+        void onTracksFound(int numberOfTracks);
 
         /**
          * Called when the {@link MediaFormat} of the track is extracted from the stream.
@@ -167,7 +300,7 @@
          * @param trackIndex The index of the track for which the {@link MediaFormat} was found.
          * @param format The extracted {@link MediaFormat}.
          */
-        void onFormat(int trackIndex, MediaFormat format);
+        void onFormat(int trackIndex, @NonNull MediaFormat format);
 
         /**
          * Called to write sample data to the output.
@@ -176,16 +309,15 @@
          * thrown {@link IOException} caused by reading from {@code input}.
          *
          * @param trackIndex The index of the track to which the sample data corresponds.
-         * @param input The {@link Input} from which to read the data.
-         * @return
+         * @param inputReader The {@link InputReader} from which to read the data.
          */
-        int onSampleData(int trackIndex, Input input) throws IOException, InterruptedException;
+        void onSampleData(int trackIndex, @NonNull InputReader inputReader)
+                throws IOException, InterruptedException;
 
         /**
-         * Defines the boundaries and metadata of an extracted sample.
+         * Called once all the data of a sample has been passed to {@link #onSampleData}.
          *
-         * <p>The corresponding sample data will have already been passed to the output via calls to
-         * {@link #onSampleData}.
+         * <p>Also includes sample metadata, like presentation timestamp and flags.
          *
          * @param trackIndex The index of the track to which the sample corresponds.
          * @param timeUs The media timestamp associated with the sample, in microseconds.
@@ -203,57 +335,22 @@
                 int flags,
                 int size,
                 int offset,
-                MediaCodec.CryptoInfo cryptoData);
-    }
-
-    /**
-     * Controls the behavior of extractors' implementations.
-     *
-     * <p>DESIGN NOTE: For setting flags like workarounds and special behaviors for adaptive
-     * streaming.
-     */
-    public static final class Parameters {
-
-        // TODO: Implement.
-
-    }
-
-    /** Holds the result of an {@link #advance} invocation. */
-    public static final class ResultHolder {
-
-        /** Creates a new instance with {@link #result} holding {@link #ADVANCE_RESULT_CONTINUE}. */
-        public ResultHolder() {
-            result = ADVANCE_RESULT_CONTINUE;
-        }
-
-        /**
-         * May hold {@link #ADVANCE_RESULT_END_OF_INPUT}, {@link #ADVANCE_RESULT_CONTINUE}, {@link
-         * #ADVANCE_RESULT_SEEK}.
-         */
-        public int result;
-
-        /**
-         * If {@link #result} holds {@link #ADVANCE_RESULT_SEEK}, holds the stream position required
-         * from the passed {@link Input} to the next {@link #advance} call. If {@link #result} does
-         * not hold {@link #ADVANCE_RESULT_SEEK}, the value of this variable is undefined and should
-         * be ignored.
-         */
-        public long seekPosition;
+                @Nullable MediaCodec.CryptoInfo cryptoData);
     }
 
     /**
      * Thrown if all extractors implementations provided to {@link #create} failed to sniff the
      * input content.
      */
-    // @HiddenApi
     public static final class UnrecognizedInputFormatException extends IOException {
 
         /**
          * Creates a new instance which signals that the extractors with the given names failed to
          * parse the input.
          */
-        public static UnrecognizedInputFormatException createForExtractors(
-                String... extractorNames) {
+        @NonNull
+        private static UnrecognizedInputFormatException createForExtractors(
+                @NonNull String... extractorNames) {
             StringBuilder builder = new StringBuilder();
             builder.append("None of the available extractors ( ");
             builder.append(extractorNames[0]);
@@ -270,21 +367,9 @@
         }
     }
 
-    // Public constants.
+    // Private constants.
 
-    /**
-     * Returned by {@link #advance} if the {@link Input} passed to the next {@link #advance} is
-     * required to provide data continuing from the position in the stream reached by the returning
-     * call.
-     */
-    public static final int ADVANCE_RESULT_CONTINUE = -1;
-    /** Returned by {@link #advance} if the end of the {@link Input} was reached. */
-    public static final int ADVANCE_RESULT_END_OF_INPUT = -2;
-    /**
-     * Returned by {@link #advance} when its next call expects a specific stream position, which
-     * will be held by {@link ResultHolder#seekPosition}.
-     */
-    public static final int ADVANCE_RESULT_SEEK = -3;
+    private static final Map<String, ExtractorFactory> EXTRACTOR_FACTORIES_BY_NAME;
 
     // Instance creation methods.
 
@@ -293,13 +378,15 @@
      * instance will attempt extraction without sniffing the content.
      *
      * @param name The name of the extractor that will be associated with the created instance.
-     * @param outputCallback The {@link OutputCallback} to which track data and samples are pushed.
-     * @param parameters Parameters that control specific aspects of the behavior of the extractors.
+     * @param outputConsumer The {@link OutputConsumer} to which track data and samples are pushed.
      * @return A new instance.
+     * @throws IllegalArgumentException If an invalid name is provided.
      */
-    public static MediaParser createByName(
-            String name, OutputCallback outputCallback, Parameters parameters) {
-        throw new UnsupportedOperationException();
+    public static @NonNull MediaParser createByName(
+            @NonNull String name, @NonNull OutputConsumer outputConsumer) {
+        String[] nameAsArray = new String[] {name};
+        assertValidNames(nameAsArray);
+        return new MediaParser(outputConsumer, /* sniff= */ false, name);
     }
 
     /**
@@ -307,30 +394,46 @@
      * the first {@link #advance} call. Extractor implementations will sniff the content in order of
      * appearance in {@code extractorNames}.
      *
-     * @param outputCallback The {@link OutputCallback} to track data and samples are obtained.
-     * @param parameters Parameters that control specific aspects of the behavior of the extractors.
+     * @param outputConsumer The {@link OutputConsumer} to which extracted data is output.
      * @param extractorNames The names of the extractors to sniff the content with. If empty, a
      *     default array of names is used.
      * @return A new instance.
      */
-    public static MediaParser create(
-            OutputCallback outputCallback, Parameters parameters, String... extractorNames) {
-        throw new UnsupportedOperationException();
+    public static @NonNull MediaParser create(
+            @NonNull OutputConsumer outputConsumer, @NonNull String... extractorNames) {
+        assertValidNames(extractorNames);
+        if (extractorNames.length == 0) {
+            extractorNames = EXTRACTOR_FACTORIES_BY_NAME.keySet().toArray(new String[0]);
+        }
+        return new MediaParser(outputConsumer, /* sniff= */ true, extractorNames);
     }
 
     // Misc static methods.
 
     /**
      * Returns an immutable list with the names of the extractors that are suitable for container
-     * formats with the given {@code mimeTypes}. If an empty string is passed, all available
-     * extractors' names are returned.
+     * formats with the given {@link MediaFormat}.
      *
-     * <p>TODO: Replace string with media type object.
+     * <p>TODO: List which properties are taken into account. E.g. MimeType.
      */
-    public static List<String> getExtractorNames(String mimeTypes) {
+    public static @NonNull List<String> getExtractorNames(@NonNull MediaFormat mediaFormat) {
         throw new UnsupportedOperationException();
     }
 
+    // Private fields.
+
+    private final OutputConsumer mOutputConsumer;
+    private final String[] mExtractorNamesPool;
+    private final PositionHolder mPositionHolder;
+    private final InputReadingDataSource mDataSource;
+    private final ExtractorInputAdapter mScratchExtractorInputAdapter;
+    private final ParsableByteArrayAdapter mScratchParsableByteArrayAdapter;
+    private String mExtractorName;
+    private Extractor mExtractor;
+    private ExtractorInput mExtractorInput;
+    private long mPendingSeekPosition;
+    private long mPendingSeekTimeUs;
+
     // Public methods.
 
     /**
@@ -344,8 +447,8 @@
      * @return The name of the backing extractor implementation, or null if the backing extractor
      *     implementation has not yet been selected.
      */
-    public String getExtractorName() {
-        throw new UnsupportedOperationException();
+    public @Nullable String getExtractorName() {
+        return mExtractorName;
     }
 
     /**
@@ -357,26 +460,85 @@
      * <p>If this instance was created using {@link #create}. the first call to this method will
      * sniff the content with the extractors with the provided names.
      *
-     * @param input The {@link Input} from which to obtain the media container data.
-     * @param resultHolder The {@link ResultHolder} into which the result of the operation will be
-     *     written.
+     * @param seekableInputReader The {@link SeekableInputReader} from which to obtain the media
+     *     container data.
+     * @return Whether there is any data left to extract. Returns false if the end of input has been
+     *     reached.
      * @throws UnrecognizedInputFormatException
      */
-    public void advance(Input input, ResultHolder resultHolder)
+    public boolean advance(@NonNull SeekableInputReader seekableInputReader)
             throws IOException, InterruptedException {
-        throw new UnsupportedOperationException();
+        if (mExtractorInput == null) {
+            // TODO: For efficiency, the same implementation should be used, by providing a
+            // clearBuffers() method, or similar.
+            mExtractorInput =
+                    new DefaultExtractorInput(
+                            mDataSource,
+                            seekableInputReader.getPosition(),
+                            seekableInputReader.getLength());
+        }
+        mDataSource.mInputReader = seekableInputReader;
+
+        if (mExtractor == null) {
+            for (String extractorName : mExtractorNamesPool) {
+                Extractor extractor =
+                        EXTRACTOR_FACTORIES_BY_NAME.get(extractorName).createInstance();
+                try {
+                    if (extractor.sniff(mExtractorInput)) {
+                        mExtractorName = extractorName;
+                        mExtractor = extractor;
+                        mExtractor.init(new ExtractorOutputAdapter());
+                        break;
+                    }
+                } catch (EOFException e) {
+                    // Do nothing.
+                } catch (IOException | InterruptedException e) {
+                    throw new IllegalStateException(e);
+                } finally {
+                    mExtractorInput.resetPeekPosition();
+                }
+            }
+            if (mExtractor == null) {
+                UnrecognizedInputFormatException.createForExtractors(mExtractorNamesPool);
+            }
+            return true;
+        }
+
+        if (isPendingSeek()) {
+            mExtractor.seek(mPendingSeekPosition, mPendingSeekTimeUs);
+            removePendingSeek();
+        }
+
+        mPositionHolder.position = seekableInputReader.getPosition();
+        int result = mExtractor.read(mExtractorInput, mPositionHolder);
+        if (result == Extractor.RESULT_END_OF_INPUT) {
+            return false;
+        }
+        if (result == Extractor.RESULT_SEEK) {
+            mExtractorInput = null;
+            seekableInputReader.seekToPosition(mPositionHolder.position);
+        }
+        return true;
     }
 
     /**
      * Seeks within the media container being extracted.
      *
-     * <p>Following a call to this method, the {@link Input} passed to the next invocation of {@link
-     * #advance} must provide data starting from {@link SeekPoint#mPosition} in the stream.
+     * <p>{@link SeekPoint SeekPoints} can be obtained from the {@link SeekMap} passed to {@link
+     * OutputConsumer#onSeekMap(SeekMap)}.
+     *
+     * <p>Following a call to this method, the {@link InputReader} passed to the next invocation of
+     * {@link #advance} must provide data starting from {@link SeekPoint#position} in the stream.
      *
      * @param seekPoint The {@link SeekPoint} to seek to.
      */
-    public void seek(SeekPoint seekPoint) {
-        throw new UnsupportedOperationException();
+    public void seek(@NonNull SeekPoint seekPoint) {
+        if (mExtractor == null) {
+            mPendingSeekPosition = seekPoint.position;
+            mPendingSeekTimeUs = seekPoint.timeUs;
+        } else {
+            mExtractor.seek(seekPoint.position, seekPoint.timeUs);
+        }
     }
 
     /**
@@ -386,6 +548,359 @@
      * invoked. DESIGN NOTE: Should be removed. There shouldn't be any resource for releasing.
      */
     public void release() {
-        throw new UnsupportedOperationException();
+        mExtractorInput = null;
+        mExtractor = null;
+    }
+
+    // Private methods.
+
+    private MediaParser(
+            OutputConsumer outputConsumer, boolean sniff, String... extractorNamesPool) {
+        mOutputConsumer = outputConsumer;
+        mExtractorNamesPool = extractorNamesPool;
+        if (!sniff) {
+            mExtractorName = extractorNamesPool[0];
+            mExtractor = EXTRACTOR_FACTORIES_BY_NAME.get(mExtractorName).createInstance();
+        }
+        mPositionHolder = new PositionHolder();
+        mDataSource = new InputReadingDataSource();
+        removePendingSeek();
+        mScratchExtractorInputAdapter = new ExtractorInputAdapter();
+        mScratchParsableByteArrayAdapter = new ParsableByteArrayAdapter();
+    }
+
+    private boolean isPendingSeek() {
+        return mPendingSeekPosition >= 0;
+    }
+
+    private void removePendingSeek() {
+        mPendingSeekPosition = -1;
+        mPendingSeekTimeUs = -1;
+    }
+
+    // Private classes.
+
+    private static final class InputReadingDataSource implements DataSource {
+
+        public InputReader mInputReader;
+
+        @Override
+        public void addTransferListener(TransferListener transferListener) {
+            // Do nothing.
+        }
+
+        @Override
+        public long open(DataSpec dataSpec) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public int read(byte[] buffer, int offset, int readLength) throws IOException {
+            // TODO: Reevaluate interruption in Input.
+            try {
+                return mInputReader.read(buffer, offset, readLength);
+            } catch (InterruptedException e) {
+                // TODO: Remove.
+                throw new RuntimeException();
+            }
+        }
+
+        @Override
+        public Uri getUri() {
+            return null;
+        }
+
+        @Override
+        public Map<String, List<String>> getResponseHeaders() {
+            return null;
+        }
+
+        @Override
+        public void close() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    private final class ExtractorOutputAdapter implements ExtractorOutput {
+
+        private final SparseArray<TrackOutput> mTrackOutputAdapters;
+        private boolean mTracksEnded;
+
+        private ExtractorOutputAdapter() {
+            mTrackOutputAdapters = new SparseArray<>();
+        }
+
+        @Override
+        public TrackOutput track(int id, int type) {
+            TrackOutput trackOutput = mTrackOutputAdapters.get(id);
+            if (trackOutput == null) {
+                trackOutput = new TrackOutputAdapter(mTrackOutputAdapters.size());
+                mTrackOutputAdapters.put(id, trackOutput);
+            }
+            return trackOutput;
+        }
+
+        @Override
+        public void endTracks() {
+            mOutputConsumer.onTracksFound(mTrackOutputAdapters.size());
+        }
+
+        @Override
+        public void seekMap(com.google.android.exoplayer2.extractor.SeekMap exoplayerSeekMap) {
+            mOutputConsumer.onSeekMap(new ExoToMediaParserSeekMapAdapter(exoplayerSeekMap));
+        }
+    }
+
+    private class TrackOutputAdapter implements TrackOutput {
+
+        private final int mTrackIndex;
+
+        private TrackOutputAdapter(int trackIndex) {
+            mTrackIndex = trackIndex;
+        }
+
+        @Override
+        public void format(Format format) {
+            mOutputConsumer.onFormat(mTrackIndex, toMediaFormat(format));
+        }
+
+        @Override
+        public int sampleData(ExtractorInput input, int length, boolean allowEndOfInput)
+                throws IOException, InterruptedException {
+            mScratchExtractorInputAdapter.setExtractorInput(input, length);
+            long positionBeforeReading = mScratchExtractorInputAdapter.getPosition();
+            mOutputConsumer.onSampleData(mTrackIndex, mScratchExtractorInputAdapter);
+            return (int) (mScratchExtractorInputAdapter.getPosition() - positionBeforeReading);
+        }
+
+        @Override
+        public void sampleData(ParsableByteArray data, int length) {
+            mScratchParsableByteArrayAdapter.resetWithByteArray(data, length);
+            try {
+                mOutputConsumer.onSampleData(mTrackIndex, mScratchParsableByteArrayAdapter);
+            } catch (IOException | InterruptedException e) {
+                // Unexpected.
+                throw new RuntimeException(e);
+            }
+        }
+
+        @Override
+        public void sampleMetadata(
+                long timeUs, int flags, int size, int offset, CryptoData encryptionData) {
+            mOutputConsumer.onSampleCompleted(
+                    mTrackIndex, timeUs, flags, size, offset, toCryptoInfo(encryptionData));
+        }
+    }
+
+    private static final class ExtractorInputAdapter implements InputReader {
+
+        private ExtractorInput mExtractorInput;
+        private int mCurrentPosition;
+        private long mLength;
+
+        public void setExtractorInput(ExtractorInput extractorInput, long length) {
+            mExtractorInput = extractorInput;
+            mCurrentPosition = 0;
+            mLength = length;
+        }
+
+        // Input implementation.
+
+        @Override
+        public int read(byte[] buffer, int offset, int readLength)
+                throws IOException, InterruptedException {
+            int readBytes = mExtractorInput.read(buffer, offset, readLength);
+            mCurrentPosition += readBytes;
+            return readBytes;
+        }
+
+        @Override
+        public long getPosition() {
+            return mCurrentPosition;
+        }
+
+        @Override
+        public long getLength() {
+            return mLength - mCurrentPosition;
+        }
+    }
+
+    private static final class ParsableByteArrayAdapter implements InputReader {
+
+        private ParsableByteArray mByteArray;
+        private long mLength;
+        private int mCurrentPosition;
+
+        public void resetWithByteArray(ParsableByteArray byteArray, long length) {
+            mByteArray = byteArray;
+            mCurrentPosition = 0;
+            mLength = length;
+        }
+
+        // Input implementation.
+
+        @Override
+        public int read(byte[] buffer, int offset, int readLength) {
+            mByteArray.readBytes(buffer, offset, readLength);
+            mCurrentPosition += readLength;
+            return readLength;
+        }
+
+        @Override
+        public long getPosition() {
+            return mCurrentPosition;
+        }
+
+        @Override
+        public long getLength() {
+            return mLength - mCurrentPosition;
+        }
+    }
+
+    /** Creates extractor instances. */
+    private interface ExtractorFactory {
+
+        /** Returns a new extractor instance. */
+        Extractor createInstance();
+    }
+
+    private static class ExoToMediaParserSeekMapAdapter implements SeekMap {
+
+        private final com.google.android.exoplayer2.extractor.SeekMap mExoPlayerSeekMap;
+
+        private ExoToMediaParserSeekMapAdapter(
+                com.google.android.exoplayer2.extractor.SeekMap exoplayerSeekMap) {
+            mExoPlayerSeekMap = exoplayerSeekMap;
+        }
+
+        @Override
+        public boolean isSeekable() {
+            return mExoPlayerSeekMap.isSeekable();
+        }
+
+        @Override
+        public long getDurationUs() {
+            return mExoPlayerSeekMap.getDurationUs();
+        }
+
+        @Override
+        public Pair<SeekPoint, SeekPoint> getSeekPoints(long timeUs) {
+            SeekPoints seekPoints = mExoPlayerSeekMap.getSeekPoints(timeUs);
+            return new Pair<>(toSeekPoint(seekPoints.first), toSeekPoint(seekPoints.second));
+        }
+    }
+
+    // Private static methods.
+
+    private static MediaFormat toMediaFormat(Format format) {
+
+        // TODO: Add if (value != Format.NO_VALUE);
+
+        MediaFormat result = new MediaFormat();
+        result.setInteger(MediaFormat.KEY_BIT_RATE, format.bitrate);
+        result.setInteger(MediaFormat.KEY_CHANNEL_COUNT, format.channelCount);
+        if (format.colorInfo != null) {
+            result.setInteger(MediaFormat.KEY_COLOR_TRANSFER, format.colorInfo.colorTransfer);
+            result.setInteger(MediaFormat.KEY_COLOR_RANGE, format.colorInfo.colorRange);
+            result.setInteger(MediaFormat.KEY_COLOR_STANDARD, format.colorInfo.colorSpace);
+            if (format.colorInfo.hdrStaticInfo != null) {
+                result.setByteBuffer(
+                        MediaFormat.KEY_HDR_STATIC_INFO,
+                        ByteBuffer.wrap(format.colorInfo.hdrStaticInfo));
+            }
+        }
+        result.setString(MediaFormat.KEY_MIME, format.sampleMimeType);
+        result.setFloat(MediaFormat.KEY_FRAME_RATE, format.frameRate);
+        result.setInteger(MediaFormat.KEY_WIDTH, format.width);
+        result.setInteger(MediaFormat.KEY_HEIGHT, format.height);
+        List<byte[]> initData = format.initializationData;
+        if (initData != null) {
+            for (int i = 0; i < initData.size(); i++) {
+                result.setByteBuffer("csd-" + i, ByteBuffer.wrap(initData.get(i)));
+            }
+        }
+        result.setString(MediaFormat.KEY_LANGUAGE, format.language);
+        result.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, format.maxInputSize);
+        result.setInteger(MediaFormat.KEY_PCM_ENCODING, format.pcmEncoding);
+        result.setInteger(MediaFormat.KEY_ROTATION, format.rotationDegrees);
+        result.setInteger(MediaFormat.KEY_SAMPLE_RATE, format.sampleRate);
+
+        int selectionFlags = format.selectionFlags;
+        // We avoid setting selection flags in the MediaFormat, unless explicitly signaled by the
+        // extractor.
+        if ((selectionFlags & C.SELECTION_FLAG_AUTOSELECT) != 0) {
+            result.setInteger(MediaFormat.KEY_IS_AUTOSELECT, 1);
+        }
+        if ((selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0) {
+            result.setInteger(MediaFormat.KEY_IS_DEFAULT, 1);
+        }
+        if ((selectionFlags & C.SELECTION_FLAG_FORCED) != 0) {
+            result.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, 1);
+        }
+
+        // LACK OF SUPPORT FOR:
+        //    format.accessibilityChannel;
+        //    format.codecs;
+        //    format.containerMimeType;
+        //    format.drmInitData;
+        //    format.encoderDelay;
+        //    format.encoderPadding;
+        //    format.id;
+        //    format.metadata;
+        //    format.pixelWidthHeightRatio;
+        //    format.roleFlags;
+        //    format.stereoMode;
+        //    format.subsampleOffsetUs;
+        return result;
+    }
+
+    private static int toFrameworkFlags(int flags) {
+        // TODO: Implement.
+        return 0;
+    }
+
+    private static MediaCodec.CryptoInfo toCryptoInfo(TrackOutput.CryptoData encryptionData) {
+        // TODO: Implement.
+        return null;
+    }
+
+    /** Returns a new {@link SeekPoint} equivalent to the given {@code exoPlayerSeekPoint}. */
+    private static SeekPoint toSeekPoint(
+            com.google.android.exoplayer2.extractor.SeekPoint exoPlayerSeekPoint) {
+        return new SeekPoint(exoPlayerSeekPoint.timeUs, exoPlayerSeekPoint.position);
+    }
+
+    private static void assertValidNames(@NonNull String[] names) {
+        for (String name : names) {
+            if (!EXTRACTOR_FACTORIES_BY_NAME.containsKey(name)) {
+                throw new IllegalArgumentException(
+                        "Invalid extractor name: "
+                                + name
+                                + ". Supported extractors are: "
+                                + TextUtils.join(", ", EXTRACTOR_FACTORIES_BY_NAME.keySet())
+                                + ".");
+            }
+        }
+    }
+
+    // Static initialization.
+
+    static {
+        // Using a LinkedHashMap to keep the insertion order when iterating over the keys.
+        LinkedHashMap<String, ExtractorFactory> extractorFactoriesByName = new LinkedHashMap<>();
+        extractorFactoriesByName.put("exo.Ac3Extractor", Ac3Extractor::new);
+        extractorFactoriesByName.put("exo.Ac4Extractor", Ac4Extractor::new);
+        extractorFactoriesByName.put("exo.AdtsExtractor", AdtsExtractor::new);
+        extractorFactoriesByName.put("exo.AmrExtractor", AmrExtractor::new);
+        extractorFactoriesByName.put("exo.FlvExtractor", FlvExtractor::new);
+        extractorFactoriesByName.put("exo.FragmentedMp4Extractor", FragmentedMp4Extractor::new);
+        extractorFactoriesByName.put("exo.MatroskaExtractor", MatroskaExtractor::new);
+        extractorFactoriesByName.put("exo.Mp3Extractor", Mp3Extractor::new);
+        extractorFactoriesByName.put("exo.Mp4Extractor", Mp4Extractor::new);
+        extractorFactoriesByName.put("exo.OggExtractor", OggExtractor::new);
+        extractorFactoriesByName.put("exo.PsExtractor", PsExtractor::new);
+        extractorFactoriesByName.put("exo.TsExtractor", TsExtractor::new);
+        extractorFactoriesByName.put("exo.WavExtractor", WavExtractor::new);
+        EXTRACTOR_FACTORIES_BY_NAME = Collections.unmodifiableMap(extractorFactoriesByName);
     }
 }
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 3a092a0..c03e8e2 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -388,12 +388,21 @@
      */
     public static final int FLAG_NO_SYSTEM_CAPTURE = 0x1 << 12;
 
+    /**
+     * @hide
+     * Flag requesting private audio capture. When set in audio attributes passed to an
+     * AudioRecord, this prevents a privileged Assistant from capturing audio while this
+     * AudioRecord is active.
+     */
+    public static final int FLAG_CAPTURE_PRIVATE = 0x1 << 13;
+
+
     // Note that even though FLAG_MUTE_HAPTIC is stored as a flag bit, it is not here since
     // it is known as a boolean value outside of AudioAttributes.
     private static final int FLAG_ALL = FLAG_AUDIBILITY_ENFORCED | FLAG_SECURE | FLAG_SCO
             | FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD | FLAG_BYPASS_INTERRUPTION_POLICY
             | FLAG_BYPASS_MUTE | FLAG_LOW_LATENCY | FLAG_DEEP_BUFFER | FLAG_NO_MEDIA_PROJECTION
-            | FLAG_NO_SYSTEM_CAPTURE;
+            | FLAG_NO_SYSTEM_CAPTURE | FLAG_CAPTURE_PRIVATE;
     private final static int FLAG_ALL_PUBLIC = FLAG_AUDIBILITY_ENFORCED |
             FLAG_HW_AV_SYNC | FLAG_LOW_LATENCY;
 
@@ -620,6 +629,12 @@
             if (mMuteHapticChannels) {
                 aa.mFlags |= FLAG_MUTE_HAPTIC;
             }
+            // capturing for camcorder of communication is private by default to
+            // reflect legacy behavior
+            if (aa.mSource == MediaRecorder.AudioSource.VOICE_COMMUNICATION
+                    || aa.mSource == MediaRecorder.AudioSource.CAMCORDER) {
+                aa.mFlags |= FLAG_CAPTURE_PRIVATE;
+            }
             aa.mTags = (HashSet<String>) mTags.clone();
             aa.mFormattedTags = TextUtils.join(";", mTags);
             if (mBundle != null) {
@@ -1062,7 +1077,7 @@
     }
 
     /** @hide */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
 
         proto.write(AudioAttributesProto.USAGE, mUsage);
diff --git a/media/java/android/media/AudioDeviceAddress.java b/media/java/android/media/AudioDeviceAddress.java
index 415e77d..3d8fc37 100644
--- a/media/java/android/media/AudioDeviceAddress.java
+++ b/media/java/android/media/AudioDeviceAddress.java
@@ -72,10 +72,12 @@
     private final @Role int mRole;
 
     /**
+     * @hide
      * Constructor from a valid {@link AudioDeviceInfo}
      * @param deviceInfo the connected audio device from which to obtain the device-identifying
      *                   type and address.
      */
+    @SystemApi
     public AudioDeviceAddress(@NonNull AudioDeviceInfo deviceInfo) {
         Objects.requireNonNull(deviceInfo);
         mRole = deviceInfo.isSink() ? ROLE_OUTPUT : ROLE_INPUT;
@@ -83,6 +85,14 @@
         mAddress = deviceInfo.getAddress();
     }
 
+    /**
+     * @hide
+     * Constructor from role, device type and address
+     * @param role indicates input or output role
+     * @param type the device type, as defined in {@link AudioDeviceInfo}
+     * @param address the address of the device, or an empty string for devices without one
+     */
+    @SystemApi
     public AudioDeviceAddress(@Role int role, @AudioDeviceInfo.AudioDeviceType int type,
                               @NonNull String address) {
         Objects.requireNonNull(address);
@@ -101,14 +111,38 @@
         mAddress = address;
     }
 
+    /*package*/ AudioDeviceAddress(int nativeType, @NonNull String address) {
+        mRole = (nativeType & AudioSystem.DEVICE_BIT_IN) != 0 ? ROLE_INPUT : ROLE_OUTPUT;
+        mType = AudioDeviceInfo.convertInternalDeviceToDeviceType(nativeType);
+        mAddress = address;
+    }
+
+    /**
+     * @hide
+     * Returns the role of a device
+     * @return the role
+     */
+    @SystemApi
     public @Role int getRole() {
         return mRole;
     }
 
+    /**
+     * @hide
+     * Returns the audio device type of a device
+     * @return the type, as defined in {@link AudioDeviceInfo}
+     */
+    @SystemApi
     public @AudioDeviceInfo.AudioDeviceType int getType() {
         return mType;
     }
 
+    /**
+     * @hide
+     * Returns the address of the audio device, or an empty string for devices without one
+     * @return the device address
+     */
+    @SystemApi
     public @NonNull String getAddress() {
         return mAddress;
     }
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index a39bc51..8293b5f 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -155,7 +155,9 @@
             TYPE_TV_TUNER }
     )
     @Retention(RetentionPolicy.SOURCE)
-    public @interface AudioDeviceType {}    /** @hide */
+    public @interface AudioDeviceType {}
+
+    /** @hide */
     @IntDef(flag = false, prefix = "TYPE", value = {
             TYPE_BUILTIN_MIC,
             TYPE_BLUETOOTH_SCO,
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index d552491..fac276c 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -78,6 +78,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.TreeMap;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
@@ -1536,6 +1537,76 @@
     }
 
     //====================================================================
+    // Audio Product Strategy routing
+
+    /**
+     * @hide
+     * Set the preferred device for a given strategy, i.e. the audio routing to be used by
+     * this audio strategy. Note that the device may not be available at the time the preferred
+     * device is set, but it will be used once made available.
+     * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
+     * this preference for this strategy.</p>
+     * @param strategy the audio strategy whose routing will be affected
+     * @param device the audio device to route to when available
+     * @return true if the operation was successful, false otherwise
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+    public boolean setPreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy,
+            @NonNull AudioDeviceAddress device) {
+        Objects.requireNonNull(strategy);
+        Objects.requireNonNull(device);
+        try {
+            final int status =
+                    getService().setPreferredDeviceForStrategy(strategy.getId(), device);
+            return status == AudioSystem.SUCCESS;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * @hide
+     * Removes the preferred audio device previously set with
+     * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAddress)}.
+     * @param strategy the audio strategy whose routing will be affected
+     * @return true if the operation was successful, false otherwise (invalid strategy, or no
+     *     device set for example)
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+    public boolean removePreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy) {
+        Objects.requireNonNull(strategy);
+        try {
+            final int status =
+                    getService().removePreferredDeviceForStrategy(strategy.getId());
+            return status == AudioSystem.SUCCESS;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * @hide
+     * Return the preferred device for an audio strategy, previously set with
+     * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAddress)}
+     * @param strategy the strategy to query
+     * @return the preferred device for that strategy, or null if none was ever set or if the
+     *    strategy is invalid
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+    public @Nullable AudioDeviceAddress getPreferredDeviceForStrategy(
+            @NonNull AudioProductStrategy strategy) {
+        Objects.requireNonNull(strategy);
+        try {
+            return getService().getPreferredDeviceForStrategy(strategy.getId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    //====================================================================
     // Offload query
     /**
      * Returns whether offloaded playback of an audio format is supported on the device.
@@ -4962,6 +5033,14 @@
      */
     public static final int GET_DEVICES_OUTPUTS   = 0x0002;
 
+    /** @hide */
+    @IntDef(flag = true, prefix = "GET_DEVICES", value = {
+            GET_DEVICES_INPUTS,
+            GET_DEVICES_OUTPUTS }
+    )
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AudioDeviceRole {}
+
     /**
      * Specifies to the {@link AudioManager#getDevices(int)} method to include both
      * source and sink devices.
@@ -4994,7 +5073,7 @@
      * @see #GET_DEVICES_ALL
      * @return A (possibly zero-length) array of AudioDeviceInfo objects.
      */
-    public AudioDeviceInfo[] getDevices(int flags) {
+    public AudioDeviceInfo[] getDevices(@AudioDeviceRole int flags) {
         return getDevicesStatic(flags);
     }
 
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 0254c97..95afb09 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -527,6 +527,11 @@
         private AudioFormat mFormat;
         private int mBufferSizeInBytes;
         private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;
+        private int mPrivacySensitive = PRIVACY_SENSITIVE_DEFAULT;
+
+        private static final int PRIVACY_SENSITIVE_DEFAULT = -1;
+        private static final int PRIVACY_SENSITIVE_DISABLED = 0;
+        private static final int PRIVACY_SENSITIVE_ENABLED = 1;
 
         /**
          * Constructs a new Builder with the default values as described above.
@@ -632,6 +637,36 @@
         }
 
         /**
+         * Indicates that this capture request is privacy sensitive and that
+         * any concurrent capture is not permitted.
+         * <p>
+         * The default is not privacy sensitive except when the audio source set with
+         * {@link #setAudioSource(int)} is {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION} or
+         * {@link MediaRecorder.AudioSource#CAMCORDER}.
+         * <p>
+         * Always takes precedence over default from audio source when set explicitly.
+         * <p>
+         * Using this API is only permitted when the audio source is one of:
+         * <ul>
+         * <li>{@link MediaRecorder.AudioSource#MIC}</li>
+         * <li>{@link MediaRecorder.AudioSource#CAMCORDER}</li>
+         * <li>{@link MediaRecorder.AudioSource#VOICE_RECOGNITION}</li>
+         * <li>{@link MediaRecorder.AudioSource#VOICE_COMMUNICATION}</li>
+         * <li>{@link MediaRecorder.AudioSource#UNPROCESSED}</li>
+         * <li>{@link MediaRecorder.AudioSource#VOICE_PERFORMANCE}</li>
+         * </ul>
+         * Invoking {@link #build()} will throw an UnsupportedOperationException if this
+         * condition is not met.
+         * @param privacySensitive True if capture from this AudioRecord must be marked as privacy
+         * sensitive, false otherwise.
+         */
+        public @NonNull Builder setPrivacySensitive(boolean privacySensitive) {
+            mPrivacySensitive =
+                privacySensitive ? PRIVACY_SENSITIVE_ENABLED : PRIVACY_SENSITIVE_DISABLED;
+            return this;
+        }
+
+        /**
          * @hide
          * To be only used by system components.
          * @param sessionId ID of audio session the AudioRecord must be attached to, or
@@ -704,6 +739,34 @@
                         .setInternalCapturePreset(MediaRecorder.AudioSource.DEFAULT)
                         .build();
             }
+
+            // If mPrivacySensitive is default, the privacy flag is already set
+            // according to audio source in audio attributes.
+            if (mPrivacySensitive != PRIVACY_SENSITIVE_DEFAULT) {
+                int source = mAttributes.getCapturePreset();
+                if (source == MediaRecorder.AudioSource.REMOTE_SUBMIX
+                        || source == MediaRecorder.AudioSource.RADIO_TUNER
+                        || source == MediaRecorder.AudioSource.VOICE_DOWNLINK
+                        || source == MediaRecorder.AudioSource.VOICE_UPLINK
+                        || source == MediaRecorder.AudioSource.VOICE_CALL
+                        || source == MediaRecorder.AudioSource.ECHO_REFERENCE) {
+                    throw new UnsupportedOperationException(
+                            "Cannot request private capture with source: " + source);
+                }
+
+                int flags = mAttributes.getAllFlags();
+                if (mPrivacySensitive == PRIVACY_SENSITIVE_DISABLED) {
+                    flags &= ~AudioAttributes.FLAG_CAPTURE_PRIVATE;
+                } else if (mPrivacySensitive == PRIVACY_SENSITIVE_ENABLED) {
+                    flags |= AudioAttributes.FLAG_CAPTURE_PRIVATE;
+                }
+                if (flags != mAttributes.getAllFlags()) {
+                    mAttributes = new AudioAttributes.Builder(mAttributes)
+                            .replaceFlags(flags)
+                            .build();
+                }
+            }
+
             try {
                 // If the buffer size is not specified,
                 // use a single frame for the buffer size and let the
@@ -1062,6 +1125,17 @@
         return mSessionId;
     }
 
+    /**
+     * Returns whether this AudioRecord is marked as privacy sensitive or not.
+     * <p>
+     * See {@link Builder#setPrivacySensitive(boolean)}
+     * <p>
+     * @return true if privacy sensitive, false otherwise
+     */
+    public boolean isPrivacySensitive() {
+        return (mAudioAttributes.getAllFlags() & AudioAttributes.FLAG_CAPTURE_PRIVATE) != 0;
+    }
+
     //---------------------------------------------------------
     // Transport control methods
     //--------------------
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index d64e4ef..066bf25 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1173,6 +1173,48 @@
      */
     public static native boolean isCallScreeningModeSupported();
 
+    // use case routing by product strategy
+
+    /**
+     * Sets the preferred device to use for a given audio strategy in the audio policy engine
+     * @param strategy the id of the strategy to configure
+     * @param device the device type and address to route to when available
+     * @return {@link #SUCCESS} if successfully set
+     */
+    public static int setPreferredDeviceForStrategy(
+            int strategy, @NonNull AudioDeviceAddress device) {
+        return setPreferredDeviceForStrategy(strategy,
+                AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType()),
+                device.getAddress());
+    }
+    /**
+     * Set device routing per product strategy.
+     * @param strategy the id of the strategy to configure
+     * @param deviceType the native device type, NOT AudioDeviceInfo types
+     * @param deviceAddress the address of the device
+     * @return {@link #SUCCESS} if successfully set
+     */
+    private static native int setPreferredDeviceForStrategy(
+            int strategy, int deviceType, String deviceAddress);
+
+    /**
+     * Remove preferred routing for the strategy
+     * @param strategy the id of the strategy to configure
+     * @return {@link #SUCCESS} if successfully removed
+     */
+    public static native int removePreferredDeviceForStrategy(int strategy);
+
+    /**
+     * Query previously set preferred device for a strategy
+     * @param strategy the id of the strategy to query for
+     * @param device an array of size 1 that will contain the preferred device, or null if
+     *               none was set
+     * @return {@link #SUCCESS} if there is a preferred device and it was successfully retrieved
+     *     and written to the array
+     */
+    public static native int getPreferredDeviceForStrategy(int strategy,
+                                                           AudioDeviceAddress[] device);
+
     // Items shared with audio service
 
     /**
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index ef451ce..ad7335e 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -18,6 +18,7 @@
 
 import android.bluetooth.BluetoothDevice;
 import android.media.AudioAttributes;
+import android.media.AudioDeviceAddress;
 import android.media.AudioFocusInfo;
 import android.media.AudioPlaybackConfiguration;
 import android.media.AudioRecordingConfiguration;
@@ -265,6 +266,12 @@
 
     boolean isCallScreeningModeSupported();
 
+    int setPreferredDeviceForStrategy(in int strategy, in AudioDeviceAddress device);
+
+    int removePreferredDeviceForStrategy(in int strategy);
+
+    AudioDeviceAddress getPreferredDeviceForStrategy(in int strategy);
+
     // WARNING: read warning at top of file, new methods that need to be used by native
     // code via IAudioManager.h need to be added to the top section.
 }
diff --git a/media/java/android/media/IMediaRoute2ProviderClient.aidl b/media/java/android/media/IMediaRoute2ProviderClient.aidl
index 6f44d45..f4fb7f4 100644
--- a/media/java/android/media/IMediaRoute2ProviderClient.aidl
+++ b/media/java/android/media/IMediaRoute2ProviderClient.aidl
@@ -17,10 +17,13 @@
 package android.media;
 
 import android.media.MediaRoute2ProviderInfo;
+import android.media.MediaRoute2Info;
+import android.os.Bundle;
 
 /**
  * @hide
  */
 oneway interface IMediaRoute2ProviderClient {
     void updateProviderInfo(in MediaRoute2ProviderInfo info);
+    void notifyRouteSelected(String packageName, String routeId, in Bundle controlHints, int seq);
 }
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index 81a7ee2..d803f04 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -40,7 +40,6 @@
     void setSelectedRoute(IMediaRouterClient client, String routeId, boolean explicit);
     void requestSetVolume(IMediaRouterClient client, String routeId, int volume);
     void requestUpdateVolume(IMediaRouterClient client, String routeId, int direction);
-    void setControlCategories(IMediaRouterClient client, in List<String> categories);
 
     // Methods for media router 2
     List<MediaRoute2Info> getSystemRoutes();
@@ -56,7 +55,7 @@
      * @param route the route to be selected
      */
     void requestSelectRoute2(IMediaRouter2Client client, in @nullable MediaRoute2Info route);
-    void setControlCategories2(IMediaRouter2Client client, in List<String> categories);
+    void setControlCategories(IMediaRouter2Client client, in List<String> categories);
 
     void registerManager(IMediaRouter2Manager manager, String packageName);
     void unregisterManager(IMediaRouter2Manager manager);
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 63657a6..6523e30 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -36,9 +36,12 @@
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
@@ -203,6 +206,16 @@
                 securityLevel);
     }
 
+    /**
+     * @return list of crypto schemes (as {@link UUID}s) for which
+     * {@link #isCryptoSchemeSupported(UUID)} returns true; each {@link UUID}
+     * can be used as input to create {@link MediaDrm} objects via {@link #MediaDrm(UUID)}.
+     */
+    public static final @NonNull List<UUID> getSupportedCryptoSchemes(){
+        byte[] uuidBytes = getSupportedCryptoSchemesNative();
+        return getUUIDsFromByteArray(uuidBytes);
+    }
+
     private static final byte[] getByteArrayFromUUID(@NonNull UUID uuid) {
         long msb = uuid.getMostSignificantBits();
         long lsb = uuid.getLeastSignificantBits();
@@ -216,6 +229,28 @@
         return uuidBytes;
     }
 
+    private static final UUID getUUIDFromByteArray(@NonNull byte[] uuidBytes, int off) {
+        long msb = 0;
+        long lsb = 0;
+
+        for (int i = 0; i < 8; ++i) {
+            msb = (msb << 8) | (0xffl & uuidBytes[off + i]);
+            lsb = (lsb << 8) | (0xffl & uuidBytes[off + i + 8]);
+        }
+
+        return new UUID(msb, lsb);
+    }
+
+    private static final List<UUID> getUUIDsFromByteArray(@NonNull byte[] uuidBytes) {
+        Set<UUID> uuids = new LinkedHashSet<>();
+        for (int off = 0; off < uuidBytes.length; off+=16) {
+            uuids.add(getUUIDFromByteArray(uuidBytes, off));
+        }
+        return new ArrayList<>(uuids);
+    }
+
+    private static final native byte[] getSupportedCryptoSchemesNative();
+
     private static final native boolean isCryptoSchemeSupportedNative(
             @NonNull byte[] uuid, @Nullable String mimeType, @SecurityLevel int securityLevel);
 
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 8080f45..94a6f13 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -99,6 +99,8 @@
  * <tr><td>{@link #KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT}</td><td>Integer</td><td><b>decoder-only</b>, optional, if content is AAC audio, specifies the maximum number of channels the decoder outputs.</td></tr>
  * <tr><td>{@link #KEY_AAC_DRC_EFFECT_TYPE}</td><td>Integer</td><td><b>decoder-only</b>, optional, if content is AAC audio, specifies the MPEG-D DRC effect type to use.</td></tr>
  * <tr><td>{@link #KEY_CHANNEL_MASK}</td><td>Integer</td><td>optional, a mask of audio channel assignments</td></tr>
+ * <tr><td>{@link #KEY_ENCODER_DELAY}</td><td>Integer</td><td>optional, the number of frames to trim from the start of the decoded audio stream.</td></tr>
+ * <tr><td>{@link #KEY_ENCODER_PADDING}</td><td>Integer</td><td>optional, the number of frames to trim from the end of the decoded audio stream.</td></tr>
  * <tr><td>{@link #KEY_FLAC_COMPRESSION_LEVEL}</td><td>Integer</td><td><b>encoder-only</b>, optional, if content is FLAC audio, specifies the desired compression level.</td></tr>
  * </table>
  *
@@ -569,6 +571,18 @@
     public static final String KEY_CHANNEL_MASK = "channel-mask";
 
     /**
+     * A key describing the number of frames to trim from the start of the decoded audio stream.
+     * The associated value is an integer.
+     */
+    public static final String KEY_ENCODER_DELAY = "encoder-delay";
+
+    /**
+     * A key describing the number of frames to trim from the end of the decoded audio stream.
+     * The associated value is an integer.
+     */
+    public static final String KEY_ENCODER_PADDING = "encoder-padding";
+
+    /**
      * A key describing the AAC profile to be used (AAC audio formats only).
      * Constants are declared in {@link android.media.MediaCodecInfo.CodecProfileLevel}.
      */
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 9723652..abb8206 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -587,6 +587,46 @@
     }
 
     /**
+     * Indicates that this capture request is privacy sensitive and that
+     * any concurrent capture is not permitted.
+     * <p>
+     * The default is not privacy sensitive except when the audio source set with
+     * {@link #setAudioSource(int)} is {@link AudioSource#VOICE_COMMUNICATION} or
+     * {@link AudioSource#CAMCORDER}.
+     * <p>
+     * Always takes precedence over default from audio source when set explicitly.
+     * <p>
+     * Using this API is only permitted when the audio source is one of:
+     * <ul>
+     * <li>{@link AudioSource#MIC}</li>
+     * <li>{@link AudioSource#CAMCORDER}</li>
+     * <li>{@link AudioSource#VOICE_RECOGNITION}</li>
+     * <li>{@link AudioSource#VOICE_COMMUNICATION}</li>
+     * <li>{@link AudioSource#UNPROCESSED}</li>
+     * <li>{@link AudioSource#VOICE_PERFORMANCE}</li>
+     * </ul>
+     * Invoking {@link #prepare()} will throw an IOException if this
+     * condition is not met.
+     * <p>
+     * Must be called after {@link #setAudioSource(int)} and before {@link #setOutputFormat(int)}.
+     * @param privacySensitive True if capture from this MediaRecorder must be marked as privacy
+     * sensitive, false otherwise.
+     * @throws IllegalStateException if called before {@link #setAudioSource(int)}
+     * or after {@link #setOutputFormat(int)}
+     */
+    public native void setPrivacySensitive(boolean privacySensitive);
+
+    /**
+     * Returns whether this MediaRecorder is marked as privacy sensitive or not with
+     * regard to audio capture.
+     * <p>
+     * See {@link #setPrivacySensitive(boolean)}
+     * <p>
+     * @return true if privacy sensitive, false otherwise
+     */
+    public native boolean isPrivacySensitive();
+
+    /**
      * Sets the video source to be used for recording. If this method is not
      * called, the output file will not contain an video track. The source needs
      * to be specified before setting recording-parameters or encoders. Call
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index 386d2dc..1b6183e 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -18,14 +18,19 @@
 
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.Service;
 import android.content.Intent;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.util.Log;
 
+import java.util.Objects;
+
 /**
  * @hide
  */
@@ -44,7 +49,7 @@
     }
 
     @Override
-    public IBinder onBind(Intent intent) {
+    public IBinder onBind(@NonNull Intent intent) {
         //TODO: Allow binding from media router service only?
         if (SERVICE_INTERFACE.equals(intent.getAction())) {
             if (mStub == null) {
@@ -57,11 +62,17 @@
 
     /**
      * Called when selectRoute is called on a route of the provider.
+     * Once the route is ready to be used , call {@link #notifyRouteSelected(SelectToken, Bundle)}
+     * to notify that.
      *
      * @param packageName the package name of the application that selected the route
      * @param routeId the id of the route being selected
+     * @param token token that contains select info
+     *
+     * @see #notifyRouteSelected
      */
-    public abstract void onSelectRoute(String packageName, String routeId);
+    public abstract void onSelectRoute(@NonNull String packageName, @NonNull String routeId,
+            @NonNull SelectToken token);
 
     /**
      * Called when unselectRoute is called on a route of the provider.
@@ -69,7 +80,7 @@
      * @param packageName the package name of the application that has selected the route.
      * @param routeId the id of the route being unselected
      */
-    public abstract void onUnselectRoute(String packageName, String routeId);
+    public abstract void onUnselectRoute(@NonNull String packageName, @NonNull String routeId);
 
     /**
      * Called when sendControlRequest is called on a route of the provider
@@ -78,21 +89,21 @@
      * @param request the media control request intent
      */
     //TODO: Discuss what to use for request (e.g., Intent? Request class?)
-    public abstract void onControlRequest(String routeId, Intent request);
+    public abstract void onControlRequest(@NonNull String routeId, @NonNull Intent request);
 
     /**
      * Called when requestSetVolume is called on a route of the provider
      * @param routeId the id of the route
      * @param volume the target volume
      */
-    public abstract void onSetVolume(String routeId, int volume);
+    public abstract void onSetVolume(@NonNull String routeId, int volume);
 
     /**
      * Called when requestUpdateVolume is called on a route of the provider
      * @param routeId id of the route
      * @param delta the delta to add to the current volume
      */
-    public abstract void onUpdateVolume(String routeId, int delta);
+    public abstract void onUpdateVolume(@NonNull String routeId, int delta);
 
     /**
      * Updates provider info and publishes routes
@@ -102,6 +113,29 @@
         publishState();
     }
 
+    /**
+     * Notifies the client of that the selected route is ready for use. If the selected route can be
+     * controlled, pass a {@link Bundle} that contains how to control it.
+     *
+     * @param token token passed in {@link #onSelectRoute}
+     * @param controlHints a {@link Bundle} that contains how to control the given route.
+     * Pass {@code null} if the route is not available.
+     */
+    public final void notifyRouteSelected(@NonNull SelectToken token,
+            @Nullable Bundle controlHints) {
+        Objects.requireNonNull(token, "token must not be null");
+
+        if (mClient == null) {
+            return;
+        }
+        try {
+            mClient.notifyRouteSelected(token.mPackageName, token.mRouteId,
+                    controlHints, token.mSeq);
+        } catch (RemoteException ex) {
+            Log.w(TAG, "Failed to notify route selected");
+        }
+    }
+
     void setClient(IMediaRoute2ProviderClient client) {
         mClient = client;
         publishState();
@@ -118,6 +152,23 @@
         }
     }
 
+    /**
+     * Route selection information.
+     *
+     * @see #notifyRouteSelected
+     */
+    public final class SelectToken {
+        final String mPackageName;
+        final String mRouteId;
+        final int mSeq;
+
+        SelectToken(String packageName, String routeId, int seq) {
+            mPackageName = packageName;
+            mRouteId = routeId;
+            mSeq = seq;
+        }
+    }
+
     final class ProviderStub extends IMediaRoute2Provider.Stub {
         ProviderStub() { }
 
@@ -129,10 +180,10 @@
 
         @Override
         public void requestSelectRoute(String packageName, String id, int seq) {
-            // TODO: When introducing MediaRoute2ProviderService#sendConnectionHints(),
-            // use the sequence number here properly.
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSelectRoute,
-                    MediaRoute2ProviderService.this, packageName, id));
+                    MediaRoute2ProviderService.this, packageName, id,
+                    new SelectToken(packageName, id, seq)));
+
         }
 
         @Override
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 9cb7869..d72231f 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -49,8 +49,6 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Objects;
@@ -84,7 +82,6 @@
 
         final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
         final ArrayList<RouteCategory> mCategories = new ArrayList<RouteCategory>();
-        List<String> mControlCategories = Collections.emptyList();
 
         final RouteCategory mSystemCategory;
 
@@ -361,18 +358,6 @@
             return mDisplayService.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION);
         }
 
-        public void setControlCategories(Collection<String> controlCategories) {
-            List<String> newControlCategories = new ArrayList<>(controlCategories);
-            mControlCategories = newControlCategories;
-            if (mClient != null) {
-                try {
-                    mMediaRouterService.setControlCategories(mClient, newControlCategories);
-                } catch (RemoteException ex) {
-                    Log.e(TAG, "Unable to set control categories.", ex);
-                }
-            }
-        }
-
         private void updatePresentationDisplays(int changedDisplayId) {
             final int count = mRoutes.size();
             for (int i = 0; i < count; i++) {
@@ -421,7 +406,6 @@
                 try {
                     Client client = new Client();
                     mMediaRouterService.registerClientAsUser(client, mPackageName, userId);
-                    mMediaRouterService.setControlCategories(client, mControlCategories);
                     mClient = client;
                 } catch (RemoteException ex) {
                     Log.e(TAG, "Unable to register media router client.", ex);
@@ -1318,19 +1302,6 @@
         sStatic.rebindAsUser(userId);
     }
 
-    /**
-     * Sets the control categories of the application.
-     * Routes that support at least one of the given control categories only exists and are handled
-     * by the media router.
-     *
-     * @hide
-     */
-    public void setControlCategories(@NonNull Collection<String> controlCategories) {
-        Objects.requireNonNull(controlCategories, "control categories must not be null");
-
-        sStatic.setControlCategories(controlCategories);
-    }
-
     static void updateRoute(final RouteInfo info) {
         dispatchRouteChanged(info);
     }
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 94ac77a..3e6f4c0 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -57,7 +57,8 @@
     @IntDef(value = {
             SELECT_REASON_UNKNOWN,
             SELECT_REASON_USER_SELECTED,
-            SELECT_REASON_FALLBACK})
+            SELECT_REASON_FALLBACK,
+            SELECT_REASON_SYSTEM_SELECTED})
     public @interface SelectReason {}
 
     /**
@@ -80,6 +81,13 @@
      */
     public static final int SELECT_REASON_FALLBACK = 2;
 
+    /**
+     * This is passed from {@link com.android.server.media.MediaRouterService} when the route
+     * is selected in response to a request from other apps (e.g. System UI).
+     * @hide
+     */
+    public static final int SELECT_REASON_SYSTEM_SELECTED = 3;
+
     private static final String TAG = "MR2";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     private static final Object sLock = new Object();
@@ -106,7 +114,7 @@
     @GuardedBy("sLock")
     private MediaRoute2Info mSelectingRoute;
     @GuardedBy("sLock")
-    private Client mClient;
+    private Client2 mClient;
 
     final Handler mHandler;
     volatile List<MediaRoute2Info> mFilteredRoutes = Collections.emptyList();
@@ -188,10 +196,10 @@
 
         synchronized (sLock) {
             if (mClient == null) {
-                Client client = new Client();
+                Client2 client = new Client2();
                 try {
                     mMediaRouterService.registerClient2(client, mPackageName);
-                    mMediaRouterService.setControlCategories2(client, mControlCategories);
+                    mMediaRouterService.setControlCategories(client, mControlCategories);
                     mClient = client;
                 } catch (RemoteException ex) {
                     Log.e(TAG, "Unable to register media router.", ex);
@@ -280,7 +288,7 @@
     public void requestSelectRoute(@NonNull MediaRoute2Info route) {
         Objects.requireNonNull(route, "route must not be null");
 
-        Client client;
+        Client2 client;
         synchronized (sLock) {
             if (mSelectingRoute == route) {
                 Log.w(TAG, "The route selection request is already sent.");
@@ -310,7 +318,7 @@
         Objects.requireNonNull(route, "route must not be null");
         Objects.requireNonNull(request, "request must not be null");
 
-        Client client;
+        Client2 client;
         synchronized (sLock) {
             client = mClient;
         }
@@ -334,7 +342,7 @@
     public void requestSetVolume(@NonNull MediaRoute2Info route, int volume) {
         Objects.requireNonNull(route, "route must not be null");
 
-        Client client;
+        Client2 client;
         synchronized (sLock) {
             client = mClient;
         }
@@ -358,7 +366,7 @@
     public void requestUpdateVolume(@NonNull MediaRoute2Info route, int delta) {
         Objects.requireNonNull(route, "route must not be null");
 
-        Client client;
+        Client2 client;
         synchronized (sLock) {
             client = mClient;
         }
@@ -390,13 +398,13 @@
         List<MediaRoute2Info> filteredRoutes = new ArrayList<>();
 
         mControlCategories = newControlCategories;
-        Client client;
+        Client2 client;
         synchronized (sLock) {
             client = mClient;
         }
         if (client != null) {
             try {
-                mMediaRouterService.setControlCategories2(client, mControlCategories);
+                mMediaRouterService.setControlCategories(client, mControlCategories);
             } catch (RemoteException ex) {
                 Log.e(TAG, "Unable to set control categories.", ex);
             }
@@ -485,6 +493,9 @@
             }
             mSelectingRoute = null;
         }
+        if (reason == SELECT_REASON_SYSTEM_SELECTED) {
+            reason = SELECT_REASON_USER_SELECTED;
+        }
         mSelectedRoute = route;
         notifyRouteSelected(route, reason, controlHints);
     }
@@ -589,7 +600,7 @@
         }
     }
 
-    class Client extends IMediaRouter2Client.Stub {
+    class Client2 extends IMediaRouter2Client.Stub {
         @Override
         public void notifyRestoreRoute() throws RemoteException {}
 
diff --git a/media/java/android/media/MediaScannerConnection.java b/media/java/android/media/MediaScannerConnection.java
index 8d85724..515f6a8 100644
--- a/media/java/android/media/MediaScannerConnection.java
+++ b/media/java/android/media/MediaScannerConnection.java
@@ -164,7 +164,7 @@
 
     /**
      * Convenience for constructing a {@link MediaScannerConnection}, calling
-     * {@link #connect} on it, and calling {@link #scanFile} with the given
+     * {@link #connect} on it, and calling {@link #scanFile(String, String)} with the given
      * <var>path</var> and <var>mimeType</var> when the connection is
      * established.
      * @param context The caller's Context, required for establishing a connection to
diff --git a/media/java/android/media/audiopolicy/AudioProductStrategy.java b/media/java/android/media/audiopolicy/AudioProductStrategy.java
index 2799d46..612f83a 100644
--- a/media/java/android/media/audiopolicy/AudioProductStrategy.java
+++ b/media/java/android/media/audiopolicy/AudioProductStrategy.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.media.AudioAttributes;
 import android.media.AudioSystem;
 import android.media.MediaRecorder;
@@ -82,6 +83,18 @@
 
     /**
      * @hide
+     * Create an invalid AudioProductStrategy instance for testing
+     * @param id the ID for the invalid strategy, always use a different one than in use
+     * @return an invalid instance that cannot successfully be used for volume groups or routing
+     */
+    @TestApi
+    @SystemApi
+    public static @NonNull AudioProductStrategy createInvalidAudioProductStrategy(int id) {
+        return new AudioProductStrategy("dummy strategy", id, new AudioAttributesGroup[0]);
+    }
+
+    /**
+     * @hide
      * @param streamType to match against AudioProductStrategy
      * @return the AudioAttributes for the first strategy found with the associated stream type
      *          If no match is found, returns AudioAttributes with unknown content_type and usage
@@ -222,6 +235,7 @@
      * @return true if the {@link AudioProductStrategy} supports the given {@link AudioAttributes},
      *         false otherwise.
      */
+    @SystemApi
     public boolean supportsAudioAttributes(@NonNull AudioAttributes aa) {
         Preconditions.checkNotNull(aa, "AudioAttributes must not be null");
         for (final AudioAttributesGroup aag : mAudioAttributesGroups) {
diff --git a/media/java/android/media/tv/tuner/FilterSettings.java b/media/java/android/media/tv/tuner/FilterSettings.java
new file mode 100644
index 0000000..d5f1003
--- /dev/null
+++ b/media/java/android/media/tv/tuner/FilterSettings.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tuner;
+
+import android.annotation.Nullable;
+import android.hardware.tv.tuner.V1_0.Constants;
+import android.media.tv.tuner.TunerConstants.FilterSettingsType;
+
+import java.util.List;
+
+/**
+ * Demux Filter settings.
+ *
+ * @hide
+ */
+public abstract class FilterSettings {
+    @Nullable
+    protected final Settings mSettings;
+
+    protected FilterSettings(Settings settings) {
+        mSettings = settings;
+    }
+
+    /**
+     * Gets filter settings type
+     */
+    @FilterSettingsType public abstract int getType();
+
+    // TODO: more builders and getters
+
+    /**
+     *  Filter Settings for a TS filter.
+     */
+    public static class TsFilterSettings extends FilterSettings {
+        private int mTpid;
+
+        private TsFilterSettings(Settings settings, int tpid) {
+            super(settings);
+            mTpid = tpid;
+        }
+
+        @Override
+        public int getType() {
+            return TunerConstants.FILTER_SETTINGS_TS;
+        }
+
+        /**
+         * Creates a new builder.
+         */
+        public static Builder newBuilder() {
+            return new Builder();
+        }
+
+        /**
+         * Builder for TsFilterSettings.
+         */
+        public static class Builder {
+            private Settings mSettings;
+            private int mTpid;
+
+            /**
+             * Sets settings.
+             */
+            public Builder setSettings(Settings settings) {
+                mSettings = settings;
+                return this;
+            }
+
+            /**
+             * Sets TPID.
+             */
+            public Builder setTpid(int tpid) {
+                mTpid = tpid;
+                return this;
+            }
+
+            /**
+             * Builds a TsFilterSettings instance.
+             */
+            public TsFilterSettings build() {
+                return new TsFilterSettings(mSettings, mTpid);
+            }
+        }
+    }
+
+    /**
+     *  Filter Settings for a MMTP filter.
+     */
+    public static class MmtpFilterSettings extends FilterSettings {
+        private int mMmtpPid;
+
+        public MmtpFilterSettings(Settings settings) {
+            super(settings);
+        }
+
+        @Override
+        public int getType() {
+            return TunerConstants.FILTER_SETTINGS_MMTP;
+        }
+    }
+
+
+    /**
+     *  Filter Settings for a IP filter.
+     */
+    public static class IpFilterSettings extends FilterSettings {
+        private byte[] mSrcIpAddress;
+        private byte[] mDstIpAddress;
+        private int mSrcPort;
+        private int mDstPort;
+        private boolean mPassthrough;
+
+        public IpFilterSettings(Settings settings) {
+            super(settings);
+        }
+
+        @Override
+        public int getType() {
+            return TunerConstants.FILTER_SETTINGS_IP;
+        }
+    }
+
+
+    /**
+     *  Filter Settings for a TLV filter.
+     */
+    public static class TlvFilterSettings extends FilterSettings {
+        private int mPacketType;
+        private boolean mIsCompressedIpPacket;
+        private boolean mPassthrough;
+
+        public TlvFilterSettings(Settings settings) {
+            super(settings);
+        }
+
+        @Override
+        public int getType() {
+            return TunerConstants.FILTER_SETTINGS_TLV;
+        }
+    }
+
+
+    /**
+     *  Filter Settings for a ALP filter.
+     */
+    public static class AlpFilterSettings extends FilterSettings {
+        private int mPacketType;
+        private int mLengthType;
+
+        public AlpFilterSettings(Settings settings) {
+            super(settings);
+        }
+
+        @Override
+        public int getType() {
+            return TunerConstants.FILTER_SETTINGS_ALP;
+        }
+    }
+
+
+    /**
+     *  Settings for filters of different subtypes.
+     */
+    public abstract static class Settings {
+        protected final int mType;
+
+        protected Settings(int type) {
+            mType = type;
+        }
+
+        /**
+         * Gets filter settings type.
+         * @return
+         */
+        int getType() {
+            return mType;
+        }
+    }
+
+    /**
+     *  Filter Settings for Section data according to ISO/IEC 13818-1.
+     */
+    public static class SectionSettings extends Settings {
+
+        private SectionSettings(int mainType) {
+            super(SectionSettings.findType(mainType));
+        }
+
+        private static int findType(int mainType) {
+            switch (mainType) {
+                case TunerConstants.FILTER_SETTINGS_TS:
+                    return Constants.DemuxTsFilterType.SECTION;
+                case TunerConstants.FILTER_SETTINGS_MMTP:
+                    return Constants.DemuxMmtpFilterType.SECTION;
+                case TunerConstants.FILTER_SETTINGS_IP:
+                    return Constants.DemuxIpFilterType.SECTION;
+                case TunerConstants.FILTER_SETTINGS_TLV:
+                    return Constants.DemuxTlvFilterType.SECTION;
+                case TunerConstants.FILTER_SETTINGS_ALP:
+                    return Constants.DemuxAlpFilterType.SECTION;
+            }
+            // UNDEFINED
+            return 0;
+        }
+    }
+
+    /**
+     *  Bits Settings for Section Filter.
+     */
+    public static class SectionSettingsWithSectionBits extends SectionSettings {
+        private List<Byte> mFilter;
+        private List<Byte> mMask;
+        private List<Byte> mMode;
+
+        private SectionSettingsWithSectionBits(int mainType) {
+            super(mainType);
+        }
+    }
+
+    /**
+     *  Table information for Section Filter.
+     */
+    public static class SectionSettingsWithTableInfo extends SectionSettings {
+        private int mTableId;
+        private int mVersion;
+
+        private SectionSettingsWithTableInfo(int mainType) {
+            super(mainType);
+        }
+    }
+
+    /**
+     *  Filter Settings for a PES Data.
+     */
+    public static class PesSettings extends Settings {
+        private int mStreamId;
+        private boolean mIsRaw;
+
+        private PesSettings(int mainType, int streamId, boolean isRaw) {
+            super(PesSettings.findType(mainType));
+            mStreamId = streamId;
+            mIsRaw = isRaw;
+        }
+
+        private static int findType(int mainType) {
+            switch (mainType) {
+                case TunerConstants.FILTER_SETTINGS_TS:
+                    return Constants.DemuxTsFilterType.PES;
+                case TunerConstants.FILTER_SETTINGS_MMTP:
+                    return Constants.DemuxMmtpFilterType.PES;
+            }
+            // UNDEFINED
+            return 0;
+        }
+
+        /**
+         * Creates a builder for PesSettings.
+         */
+        public static Builder newBuilder(int mainType) {
+            return new Builder(mainType);
+        }
+
+        /**
+         * Builder for PesSettings.
+         */
+        public static class Builder {
+            private final int mMainType;
+            private int mStreamId;
+            private boolean mIsRaw;
+
+            public Builder(int mainType) {
+                mMainType = mainType;
+            }
+
+            /**
+             * Sets stream ID.
+             */
+            public Builder setStreamId(int streamId) {
+                mStreamId = streamId;
+                return this;
+            }
+
+            /**
+             * Sets whether it's raw.
+             * true if the filter send onFilterStatus instead of onFilterEvent.
+             */
+            public Builder setIsRaw(boolean isRaw) {
+                mIsRaw = isRaw;
+                return this;
+            }
+
+            /**
+             * Builds a PesSettings instance.
+             */
+            public PesSettings build() {
+                return new PesSettings(mMainType, mStreamId, mIsRaw);
+            }
+        }
+    }
+
+    /**
+     *  Filter Settings for a Video and Audio.
+     */
+    public static class AvSettings extends Settings {
+        private boolean mIsPassthrough;
+
+        private AvSettings(int mainType, boolean isAudio) {
+            super(AvSettings.findType(mainType, isAudio));
+        }
+
+        private static int findType(int mainType, boolean isAudio) {
+            switch (mainType) {
+                case TunerConstants.FILTER_SETTINGS_TS:
+                    return isAudio
+                            ? Constants.DemuxTsFilterType.AUDIO
+                            : Constants.DemuxTsFilterType.VIDEO;
+                case TunerConstants.FILTER_SETTINGS_MMTP:
+                    return isAudio
+                            ? Constants.DemuxMmtpFilterType.AUDIO
+                            : Constants.DemuxMmtpFilterType.VIDEO;
+            }
+            // UNDEFINED
+            return 0;
+        }
+    }
+
+    /**
+     *  Filter Settings for a Download.
+     */
+    public static class DownloadSettings extends Settings {
+        private int mDownloadId;
+
+        public DownloadSettings(int mainType) {
+            super(DownloadSettings.findType(mainType));
+        }
+
+        private static int findType(int mainType) {
+            if (mainType == TunerConstants.FILTER_SETTINGS_MMTP) {
+                return Constants.DemuxMmtpFilterType.DOWNLOAD;
+            }
+            // UNDEFINED
+            return 0;
+        }
+    }
+
+    /**
+     *  The Settings for the record in DVR.
+     */
+    public static class RecordSettings extends Settings {
+        private int mIndexType;
+        private int mIndexMask;
+
+        public RecordSettings(int mainType) {
+            super(RecordSettings.findType(mainType));
+        }
+
+        private static int findType(int mainType) {
+            switch (mainType) {
+                case TunerConstants.FILTER_SETTINGS_TS:
+                    return Constants.DemuxTsFilterType.RECORD;
+                case TunerConstants.FILTER_SETTINGS_MMTP:
+                    return Constants.DemuxMmtpFilterType.RECORD;
+            }
+            // UNDEFINED
+            return 0;
+        }
+    }
+
+}
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 82cef2e..6537f6f 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -243,9 +243,11 @@
         private FilterCallback mCallback;
         int mId;
 
+        private native int nativeConfigureFilter(int type, int subType, FilterSettings settings);
         private native boolean nativeStartFilter();
         private native boolean nativeStopFilter();
         private native boolean nativeFlushFilter();
+        private native int nativeRead(byte[] buffer, int offset, int size);
 
         private Filter(int id) {
             mId = id;
@@ -258,6 +260,14 @@
             }
         }
 
+        public int configure(FilterSettings settings) {
+            int subType = -1;
+            if (settings.mSettings != null) {
+                subType = settings.mSettings.getType();
+            }
+            return nativeConfigureFilter(settings.getType(), subType, settings);
+        }
+
         public boolean start() {
             return nativeStartFilter();
         }
@@ -269,6 +279,11 @@
         public boolean flush() {
             return nativeFlushFilter();
         }
+
+        public int read(@NonNull byte[] buffer, int offset, int size) {
+            size = Math.min(size, buffer.length - offset);
+            return nativeRead(buffer, offset, size);
+        }
     }
 
     private Filter openFilter(int type, int subType, int bufferSize, FilterCallback cb) {
diff --git a/media/java/android/media/tv/tuner/TunerConstants.java b/media/java/android/media/tv/tuner/TunerConstants.java
index 458cb16..f2d5e93 100644
--- a/media/java/android/media/tv/tuner/TunerConstants.java
+++ b/media/java/android/media/tv/tuner/TunerConstants.java
@@ -90,6 +90,17 @@
     public static final int FRONTEND_SETTINGS_ISDBS3 = 8;
     public static final int FRONTEND_SETTINGS_ISDBT = 9;
 
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({FILTER_SETTINGS_TS, FILTER_SETTINGS_MMTP, FILTER_SETTINGS_IP, FILTER_SETTINGS_TLV,
+            FILTER_SETTINGS_ALP})
+    public @interface FilterSettingsType {}
+
+    public static final int FILTER_SETTINGS_TS = Constants.DemuxFilterMainType.TS;
+    public static final int FILTER_SETTINGS_MMTP = Constants.DemuxFilterMainType.MMTP;
+    public static final int FILTER_SETTINGS_IP = Constants.DemuxFilterMainType.IP;
+    public static final int FILTER_SETTINGS_TLV = Constants.DemuxFilterMainType.TLV;
+    public static final int FILTER_SETTINGS_ALP = Constants.DemuxFilterMainType.ALP;
+
     private TunerConstants() {
     }
 }
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 2f53cbb..4ca23a1 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -41,6 +41,7 @@
         "libmedia_omx",
         "libmediametrics",
         "libmediadrm",
+        "libmediadrmmetrics_consumer",
         "libhwui",
         "libui",
         "liblog",
@@ -58,6 +59,7 @@
         "libsonivox",
         "android.hardware.cas@1.0",
         "android.hardware.cas.native@1.0",
+        "android.hardware.drm@1.3",
         "android.hidl.memory@1.0",
         "android.hidl.token@1.0-utils",
     ],
@@ -133,6 +135,8 @@
     shared_libs: [
         "android.hardware.tv.tuner@1.0",
         "libandroid_runtime",
+        "libcutils",
+        "libfmq",
         "libhidlbase",
         "liblog",
         "libutils",
diff --git a/media/jni/android_media_MediaDataSource.h b/media/jni/android_media_MediaDataSource.h
index 378baf4..b65039d3 100644
--- a/media/jni/android_media_MediaDataSource.h
+++ b/media/jni/android_media_MediaDataSource.h
@@ -19,7 +19,7 @@
 
 #include "jni.h"
 
-#include <media/IDataSource.h>
+#include <android/IDataSource.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <utils/Errors.h>
 #include <utils/Mutex.h>
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 3833c6b..f38a29c 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -27,16 +27,19 @@
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
 
+#include <android/hardware/drm/1.3/IDrmFactory.h>
 #include <binder/Parcel.h>
 #include <binder/PersistableBundle.h>
 #include <cutils/properties.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaErrors.h>
+#include <mediadrm/DrmMetricsConsumer.h>
 #include <mediadrm/DrmUtils.h>
+#include <mediadrm/IDrmMetricsConsumer.h>
 #include <mediadrm/IDrm.h>
 
 using ::android::os::PersistableBundle;
-
+namespace drm = ::android::hardware::drm;
 
 namespace android {
 
@@ -969,6 +972,26 @@
     return level;
 }
 
+static jbyteArray android_media_MediaDrm_getSupportedCryptoSchemesNative(JNIEnv *env) {
+    std::vector<uint8_t> bv;
+    for (auto &factory : DrmUtils::MakeDrmFactories()) {
+        sp<drm::V1_3::IDrmFactory> factoryV1_3 = drm::V1_3::IDrmFactory::castFrom(factory);
+        if (factoryV1_3 == nullptr) {
+            continue;
+        }
+        factoryV1_3->getSupportedCryptoSchemes(
+            [&](const hardware::hidl_vec<hardware::hidl_array<uint8_t, 16>>& schemes) {
+                for (const auto &scheme : schemes) {
+                    bv.insert(bv.end(), scheme.data(), scheme.data() + scheme.size());
+                }
+            });
+    }
+
+    jbyteArray jUuidBytes = env->NewByteArray(bv.size());
+    env->SetByteArrayRegion(jUuidBytes, 0, bv.size(), reinterpret_cast<const jbyte *>(bv.data()));
+    return jUuidBytes;
+}
+
 static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
         JNIEnv *env, jobject /* thiz */, jbyteArray uuidObj, jstring jmimeType,
         jint jSecurityLevel) {
@@ -1889,7 +1912,8 @@
 
     // Retrieve current metrics snapshot from drm.
     PersistableBundle metrics;
-    status_t err = drm->getMetrics(&metrics);
+    sp<IDrmMetricsConsumer> consumer(new DrmMetricsConsumer(&metrics));
+    status_t err = drm->getMetrics(consumer);
     if (err != OK) {
         ALOGE("getMetrics failed: %d", (int)err);
         return (jobject) NULL;
@@ -1938,6 +1962,9 @@
     { "native_setup", "(Ljava/lang/Object;[BLjava/lang/String;)V",
       (void *)android_media_MediaDrm_native_setup },
 
+    { "getSupportedCryptoSchemesNative", "()[B",
+      (void *)android_media_MediaDrm_getSupportedCryptoSchemesNative },
+
     { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;I)Z",
       (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
 
diff --git a/media/jni/android_media_MediaMetricsJNI.cpp b/media/jni/android_media_MediaMetricsJNI.cpp
index 5ddfcfc..d315154 100644
--- a/media/jni/android_media_MediaMetricsJNI.cpp
+++ b/media/jni/android_media_MediaMetricsJNI.cpp
@@ -16,213 +16,112 @@
 
 #define LOG_TAG "MediaMetricsJNI"
 
+#include <binder/Parcel.h>
 #include <jni.h>
+#include <media/MediaAnalyticsItem.h>
 #include <nativehelper/JNIHelp.h>
 
 #include "android_media_MediaMetricsJNI.h"
 #include "android_os_Parcel.h"
-#include <media/MediaAnalyticsItem.h>
-#include <binder/Parcel.h>
-
 
 // This source file is compiled and linked into:
 // core/jni/ (libandroid_runtime.so)
 
 namespace android {
 
+namespace {
+struct BundleHelper {
+    BundleHelper(JNIEnv* _env, jobject _bundle)
+        : env(_env)
+        , clazzBundle(env->FindClass("android/os/PersistableBundle"))
+        , putIntID(env->GetMethodID(clazzBundle, "putInt", "(Ljava/lang/String;I)V"))
+        , putLongID(env->GetMethodID(clazzBundle, "putLong", "(Ljava/lang/String;J)V"))
+        , putDoubleID(env->GetMethodID(clazzBundle, "putDouble", "(Ljava/lang/String;D)V"))
+        , putStringID(env->GetMethodID(clazzBundle,
+                      "putString", "(Ljava/lang/String;Ljava/lang/String;)V"))
+        , constructID(env->GetMethodID(clazzBundle, "<init>", "()V"))
+        , bundle(_bundle == nullptr ? env->NewObject(clazzBundle, constructID) : _bundle)
+        { }
+
+    JNIEnv* const env;
+    const jclass clazzBundle;
+    const jmethodID putIntID;
+    const jmethodID putLongID;
+    const jmethodID putDoubleID;
+    const jmethodID putStringID;
+    const jmethodID constructID;
+    jobject const bundle;
+
+    // We use templated put to access MediaAnalyticsItem based on data type not type enum.
+    // See std::variant and std::visit.
+    template<typename T>
+    void put(jstring keyName, const T& value) = delete;
+
+    template<>
+    void put(jstring keyName, const int32_t& value) {
+        env->CallVoidMethod(bundle, putIntID, keyName, (jint)value);
+    }
+
+    template<>
+    void put(jstring keyName, const int64_t& value) {
+        env->CallVoidMethod(bundle, putLongID, keyName, (jlong)value);
+    }
+
+    template<>
+    void put(jstring keyName, const double& value) {
+        env->CallVoidMethod(bundle, putDoubleID, keyName, (jdouble)value);
+    }
+
+    template<>
+    void put(jstring keyName, const char * const& value) {
+        env->CallVoidMethod(bundle, putStringID, keyName, env->NewStringUTF(value));
+    }
+
+    template<>
+    void put(jstring keyName, char * const& value) {
+        env->CallVoidMethod(bundle, putStringID, keyName, env->NewStringUTF(value));
+    }
+
+    template<>
+    void put(jstring keyName, const std::pair<int64_t, int64_t>& value) {
+        ; // rate is currently ignored
+    }
+
+    // We allow both jstring and non-jstring variants.
+    template<typename T>
+    void put(const char *keyName, const T& value) {
+        put(env->NewStringUTF(keyName), value);
+    }
+};
+} // namespace
+
 // place the attributes into a java PersistableBundle object
-jobject MediaMetricsJNI::writeMetricsToBundle(JNIEnv* env, MediaAnalyticsItem *item, jobject mybundle) {
+jobject MediaMetricsJNI::writeMetricsToBundle(
+        JNIEnv* env, MediaAnalyticsItem *item, jobject bundle)
+{
+    BundleHelper bh(env, bundle);
 
-    jclass clazzBundle = env->FindClass("android/os/PersistableBundle");
-    if (clazzBundle==NULL) {
-        ALOGE("can't find android/os/PersistableBundle");
-        return NULL;
-    }
-    // sometimes the caller provides one for us to fill
-    if (mybundle == NULL) {
-        // create the bundle
-        jmethodID constructID = env->GetMethodID(clazzBundle, "<init>", "()V");
-        mybundle = env->NewObject(clazzBundle, constructID);
-        if (mybundle == NULL) {
-            return NULL;
-        }
+    if (bh.bundle == nullptr) {
+        ALOGE("%s: unable to create Bundle", __func__);
+        return nullptr;
     }
 
-    // grab methods that we can invoke
-    jmethodID setIntID = env->GetMethodID(clazzBundle, "putInt", "(Ljava/lang/String;I)V");
-    jmethodID setLongID = env->GetMethodID(clazzBundle, "putLong", "(Ljava/lang/String;J)V");
-    jmethodID setDoubleID = env->GetMethodID(clazzBundle, "putDouble", "(Ljava/lang/String;D)V");
-    jmethodID setStringID = env->GetMethodID(clazzBundle, "putString", "(Ljava/lang/String;Ljava/lang/String;)V");
-
-    // env, class, method, {parms}
-    //env->CallVoidMethod(env, mybundle, setIntID, jstr, jint);
-
-    // iterate through my attributes
-    // -- get name, get type, get value
-    // -- insert appropriately into the bundle
-    for (size_t i = 0 ; i < item->mPropCount; i++ ) {
-            MediaAnalyticsItem::Prop *prop = &item->mProps[i];
-            // build the key parameter from prop->mName
-            jstring keyName = env->NewStringUTF(prop->mName);
-            // invoke the appropriate method to insert
-            switch (prop->mType) {
-                case MediaAnalyticsItem::kTypeInt32:
-                    env->CallVoidMethod(mybundle, setIntID,
-                                        keyName, (jint) prop->u.int32Value);
-                    break;
-                case MediaAnalyticsItem::kTypeInt64:
-                    env->CallVoidMethod(mybundle, setLongID,
-                                        keyName, (jlong) prop->u.int64Value);
-                    break;
-                case MediaAnalyticsItem::kTypeDouble:
-                    env->CallVoidMethod(mybundle, setDoubleID,
-                                        keyName, (jdouble) prop->u.doubleValue);
-                    break;
-                case MediaAnalyticsItem::kTypeCString:
-                    env->CallVoidMethod(mybundle, setStringID, keyName,
-                                        env->NewStringUTF(prop->u.CStringValue));
-                    break;
-                default:
-                        ALOGE("to_String bad item type: %d for %s",
-                              prop->mType, prop->mName);
-                        break;
-            }
+    bh.put("__key", item->getKey().c_str());
+    if (item->getPid() != -1) {
+        bh.put("__pid", (int32_t)item->getPid());
     }
-
-    return mybundle;
-}
-
-// convert the specified batch  metrics attributes to a persistent bundle.
-// The encoding of the byte array is specified in
-//     frameworks/av/media/libmediametrics/MediaAnalyticsItem.cpp
-//
-// type encodings; matches frameworks/av/media/libmediametrics/MediaAnalyticsItem.cpp
-enum { kInt32 = 0, kInt64, kDouble, kRate, kCString};
-
-jobject MediaMetricsJNI::writeAttributesToBundle(JNIEnv* env, jobject mybundle, char *buffer, size_t length) {
-    ALOGV("writeAttributes()");
-
-    if (buffer == NULL || length <= 0) {
-        ALOGW("bad parameters to writeAttributesToBundle()");
-        return NULL;
+    if (item->getTimestamp() > 0) {
+        bh.put("__timestamp", (int64_t)item->getTimestamp());
     }
-
-    jclass clazzBundle = env->FindClass("android/os/PersistableBundle");
-    if (clazzBundle==NULL) {
-        ALOGE("can't find android/os/PersistableBundle");
-        return NULL;
+    if (item->getUid() != -1) {
+        bh.put("__uid", (int32_t)item->getUid());
     }
-    // sometimes the caller provides one for us to fill
-    if (mybundle == NULL) {
-        // create the bundle
-        jmethodID constructID = env->GetMethodID(clazzBundle, "<init>", "()V");
-        mybundle = env->NewObject(clazzBundle, constructID);
-        if (mybundle == NULL) {
-            ALOGD("unable to create mybundle");
-            return NULL;
-        }
+    for (const auto &prop : *item) {
+        const char *name = prop.getName();
+        if (name == nullptr) continue;
+        prop.visit([&] (auto &value) { bh.put(name, value); });
     }
-
-    int left = length;
-    char *buf = buffer;
-
-    // grab methods that we can invoke
-    jmethodID setIntID = env->GetMethodID(clazzBundle, "putInt", "(Ljava/lang/String;I)V");
-    jmethodID setLongID = env->GetMethodID(clazzBundle, "putLong", "(Ljava/lang/String;J)V");
-    jmethodID setDoubleID = env->GetMethodID(clazzBundle, "putDouble", "(Ljava/lang/String;D)V");
-    jmethodID setStringID = env->GetMethodID(clazzBundle, "putString", "(Ljava/lang/String;Ljava/lang/String;)V");
-
-
-#define _EXTRACT(size, val) \
-    { if ((size) > left) goto badness; memcpy(&val, buf, (size)); buf += (size); left -= (size);}
-#define _SKIP(size) \
-    { if ((size) > left) goto badness; buf += (size); left -= (size);}
-
-    int32_t bufsize;
-    _EXTRACT(sizeof(int32_t), bufsize);
-    if (bufsize != length) {
-        goto badness;
-    }
-    int32_t proto;
-    _EXTRACT(sizeof(int32_t), proto);
-    if (proto != 0) {
-        ALOGE("unsupported wire protocol %d", proto);
-        goto badness;
-    }
-
-    int32_t count;
-    _EXTRACT(sizeof(int32_t), count);
-
-    // iterate through my attributes
-    // -- get name, get type, get value, insert into bundle appropriately.
-    for (int i = 0 ; i < count; i++ ) {
-            // prop name len (int16)
-            int16_t keylen;
-            _EXTRACT(sizeof(int16_t), keylen);
-            if (keylen <= 0) goto badness;
-            // prop name itself
-            char *key = buf;
-            jstring keyName = env->NewStringUTF(buf);
-            _SKIP(keylen);
-
-            // prop type (int8_t)
-            int8_t attrType;
-            _EXTRACT(sizeof(int8_t), attrType);
-
-	    int16_t attrSize;
-            _EXTRACT(sizeof(int16_t), attrSize);
-
-            switch (attrType) {
-                case kInt32:
-                    {
-                        int32_t i32;
-                        _EXTRACT(sizeof(int32_t), i32);
-                        env->CallVoidMethod(mybundle, setIntID,
-                                            keyName, (jint) i32);
-                        break;
-                    }
-                case kInt64:
-                    {
-                        int64_t i64;
-                        _EXTRACT(sizeof(int64_t), i64);
-                        env->CallVoidMethod(mybundle, setLongID,
-                                            keyName, (jlong) i64);
-                        break;
-                    }
-                case kDouble:
-                    {
-                        double d64;
-                        _EXTRACT(sizeof(double), d64);
-                        env->CallVoidMethod(mybundle, setDoubleID,
-                                            keyName, (jdouble) d64);
-                        break;
-                    }
-                case kCString:
-                    {
-                        jstring value = env->NewStringUTF(buf);
-                        env->CallVoidMethod(mybundle, setStringID,
-                                            keyName, value);
-                        _SKIP(attrSize);
-                        break;
-                    }
-                default:
-                        ALOGW("ignoring Attribute '%s' unknown type: %d",
-                              key, attrType);
-			_SKIP(attrSize);
-                        break;
-            }
-    }
-
-    // should have consumed it all
-    if (left != 0) {
-        ALOGW("did not consume entire buffer; left(%d) != 0", left);
-	goto badness;
-    }
-
-    return mybundle;
-
-  badness:
-    return NULL;
+    return bh.bundle;
 }
 
 // Helper function to convert a native PersistableBundle to a Java
diff --git a/media/jni/android_media_MediaMetricsJNI.h b/media/jni/android_media_MediaMetricsJNI.h
index e879da0..63ec27a 100644
--- a/media/jni/android_media_MediaMetricsJNI.h
+++ b/media/jni/android_media_MediaMetricsJNI.h
@@ -28,7 +28,6 @@
 class MediaMetricsJNI {
 public:
     static jobject writeMetricsToBundle(JNIEnv* env, MediaAnalyticsItem *item, jobject mybundle);
-    static jobject writeAttributesToBundle(JNIEnv* env, jobject mybundle, char *buffer, size_t length);
     static jobject nativeToJavaPersistableBundle(JNIEnv*, os::PersistableBundle*);
 };
 
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 24fff06..f8ba36d 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -227,6 +227,36 @@
 }
 
 static void
+android_media_MediaRecorder_setPrivacySensitive(JNIEnv *env, jobject thiz, jboolean privacySensitive)
+{
+    ALOGV("%s(%s)", __func__, privacySensitive ? "true" : "false");
+
+    sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
+    if (mr == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return;
+    }
+    process_media_recorder_call(env, mr->setPrivacySensitive(privacySensitive),
+        "java/lang/RuntimeException", "setPrivacySensitive failed.");
+}
+
+static jboolean
+android_media_MediaRecorder_isPrivacySensitive(JNIEnv *env, jobject thiz)
+{
+    sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
+    if (mr == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return false;
+    }
+    bool privacySensitive;
+    process_media_recorder_call(env, mr->isPrivacySensitive(&privacySensitive),
+        "java/lang/RuntimeException", "isPrivacySensitive failed.");
+
+    ALOGV("%s() -> %s", __func__, privacySensitive ? "true" : "false");
+    return privacySensitive;
+}
+
+static void
 android_media_MediaRecorder_setOutputFormat(JNIEnv *env, jobject thiz, jint of)
 {
     ALOGV("setOutputFormat(%d)", of);
@@ -817,6 +847,8 @@
     {"setCamera",            "(Landroid/hardware/Camera;)V",    (void *)android_media_MediaRecorder_setCamera},
     {"setVideoSource",       "(I)V",                            (void *)android_media_MediaRecorder_setVideoSource},
     {"setAudioSource",       "(I)V",                            (void *)android_media_MediaRecorder_setAudioSource},
+    {"setPrivacySensitive",  "(Z)V",                            (void *)android_media_MediaRecorder_setPrivacySensitive},
+    {"isPrivacySensitive",  "()Z",                             (void *)android_media_MediaRecorder_isPrivacySensitive},
     {"setOutputFormat",      "(I)V",                            (void *)android_media_MediaRecorder_setOutputFormat},
     {"setVideoEncoder",      "(I)V",                            (void *)android_media_MediaRecorder_setVideoEncoder},
     {"setAudioEncoder",      "(I)V",                            (void *)android_media_MediaRecorder_setAudioEncoder},
diff --git a/media/jni/android_media_Streams.cpp b/media/jni/android_media_Streams.cpp
index b7cbd97..4fd5153 100644
--- a/media/jni/android_media_Streams.cpp
+++ b/media/jni/android_media_Streams.cpp
@@ -28,67 +28,6 @@
 
 namespace android {
 
-AssetStream::AssetStream(SkStream* stream)
-    : mStream(stream), mPosition(0) {
-}
-
-AssetStream::~AssetStream() {
-}
-
-piex::Error AssetStream::GetData(
-        const size_t offset, const size_t length, std::uint8_t* data) {
-    // Seek first.
-    if (mPosition != offset) {
-        if (!mStream->seek(offset)) {
-            return piex::Error::kFail;
-        }
-    }
-
-    // Read bytes.
-    size_t size = mStream->read((void*)data, length);
-    mPosition = offset + size;
-
-    return size == length ? piex::Error::kOk : piex::Error::kFail;
-}
-
-BufferedStream::BufferedStream(SkStream* stream)
-    : mStream(stream) {
-}
-
-BufferedStream::~BufferedStream() {
-}
-
-piex::Error BufferedStream::GetData(
-        const size_t offset, const size_t length, std::uint8_t* data) {
-    // Seek first.
-    if (offset + length > mStreamBuffer.bytesWritten()) {
-        size_t sizeToRead = offset + length - mStreamBuffer.bytesWritten();
-        if (sizeToRead <= kMinSizeToRead) {
-            sizeToRead = kMinSizeToRead;
-        }
-
-        void* tempBuffer = malloc(sizeToRead);
-        if (tempBuffer == NULL) {
-          return piex::Error::kFail;
-        }
-
-        size_t bytesRead = mStream->read(tempBuffer, sizeToRead);
-        if (bytesRead != sizeToRead) {
-            free(tempBuffer);
-            return piex::Error::kFail;
-        }
-        mStreamBuffer.write(tempBuffer, bytesRead);
-        free(tempBuffer);
-    }
-
-    // Read bytes.
-    if (mStreamBuffer.read((void*)data, offset, length)) {
-        return piex::Error::kOk;
-    } else {
-        return piex::Error::kFail;
-    }
-}
-
 FileStream::FileStream(const int fd)
     : mPosition(0) {
     mFile = fdopen(fd, "r");
diff --git a/media/jni/android_media_Streams.h b/media/jni/android_media_Streams.h
index d174f9a..800591c 100644
--- a/media/jni/android_media_Streams.h
+++ b/media/jni/android_media_Streams.h
@@ -25,53 +25,9 @@
 #include <utils/KeyedVector.h>
 #include <utils/String8.h>
 #include <utils/StrongPointer.h>
-#include <SkStream.h>
-
 
 namespace android {
 
-class AssetStream : public piex::StreamInterface {
-private:
-    SkStream *mStream;
-    size_t mPosition;
-
-public:
-    explicit AssetStream(SkStream* stream);
-    ~AssetStream();
-
-    // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer
-    // provided by the caller, guaranteed to be at least "length" bytes long.
-    // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at
-    // 'offset' bytes from the start of the stream.
-    // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not
-    // change the contents of 'data'.
-    piex::Error GetData(
-            const size_t offset, const size_t length, std::uint8_t* data) override;
-};
-
-class BufferedStream : public piex::StreamInterface {
-private:
-    SkStream *mStream;
-    // Growable memory stream
-    SkDynamicMemoryWStream mStreamBuffer;
-
-    // Minimum size to read on filling the buffer.
-    const size_t kMinSizeToRead = 8192;
-
-public:
-    explicit BufferedStream(SkStream* stream);
-    ~BufferedStream();
-
-    // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer
-    // provided by the caller, guaranteed to be at least "length" bytes long.
-    // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at
-    // 'offset' bytes from the start of the stream.
-    // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not
-    // change the contents of 'data'.
-    piex::Error GetData(
-            const size_t offset, const size_t length, std::uint8_t* data) override;
-};
-
 class FileStream : public piex::StreamInterface {
 private:
     FILE *mFile;
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 5216906..a0be12e 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -28,8 +28,12 @@
 using ::android::hardware::Void;
 using ::android::hardware::hidl_vec;
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
 using ::android::hardware::tv::tuner::V1_0::DemuxMmtpPid;
+using ::android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits;
 using ::android::hardware::tv::tuner::V1_0::DemuxTpid;
+using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings;
 using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
 using ::android::hardware::tv::tuner::V1_0::FrontendAnalogSettings;
 using ::android::hardware::tv::tuner::V1_0::FrontendAnalogSifStandard;
@@ -112,6 +116,26 @@
     mFilter = env->NewWeakGlobalRef(filter);
 }
 
+/////////////// Filter ///////////////////////
+
+Filter::Filter(sp<IFilter> sp, jweak obj) : mFilterSp(sp), mFilterObj(obj) {}
+
+Filter::~Filter() {
+    EventFlag::deleteEventFlag(&mFilterMQEventFlag);
+}
+
+int Filter::close() {
+    Result r = mFilterSp->close();
+    if (r == Result::SUCCESS) {
+        EventFlag::deleteEventFlag(&mFilterMQEventFlag);
+    }
+    return (int)r;
+}
+
+sp<IFilter> Filter::getIFilter() {
+    return mFilterSp;
+}
+
 /////////////// FrontendCallback ///////////////////////
 
 FrontendCallback::FrontendCallback(jweak tunerObj, FrontendId id) : mObject(tunerObj), mId(id) {}
@@ -211,6 +235,7 @@
     fe->setCallback(feCb);
 
     jint jId = (jint) id;
+
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     // TODO: add more fields to frontend
     return env->NewObject(
@@ -327,18 +352,18 @@
         }
     }
 
-    sp<IFilter> filterSp;
+    sp<IFilter> iFilterSp;
     sp<FilterCallback> callback = new FilterCallback();
     mDemux->openFilter(type, bufferSize, callback,
             [&](Result, const sp<IFilter>& filter) {
-                filterSp = filter;
+                iFilterSp = filter;
             });
-    if (filterSp == NULL) {
+    if (iFilterSp == NULL) {
         ALOGD("Failed to open filter, type = %d", type.mainType);
         return NULL;
     }
     int fId;
-    filterSp->getId([&](Result, uint32_t filterId) {
+    iFilterSp->getId([&](Result, uint32_t filterId) {
         fId = filterId;
     });
 
@@ -350,6 +375,7 @@
                     mObject,
                     (jint) fId);
 
+    sp<Filter> filterSp = new Filter(iFilterSp, filterObj);
     filterSp->incStrong(filterObj);
     env->SetLongField(filterObj, gFields.filterContext, (jlong)filterSp.get());
 
@@ -432,7 +458,7 @@
 static FrontendSettings getFrontendSettings(JNIEnv *env, int type, jobject settings) {
     FrontendSettings frontendSettings;
     jclass clazz = env->FindClass("android/media/tv/tuner/FrontendSettings");
-    jfieldID freqField = env->GetFieldID(clazz, "frequency", "I");
+    jfieldID freqField = env->GetFieldID(clazz, "mFrequency", "I");
     uint32_t freq = static_cast<uint32_t>(env->GetIntField(clazz, freqField));
 
     // TODO: handle the other 8 types of settings
@@ -455,8 +481,8 @@
     return frontendSettings;
 }
 
-static sp<IFilter> getFilter(JNIEnv *env, jobject filter) {
-    return (IFilter *)env->GetLongField(filter, gFields.filterContext);
+static sp<Filter> getFilter(JNIEnv *env, jobject filter) {
+    return (Filter *)env->GetLongField(filter, gFields.filterContext);
 }
 
 static sp<IDvr> getDvr(JNIEnv *env, jobject dvr) {
@@ -542,8 +568,100 @@
     return tuner->openFilter(filterType, bufferSize);
 }
 
+static DemuxFilterSettings getFilterSettings(
+        JNIEnv *env, int type, int subtype, jobject filterSettingsObj) {
+    DemuxFilterSettings filterSettings;
+    // TODO: more setting types
+    jobject settingsObj =
+            env->GetObjectField(
+                    filterSettingsObj,
+                    env->GetFieldID(
+                            env->FindClass("android/media/tv/tuner/FilterSettings"),
+                            "mSettings",
+                            "Landroid/media/tv/tuner/FilterSettings$Settings;"));
+    if (type == (int)DemuxFilterMainType::TS) {
+        // DemuxTsFilterSettings
+        jclass clazz = env->FindClass("android/media/tv/tuner/FilterSettings$TsFilterSettings");
+        int tpid = env->GetIntField(filterSettingsObj, env->GetFieldID(clazz, "mTpid", "I"));
+        if (subtype == (int)DemuxTsFilterType::PES) {
+            // DemuxFilterPesDataSettings
+            jclass settingClazz =
+                    env->FindClass("android/media/tv/tuner/FilterSettings$PesSettings");
+            int streamId = env->GetIntField(
+                    settingsObj, env->GetFieldID(settingClazz, "mStreamId", "I"));
+            bool isRaw = (bool)env->GetBooleanField(
+                    settingsObj, env->GetFieldID(settingClazz, "mIsRaw", "Z"));
+            DemuxFilterPesDataSettings filterPesDataSettings {
+                    .streamId = static_cast<uint16_t>(streamId),
+                    .isRaw = isRaw,
+            };
+            DemuxTsFilterSettings tsFilterSettings {
+                    .tpid = static_cast<uint16_t>(tpid),
+            };
+            tsFilterSettings.filterSettings.pesData(filterPesDataSettings);
+            filterSettings.ts(tsFilterSettings);
+        }
+    }
+    return filterSettings;
+}
+
+static int copyData(JNIEnv *env, sp<Filter> filter, jbyteArray buffer, jint offset, int size) {
+    ALOGD("copyData, size=%d, offset=%d", size, offset);
+
+    int available = filter->mFilterMQ->availableToRead();
+    ALOGD("copyData, available=%d", available);
+    size = std::min(size, available);
+
+    jboolean isCopy;
+    jbyte *dst = env->GetByteArrayElements(buffer, &isCopy);
+    ALOGD("copyData, isCopy=%d", isCopy);
+    if (dst == nullptr) {
+        ALOGD("Failed to GetByteArrayElements");
+        return 0;
+    }
+
+    if (filter->mFilterMQ->read(reinterpret_cast<unsigned char*>(dst) + offset, size)) {
+        env->ReleaseByteArrayElements(buffer, dst, 0);
+        filter->mFilterMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
+    } else {
+        ALOGD("Failed to read FMQ");
+        env->ReleaseByteArrayElements(buffer, dst, 0);
+        return 0;
+    }
+    return size;
+}
+
+static int android_media_tv_Tuner_configure_filter(
+        JNIEnv *env, jobject filter, int type, int subtype, jobject settings) {
+    ALOGD("configure filter type=%d, subtype=%d", type, subtype);
+    sp<Filter> filterSp = getFilter(env, filter);
+    sp<IFilter> iFilterSp = filterSp->getIFilter();
+    if (iFilterSp == NULL) {
+        ALOGD("Failed to configure filter: filter not found");
+        return (int)Result::INVALID_STATE;
+    }
+    DemuxFilterSettings filterSettings = getFilterSettings(env, type, subtype, settings);
+    Result res = iFilterSp->configure(filterSettings);
+    MQDescriptorSync<uint8_t> filterMQDesc;
+    if (res == Result::SUCCESS && filterSp->mFilterMQ == NULL) {
+        Result getQueueDescResult = Result::UNKNOWN_ERROR;
+        iFilterSp->getQueueDesc(
+                [&](Result r, const MQDescriptorSync<uint8_t>& desc) {
+                    filterMQDesc = desc;
+                    getQueueDescResult = r;
+                    ALOGD("getFilterQueueDesc");
+                });
+        if (getQueueDescResult == Result::SUCCESS) {
+            filterSp->mFilterMQ = std::make_unique<FilterMQ>(filterMQDesc, true);
+            EventFlag::createEventFlag(
+                    filterSp->mFilterMQ->getEventFlagWord(), &(filterSp->mFilterMQEventFlag));
+        }
+    }
+    return (int)res;
+}
+
 static bool android_media_tv_Tuner_start_filter(JNIEnv *env, jobject filter) {
-    sp<IFilter> filterSp = getFilter(env, filter);
+    sp<IFilter> filterSp = getFilter(env, filter)->getIFilter();
     if (filterSp == NULL) {
         ALOGD("Failed to start filter: filter not found");
         return false;
@@ -552,7 +670,7 @@
 }
 
 static bool android_media_tv_Tuner_stop_filter(JNIEnv *env, jobject filter) {
-    sp<IFilter> filterSp = getFilter(env, filter);
+    sp<IFilter> filterSp = getFilter(env, filter)->getIFilter();
     if (filterSp == NULL) {
         ALOGD("Failed to stop filter: filter not found");
         return false;
@@ -561,7 +679,7 @@
 }
 
 static bool android_media_tv_Tuner_flush_filter(JNIEnv *env, jobject filter) {
-    sp<IFilter> filterSp = getFilter(env, filter);
+    sp<IFilter> filterSp = getFilter(env, filter)->getIFilter();
     if (filterSp == NULL) {
         ALOGD("Failed to flush filter: filter not found");
         return false;
@@ -569,6 +687,16 @@
     return filterSp->flush() == Result::SUCCESS;
 }
 
+static int android_media_tv_Tuner_read_filter_fmq(
+        JNIEnv *env, jobject filter, jbyteArray buffer, jint offset, jint size) {
+    sp<Filter> filterSp = getFilter(env, filter);
+    if (filterSp == NULL) {
+        ALOGD("Failed to read filter FMQ: filter not found");
+        return 0;
+    }
+    return copyData(env, filterSp, buffer, offset, size);
+}
+
 static jobject android_media_tv_Tuner_open_descrambler(JNIEnv *env, jobject thiz) {
     sp<JTuner> tuner = getTuner(env, thiz);
     return tuner->openDescrambler();
@@ -580,7 +708,7 @@
     if (descramblerSp == NULL) {
         return false;
     }
-    sp<IFilter> filterSp = getFilter(env, filter);
+    sp<IFilter> filterSp = getFilter(env, filter)->getIFilter();
     Result result = descramblerSp->addPid(getDemuxPid((int)pidType, (int)pid), filterSp);
     return result == Result::SUCCESS;
 }
@@ -591,7 +719,7 @@
     if (descramblerSp == NULL) {
         return false;
     }
-    sp<IFilter> filterSp = getFilter(env, filter);
+    sp<IFilter> filterSp = getFilter(env, filter)->getIFilter();
     Result result = descramblerSp->removePid(getDemuxPid((int)pidType, (int)pid), filterSp);
     return result == Result::SUCCESS;
 }
@@ -603,7 +731,7 @@
 
 static bool android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) {
     sp<IDvr> dvrSp = getDvr(env, dvr);
-    sp<IFilter> filterSp = getFilter(env, filter);
+    sp<IFilter> filterSp = getFilter(env, filter)->getIFilter();
     if (dvrSp == NULL || filterSp == NULL) {
         return false;
     }
@@ -613,7 +741,7 @@
 
 static bool android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobject filter) {
     sp<IDvr> dvrSp = getDvr(env, dvr);
-    sp<IFilter> filterSp = getFilter(env, filter);
+    sp<IFilter> filterSp = getFilter(env, filter)->getIFilter();
     if (dvrSp == NULL || filterSp == NULL) {
         return false;
     }
@@ -670,9 +798,12 @@
 };
 
 static const JNINativeMethod gFilterMethods[] = {
+    { "nativeConfigureFilter", "(IILandroid/media/tv/tuner/FilterSettings;)I",
+            (void *)android_media_tv_Tuner_configure_filter },
     { "nativeStartFilter", "()Z", (void *)android_media_tv_Tuner_start_filter },
     { "nativeStopFilter", "()Z", (void *)android_media_tv_Tuner_stop_filter },
     { "nativeFlushFilter", "()Z", (void *)android_media_tv_Tuner_flush_filter },
+    { "nativeRead", "([BII)I", (void *)android_media_tv_Tuner_read_filter_fmq },
 };
 
 static const JNINativeMethod gDescramblerMethods[] = {
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index f856791..467acb8 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -18,13 +18,18 @@
 #define _ANDROID_MEDIA_TV_TUNER_H_
 
 #include <android/hardware/tv/tuner/1.0/ITuner.h>
+#include <fmq/MessageQueue.h>
 #include <unordered_map>
 #include <utils/RefBase.h>
 
 #include "jni.h"
 
+using ::android::hardware::EventFlag;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::MessageQueue;
 using ::android::hardware::Return;
 using ::android::hardware::hidl_vec;
+using ::android::hardware::kSynchronizedReadWrite;
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterType;
@@ -51,6 +56,8 @@
 using ::android::hardware::tv::tuner::V1_0::PlaybackStatus;
 using ::android::hardware::tv::tuner::V1_0::RecordStatus;
 
+using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
 namespace android {
 
 struct LnbCallback : public ILnbCallback {
@@ -91,6 +98,17 @@
     FrontendId mId;
 };
 
+struct Filter : public RefBase {
+    Filter(sp<IFilter> sp, jweak obj);
+    ~Filter();
+    int close();
+    sp<IFilter> getIFilter();
+    sp<IFilter> mFilterSp;
+    std::unique_ptr<FilterMQ> mFilterMQ;
+    EventFlag* mFilterMQEventFlag;
+    jweak mFilterObj;
+};
+
 struct JTuner : public RefBase {
     JTuner(JNIEnv *env, jobject thiz);
     sp<ITuner> getTunerService();
diff --git a/media/jni/soundpool/Stream.cpp b/media/jni/soundpool/Stream.cpp
index e7d4d90..809e81b 100644
--- a/media/jni/soundpool/Stream.cpp
+++ b/media/jni/soundpool/Stream.cpp
@@ -179,6 +179,7 @@
 {
     std::lock_guard lock(mLock);
     if (streamID == mStreamID) {
+        ALOGV("%s: track streamID: %d", __func__, streamID);
         if (mAudioTrack != nullptr) {
             if (mState == PLAYING && !mMuted && (mLeftVolume != 0.f || mRightVolume != 0.f)) {
                 setVolume_l(0.f, 0.f);
@@ -202,6 +203,7 @@
 void Stream::stop_l()
 {
     if (mState != IDLE) {
+        ALOGV("%s: track streamID: %d", __func__, (int)mStreamID);
         if (mAudioTrack != nullptr) {
             mAudioTrack->stop();
         }
@@ -227,6 +229,7 @@
     LOG_ALWAYS_FATAL_IF(pairStream == nullptr, "No pair stream!");
     sp<AudioTrack> releaseTracks[2];
     {
+        ALOGV("%s: track streamID: %d", __func__, (int)mStreamID);
         // TODO: Do we really want to force a simultaneous synchronization between
         // the stream and its pair?
 
diff --git a/media/jni/soundpool/StreamManager.cpp b/media/jni/soundpool/StreamManager.cpp
index 64f81d5..c8f0ff1 100644
--- a/media/jni/soundpool/StreamManager.cpp
+++ b/media/jni/soundpool/StreamManager.cpp
@@ -38,7 +38,7 @@
 // kPlayOnCallingThread = true prior to R.
 // Changing to false means calls to play() are almost instantaneous instead of taking around
 // ~10ms to launch the AudioTrack. It is perhaps 100x faster.
-static constexpr bool kPlayOnCallingThread = true;
+static constexpr bool kPlayOnCallingThread = false;
 
 // Amount of time for a StreamManager thread to wait before closing.
 static constexpr int64_t kWaitTimeBeforeCloseNs = 9 * NANOS_PER_SECOND;
@@ -148,16 +148,18 @@
         sanityCheckQueue_l();
         // find an available stream, prefer one that has matching sound id.
         if (mAvailableStreams.size() > 0) {
-            newStream = *mAvailableStreams.begin();
             for (auto stream : mAvailableStreams) {
                 if (stream->getSoundID() == soundID) {
                     newStream = stream;
+                    ALOGV("%s: found soundID %d in available queue", __func__, soundID);
                     break;
                 }
             }
-            if (newStream != nullptr) {
-                newStream->setStopTimeNs(systemTime());
+            if (newStream == nullptr) {
+                ALOGV("%s: found stream in available queue", __func__);
+                newStream = *mAvailableStreams.begin();
             }
+            newStream->setStopTimeNs(systemTime());
             fromAvailableQueue = true;
         }
 
@@ -166,10 +168,11 @@
             for (auto [unused , stream] : mRestartStreams) {
                 if (!stream->getPairStream()->hasSound()) {
                     if (stream->getSoundID() == soundID) {
+                        ALOGV("%s: found soundID %d in restart queue", __func__, soundID);
                         newStream = stream;
-                        fromAvailableQueue = false;
                         break;
                     } else if (newStream == nullptr) {
+                        ALOGV("%s: found stream in restart queue", __func__);
                         newStream = stream;
                     }
                 }
@@ -183,6 +186,7 @@
                     if (newStream == nullptr
                             || newStream->getPriority() > stream->getPriority()) {
                         newStream = stream;
+                        ALOGV("%s: found stream in active queue", __func__);
                     }
                 }
             }
@@ -195,6 +199,7 @@
         if (newStream == nullptr) {
             for (auto [unused, stream] : mRestartStreams) {
                 if (stream->getPairPriority() <= priority) {
+                    ALOGV("%s: evict stream from restart queue", __func__);
                     newStream = stream;
                     break;
                 }
@@ -210,6 +215,8 @@
 
         Stream *pairStream = newStream->getPairStream();
         streamID = getNextIdForStream(pairStream);
+        ALOGV("%s: newStream:%p  pairStream:%p, streamID:%d",
+                __func__, newStream, pairStream, streamID);
         pairStream->setPlay(
                 streamID, sound, soundID, leftVolume, rightVolume, priority, loop, rate);
         if (fromAvailableQueue && kPlayOnCallingThread) {
diff --git a/media/jni/soundpool/tests/build_and_run.sh b/media/jni/soundpool/tests/build_and_run.sh
index 741f2ef..72fd528 100755
--- a/media/jni/soundpool/tests/build_and_run.sh
+++ b/media/jni/soundpool/tests/build_and_run.sh
@@ -23,7 +23,10 @@
 adb push $OUT/system/bin/soundpool_stress /system/bin
 
 # test SoundPool playback of all the UI sound samples (loaded twice) looping 10s 1 thread.
-#adb shell /system/bin/soundpool_stress -l -1 $uidir/*.ogg $uidir/*.ogg
+adb shell /system/bin/soundpool_stress -l -1 $uidir/*.ogg $uidir/*.ogg
+
+# test SoundPool playback of all the UI sound samples (repeating 3 times) looping 10s 1 thread.
+adb shell /system/bin/soundpool_stress -l 1 -r 3 $uidir/*.ogg
 
 # performance test SoundPool playback of all the UI sound samples (x2)
 # 1 iterations, looping, 1 second playback, 4 threads.
diff --git a/media/jni/soundpool/tests/soundpool_stress.cpp b/media/jni/soundpool/tests/soundpool_stress.cpp
index 212662f..7d9b6a2 100644
--- a/media/jni/soundpool/tests/soundpool_stress.cpp
+++ b/media/jni/soundpool/tests/soundpool_stress.cpp
@@ -49,6 +49,7 @@
     printf("    -i #iterations, default 1\n");
     printf("    -l #loop looping mode, -1 forever\n");
     printf("    -p #playback_seconds, default 10\n");
+    printf("    -r #repeat soundIDs (0 or more times), default 0\n");
     printf("    -s #streams for concurrent sound playback, default 20\n");
     printf("    -t #threads, default 1\n");
     printf("    -z #snoozeSec after stopping, -1 forever, default 0\n");
@@ -112,7 +113,7 @@
 }
 
 void testStreams(SoundPool *soundPool, const std::vector<const char *> &filenames,
-        int loop, int playSec)
+                 int loop, int repeat, int playSec)
 {
     const int64_t startTimeNs = systemTime();
     std::vector<int32_t> soundIDs;
@@ -153,23 +154,25 @@
     // TODO: Use SoundPool::setCallback() for wait
 
     for (int32_t soundID : soundIDs) {
-        while (true) {
-            const int32_t streamID =
+        for (int i = 0; i <= repeat; ++i) {
+            while (true) {
+                const int32_t streamID =
                     soundPool->play(soundID, silentVol, silentVol, priority, 0 /*loop*/, rate);
-            if (streamID != 0) {
-                const int32_t events = gCallbackManager.getNumberEvents(soundID);
-                if (events != 1) {
-                   printf("WARNING: successful play for streamID:%d soundID:%d"
-                          " but callback events(%d) != 1\n", streamID, soundID, events);
-                   ++gWarnings;
+                if (streamID != 0) {
+                    const int32_t events = gCallbackManager.getNumberEvents(soundID);
+                    if (events != 1) {
+                       printf("WARNING: successful play for streamID:%d soundID:%d"
+                              " but callback events(%d) != 1\n", streamID, soundID, events);
+                       ++gWarnings;
+                    }
+                    soundPool->stop(streamID);
+                    break;
                 }
-                soundPool->stop(streamID);
-                break;
+                usleep(1000);
             }
-            usleep(1000);
+            printf("[%d]", soundID);
+            fflush(stdout);
         }
-        printf("[%d]", soundID);
-        fflush(stdout);
     }
 
     const int64_t loadTimeNs = systemTime();
@@ -178,14 +181,17 @@
     // check and play (overlap with above).
     std::vector<int32_t> streamIDs;
     for (int32_t soundID : soundIDs) {
-        printf("\nplaying soundID=%d", soundID);
-        const int32_t streamID = soundPool->play(soundID, maxVol, maxVol, priority, loop, rate);
-        if (streamID == 0) {
-            printf(" failed!  ERROR");
-            ++gErrors;
-        } else {
-            printf(" streamID=%d", streamID);
-            streamIDs.emplace_back(streamID);
+        for (int i = 0; i <= repeat; ++i) {
+            printf("\nplaying soundID=%d", soundID);
+            const int32_t streamID =
+                    soundPool->play(soundID, maxVol, maxVol, priority, loop, rate);
+            if (streamID == 0) {
+                printf(" failed!  ERROR");
+                ++gErrors;
+            } else {
+                printf(" streamID=%d", streamID);
+                streamIDs.emplace_back(streamID);
+            }
         }
     }
     const int64_t playTimeNs = systemTime();
@@ -217,9 +223,10 @@
     int loop = 0;        // disable looping
     int maxStreams = 40; // change to have more concurrent playback streams
     int playSec = 10;
+    int repeat = 0;
     int snoozeSec = 0;
     int threadCount = 1;
-    for (int ch; (ch = getopt(argc, argv, "i:l:p:s:t:z:")) != -1; ) {
+    for (int ch; (ch = getopt(argc, argv, "i:l:p:r:s:t:z:")) != -1; ) {
         switch (ch) {
         case 'i':
             iterations = atoi(optarg);
@@ -230,6 +237,9 @@
         case 'p':
             playSec = atoi(optarg);
             break;
+        case 'r':
+            repeat = atoi(optarg);
+            break;
         case 's':
             maxStreams = atoi(optarg);
             break;
@@ -280,7 +290,7 @@
         printf("testing %zu threads\n", threads.size());
         for (auto &thread : threads) {
             thread = std::async(std::launch::async,
-                    [&]{ testStreams(soundPool.get(), filenames, loop, playSec);});
+                    [&]{ testStreams(soundPool.get(), filenames, loop, repeat, playSec);});
         }
         // automatically joins.
     }
diff --git a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
index f4f8d0b..6650f96 100644
--- a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
+++ b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
@@ -20,6 +20,7 @@
 import android.media.MediaRoute2Info;
 import android.media.MediaRoute2ProviderInfo;
 import android.media.MediaRoute2ProviderService;
+import android.os.Bundle;
 import android.os.IBinder;
 
 import java.util.HashMap;
@@ -95,7 +96,7 @@
     }
 
     @Override
-    public void onSelectRoute(String packageName, String routeId) {
+    public void onSelectRoute(String packageName, String routeId, SelectToken token) {
         MediaRoute2Info route = mRoutes.get(routeId);
         if (route == null) {
             return;
@@ -104,6 +105,7 @@
                 .setClientPackageName(packageName)
                 .build());
         publishRoutes();
+        notifyRouteSelected(token, Bundle.EMPTY);
     }
 
     @Override
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
index d0f7c78..c70ad8d 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
@@ -23,23 +23,19 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
 
 import android.content.Context;
 import android.content.Intent;
 import android.media.MediaRoute2Info;
 import android.media.MediaRouter2;
 import android.media.MediaRouter2Manager;
+import android.os.Bundle;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.text.TextUtils;
 
-import org.junit.Assert;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -95,9 +91,14 @@
     private Executor mExecutor;
     private String mPackageName;
 
+    private final List<MediaRouter2Manager.Callback> mManagerCallbacks = new ArrayList<>();
+    private final List<MediaRouter2.Callback> mRouterCallbacks = new ArrayList<>();
+    private Map<String, MediaRoute2Info> mRoutes;
+
     private static final List<String> CATEGORIES_ALL = new ArrayList();
     private static final List<String> CATEGORIES_SPECIAL = new ArrayList();
     private static final List<String> CATEGORIES_LIVE_AUDIO = new ArrayList<>();
+
     static {
         CATEGORIES_ALL.add(CATEGORY_SAMPLE);
         CATEGORIES_ALL.add(CATEGORY_SPECIAL);
@@ -108,6 +109,7 @@
         CATEGORIES_LIVE_AUDIO.add(CATEGORY_LIVE_AUDIO);
     }
 
+
     @Before
     public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getTargetContext();
@@ -116,6 +118,16 @@
         //TODO: If we need to support thread pool executors, change this to thread pool executor.
         mExecutor = Executors.newSingleThreadExecutor();
         mPackageName = mContext.getPackageName();
+
+        // ensure media router 2 client
+        addRouterCallback(new MediaRouter2.Callback());
+        mRoutes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+    }
+
+    @After
+    public void tearDown() {
+        // unregister callbacks
+        clearCallbacks();
     }
 
     //TODO: Move to a separate file
@@ -132,10 +144,13 @@
         assertNotEquals(routeInfo1, routeInfo3);
     }
 
+    /**
+     * Tests if routes are added correctly when a new callback is registered.
+     */
     @Test
     public void testOnRoutesAdded() throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
-        MediaRouter2Manager.Callback callback = new MediaRouter2Manager.Callback() {
+        addManagerCallback(new MediaRouter2Manager.Callback() {
             @Override
             public void onRoutesAdded(List<MediaRoute2Info> routes) {
                 assertTrue(routes.size() > 0);
@@ -145,27 +160,15 @@
                     }
                 }
             }
-        };
-        mManager.registerCallback(mExecutor, callback);
+        });
 
         assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-
-        mManager.unregisterCallback(callback);
     }
 
     @Test
     public void testOnRoutesRemoved() throws Exception {
-        MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class);
-        mManager.registerCallback(mExecutor, mockCallback);
-
-        MediaRouter2.Callback routerCallback = new MediaRouter2.Callback();
-        mRouter2.registerCallback(mExecutor, routerCallback);
-
-        Map<String, MediaRoute2Info> routes =
-                waitAndGetRoutesWithManager(CATEGORIES_ALL);
-
         CountDownLatch latch = new CountDownLatch(1);
-        MediaRouter2Manager.Callback callback = new MediaRouter2Manager.Callback() {
+        addManagerCallback(new MediaRouter2Manager.Callback() {
             @Override
             public void onRoutesRemoved(List<MediaRoute2Info> routes) {
                 assertTrue(routes.size() > 0);
@@ -175,16 +178,12 @@
                     }
                 }
             }
-        };
-        mManager.registerCallback(mExecutor, callback);
+        });
 
         //TODO: Figure out a more proper way to test.
         // (Control requests shouldn't be used in this way.)
-        mRouter2.sendControlRequest(routes.get(ROUTE_ID2), new Intent(ACTION_REMOVE_ROUTE));
+        mRouter2.sendControlRequest(mRoutes.get(ROUTE_ID2), new Intent(ACTION_REMOVE_ROUTE));
         assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-
-        mRouter2.unregisterCallback(routerCallback);
-        mManager.unregisterCallback(mockCallback);
     }
 
     /**
@@ -192,16 +191,10 @@
      */
     @Test
     public void testControlCategory() throws Exception {
-        MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class);
-        mManager.registerCallback(mExecutor, mockCallback);
+        Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_SPECIAL);
 
-        Map<String, MediaRoute2Info> routes =
-                waitAndGetRoutesWithManager(CATEGORIES_SPECIAL);
-
-        Assert.assertEquals(1, routes.size());
-        Assert.assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
-
-        mManager.unregisterCallback(mockCallback);
+        assertEquals(1, routes.size());
+        assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
     }
 
     /**
@@ -209,37 +202,60 @@
      */
     @Test
     public void testGetRoutes() throws Exception {
-        MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class);
-        mRouter2.registerCallback(mExecutor, mockCallback);
-
         Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_SPECIAL);
 
-        Assert.assertEquals(1, routes.size());
-        Assert.assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
-
-        mRouter2.unregisterCallback(mockCallback);
+        assertEquals(1, routes.size());
+        assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
     }
 
+    /**
+     * Tests if MR2.Callback.onRouteSelected is called when a route is selected from MR2Manager.
+     */
     @Test
-    public void testOnRouteSelected() throws Exception {
-        MediaRouter2.Callback routerCallback = new MediaRouter2.Callback();
-        MediaRouter2Manager.Callback managerCallback = mock(MediaRouter2Manager.Callback.class);
+    public void testRouterOnRouteSelected() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
 
-        mManager.registerCallback(mExecutor, managerCallback);
-        mRouter2.registerCallback(mExecutor, routerCallback);
+        addRouterCallback(new MediaRouter2.Callback() {
+            @Override
+            public void onRouteSelected(MediaRoute2Info route, int reason, Bundle controlHints) {
+                if (route != null && TextUtils.equals(route.getId(), ROUTE_ID1)) {
+                    latch.countDown();
+                }
+            }
+        });
 
-        Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
-
-        MediaRoute2Info routeToSelect = routes.get(ROUTE_ID1);
+        MediaRoute2Info routeToSelect = mRoutes.get(ROUTE_ID1);
         assertNotNull(routeToSelect);
 
         mManager.selectRoute(mPackageName, routeToSelect);
-        verify(managerCallback, timeout(TIMEOUT_MS))
-                .onRouteSelected(eq(mPackageName),
-                        argThat(route -> route != null && route.equals(routeToSelect)));
 
-        mRouter2.unregisterCallback(routerCallback);
-        mManager.unregisterCallback(managerCallback);
+        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+    }
+
+    /**
+     * Tests if MR2Manager.Callback.onRouteSelected is called
+     * when a route is selected by MR2Manager.
+     */
+    @Test
+    public void testManagerOnRouteSelected() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+
+        addManagerCallback(new MediaRouter2Manager.Callback() {
+            @Override
+            public void onRouteSelected(String packageName, MediaRoute2Info route) {
+                if (TextUtils.equals(mPackageName, packageName)
+                        && route != null && TextUtils.equals(route.getId(), ROUTE_ID1)) {
+                    latch.countDown();
+                }
+            }
+        });
+
+        MediaRoute2Info routeToSelect = mRoutes.get(ROUTE_ID1);
+        assertNotNull(routeToSelect);
+
+        mManager.selectRoute(mPackageName, routeToSelect);
+
+        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
     }
 
     /**
@@ -247,19 +263,13 @@
      */
     @Test
     public void testSingleProviderSelect() throws Exception {
-        MediaRouter2.Callback routerCallback = mock(MediaRouter2.Callback.class);
-
-        mRouter2.registerCallback(mExecutor, routerCallback);
-
-        Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
-
         awaitOnRouteChangedManager(
-                () -> mManager.selectRoute(mPackageName, routes.get(ROUTE_ID1)),
+                () -> mManager.selectRoute(mPackageName, mRoutes.get(ROUTE_ID1)),
                 ROUTE_ID1,
                 route -> TextUtils.equals(route.getClientPackageName(), mPackageName));
 
         awaitOnRouteChangedManager(
-                () -> mManager.selectRoute(mPackageName, routes.get(ROUTE_ID2)),
+                () -> mManager.selectRoute(mPackageName, mRoutes.get(ROUTE_ID2)),
                 ROUTE_ID2,
                 route -> TextUtils.equals(route.getClientPackageName(), mPackageName));
 
@@ -267,8 +277,6 @@
                 () -> mManager.unselectRoute(mPackageName),
                 ROUTE_ID2,
                 route -> TextUtils.equals(route.getClientPackageName(), null));
-
-        mRouter2.unregisterCallback(routerCallback);
     }
 
     @Test
@@ -292,12 +300,7 @@
 
     @Test
     public void testControlVolumeWithManager() throws Exception {
-        MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class);
-
-        mRouter2.registerCallback(mExecutor, mockCallback);
-        Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
-
-        MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
+        MediaRoute2Info volRoute = mRoutes.get(ROUTE_ID_VARIABLE_VOLUME);
         int originalVolume = volRoute.getVolume();
         int deltaVolume = (originalVolume == volRoute.getVolumeMax() ? -1 : 1);
 
@@ -310,24 +313,16 @@
                 () -> mManager.requestSetVolume(volRoute, originalVolume),
                 ROUTE_ID_VARIABLE_VOLUME,
                 (route -> route.getVolume() == originalVolume));
-
-        mRouter2.unregisterCallback(mockCallback);
     }
 
     @Test
     public void testVolumeHandling() throws Exception {
-        MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class);
-        mRouter2.registerCallback(mExecutor, mockCallback);
-        Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_ALL);
-
-        MediaRoute2Info fixedVolumeRoute = routes.get(ROUTE_ID_FIXED_VOLUME);
-        MediaRoute2Info variableVolumeRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
+        MediaRoute2Info fixedVolumeRoute = mRoutes.get(ROUTE_ID_FIXED_VOLUME);
+        MediaRoute2Info variableVolumeRoute = mRoutes.get(ROUTE_ID_VARIABLE_VOLUME);
 
         assertEquals(PLAYBACK_VOLUME_FIXED, fixedVolumeRoute.getVolumeHandling());
         assertEquals(PLAYBACK_VOLUME_VARIABLE, variableVolumeRoute.getVolumeHandling());
         assertEquals(VOLUME_MAX, variableVolumeRoute.getVolumeMax());
-
-        mRouter2.unregisterCallback(mockCallback);
     }
 
     @Test
@@ -368,6 +363,7 @@
                     latch.countDown();
                 }
             }
+
             @Override
             public void onControlCategoriesChanged(String packageName) {
                 if (TextUtils.equals(mPackageName, packageName)) {
@@ -401,7 +397,7 @@
         };
         mRouter2.registerCallback(mExecutor, callback);
         try {
-            new Thread(task).start();
+            task.run();
             assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         } finally {
             mRouter2.unregisterCallback(callback);
@@ -422,7 +418,7 @@
         };
         mManager.registerCallback(mExecutor, callback);
         try {
-            new Thread(task).start();
+            task.run();
             assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         } finally {
             mManager.unregisterCallback(callback);
@@ -433,9 +429,31 @@
     static Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) {
         Map<String, MediaRoute2Info> routeMap = new HashMap<>();
         for (MediaRoute2Info route : routes) {
-            // intentionally not route.getUniqueId() for convenience.
+            // intentionally not using route.getUniqueId() for convenience.
             routeMap.put(route.getId(), route);
         }
         return routeMap;
     }
+
+    private void addManagerCallback(MediaRouter2Manager.Callback callback) {
+        mManagerCallbacks.add(callback);
+        mManager.registerCallback(mExecutor, callback);
+    }
+
+    private void addRouterCallback(MediaRouter2.Callback callback) {
+        mRouterCallbacks.add(callback);
+        mRouter2.registerCallback(mExecutor, callback);
+    }
+
+    private void clearCallbacks() {
+        for (MediaRouter2Manager.Callback callback : mManagerCallbacks) {
+            mManager.unregisterCallback(callback);
+        }
+        mManagerCallbacks.clear();
+
+        for (MediaRouter2.Callback callback : mRouterCallbacks) {
+            mRouter2.unregisterCallback(callback);
+        }
+        mRouterCallbacks.clear();
+    }
 }
diff --git a/packages/CarSystemUI/res/values/dimens.xml b/packages/CarSystemUI/res/values/dimens.xml
index ee79653..f68d034 100644
--- a/packages/CarSystemUI/res/values/dimens.xml
+++ b/packages/CarSystemUI/res/values/dimens.xml
@@ -60,21 +60,6 @@
     <dimen name="car_keyline_2">96dp</dimen>
     <dimen name="car_keyline_3">128dp</dimen>
 
-    <!-- Height of icons in Ongoing App Ops dialog. Both App Op icon and application icon -->
-    <dimen name="ongoing_appops_dialog_icon_height">48dp</dimen>
-    <!-- Margin between text lines in Ongoing App Ops dialog -->
-    <dimen name="ongoing_appops_dialog_text_margin">15dp</dimen>
-    <!-- Padding around Ongoing App Ops dialog content -->
-    <dimen name="ongoing_appops_dialog_content_padding">24dp</dimen>
-    <!-- Margins around the Ongoing App Ops chip. In landscape, the side margins are 0 -->
-    <dimen name="ongoing_appops_chip_margin">12dp</dimen>
-    <!-- Start and End padding for Ongoing App Ops chip -->
-    <dimen name="ongoing_appops_chip_side_padding">6dp</dimen>
-    <!-- Padding between background of Ongoing App Ops chip and content -->
-    <dimen name="ongoing_appops_chip_bg_padding">4dp</dimen>
-    <!-- Radius of Ongoing App Ops chip corners -->
-    <dimen name="ongoing_appops_chip_bg_corner_radius">12dp</dimen>
-
     <!-- Car volume dimens. -->
     <dimen name="car_volume_item_icon_size">@dimen/car_primary_icon_size</dimen>
     <dimen name="car_volume_item_height">@*android:dimen/car_single_line_list_item_height</dimen>
diff --git a/packages/CarSystemUI/res/values/integers_car.xml b/packages/CarSystemUI/res/values/integers_car.xml
index e53446e..d245f67 100644
--- a/packages/CarSystemUI/res/values/integers_car.xml
+++ b/packages/CarSystemUI/res/values/integers_car.xml
@@ -32,4 +32,6 @@
     <!-- Timeout values in milliseconds for displaying volume dialog-->
     <integer name="car_volume_dialog_display_normal_timeout">3000</integer>
     <integer name="car_volume_dialog_display_hovering_timeout">16000</integer>
+    <integer name="car_volume_dialog_display_expanded_normal_timeout">6000</integer>
+    <integer name="car_volume_dialog_display_expanded_hovering_timeout">32000</integer>
 </resources>
diff --git a/packages/CarSystemUI/src/com/android/systemui/TEST_MAPPING b/packages/CarSystemUI/src/com/android/systemui/TEST_MAPPING
index f90947c..6056ddf 100644
--- a/packages/CarSystemUI/src/com/android/systemui/TEST_MAPPING
+++ b/packages/CarSystemUI/src/com/android/systemui/TEST_MAPPING
@@ -1,5 +1,5 @@
 {
-  "auto-postsubmit": [
+  "auto-end-to-end-presubmit": [
     {
       "name": "AndroidAutoUiTests",
       "options" : [
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 bcb76d7..c8532e0 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -119,11 +119,11 @@
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.StatusBarComponent;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
-import com.android.systemui.statusbar.phone.StatusBarWindowViewController;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -140,6 +140,7 @@
 import java.util.Optional;
 
 import javax.inject.Named;
+import javax.inject.Provider;
 
 import dagger.Lazy;
 
@@ -156,7 +157,6 @@
     private static final float FLING_SPEED_UP_FACTOR = 0.6f;
 
     private final ScrimController mScrimController;
-    private final StatusBarWindowViewController mStatusBarWindowViewController;
     private final LockscreenLockIconController mLockscreenLockIconController;
 
     private float mOpeningVelocity = DEFAULT_FLING_VELOCITY;
@@ -174,7 +174,6 @@
 
     private final Object mQueueLock = new Object();
     private final CarNavigationBarController mCarNavigationBarController;
-    private final Lazy<DrivingStateHelper> mDrivingStateHelperLazy;
     private final Lazy<PowerManagerHelper> mPowerManagerHelperLazy;
     private final CarServiceProvider mCarServiceProvider;
 
@@ -289,7 +288,6 @@
             NotificationListener notificationListener,
             ConfigurationController configurationController,
             StatusBarWindowController statusBarWindowController,
-            StatusBarWindowViewController statusBarWindowViewController,
             LockscreenLockIconController lockscreenLockIconController,
             DozeParameters dozeParameters,
             ScrimController scrimController,
@@ -302,6 +300,7 @@
             VolumeComponent volumeComponent,
             CommandQueue commandQueue,
             Optional<Recents> recents,
+            Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
             PluginManager pluginManager,
             RemoteInputUriController remoteInputUriController,
             Optional<Divider> dividerOptional,
@@ -314,7 +313,6 @@
             DismissCallbackRegistry dismissCallbackRegistry,
             /* Car Settings injected components. */
             CarServiceProvider carServiceProvider,
-            Lazy<DrivingStateHelper> drivingStateHelperLazy,
             Lazy<PowerManagerHelper> powerManagerHelperLazy,
             Lazy<FullscreenUserSwitcher> fullscreenUserSwitcherLazy,
             CarNavigationBarController carNavigationBarController) {
@@ -368,7 +366,6 @@
                 notificationListener,
                 configurationController,
                 statusBarWindowController,
-                statusBarWindowViewController,
                 lockscreenLockIconController,
                 dozeParameters,
                 scrimController,
@@ -382,6 +379,7 @@
                 volumeComponent,
                 commandQueue,
                 recents,
+                statusBarComponentBuilder,
                 pluginManager,
                 remoteInputUriController,
                 dividerOptional,
@@ -392,11 +390,9 @@
                 viewMediatorCallback,
                 dismissCallbackRegistry);
         mScrimController = scrimController;
-        mStatusBarWindowViewController = statusBarWindowViewController;
         mLockscreenLockIconController = lockscreenLockIconController;
         mDeviceProvisionedController = deviceProvisionedController;
         mCarServiceProvider = carServiceProvider;
-        mDrivingStateHelperLazy = drivingStateHelperLazy;
         mPowerManagerHelperLazy = powerManagerHelperLazy;
         mFullscreenUserSwitcherLazy = fullscreenUserSwitcherLazy;
         mCarNavigationBarController = carNavigationBarController;
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 6529868..eff60fa 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
@@ -78,11 +78,11 @@
 import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.StatusBarComponent;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
-import com.android.systemui.statusbar.phone.StatusBarWindowViewController;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -96,6 +96,7 @@
 import java.util.Optional;
 
 import javax.inject.Named;
+import javax.inject.Provider;
 import javax.inject.Singleton;
 
 import dagger.Lazy;
@@ -162,7 +163,6 @@
             NotificationListener notificationListener,
             ConfigurationController configurationController,
             StatusBarWindowController statusBarWindowController,
-            StatusBarWindowViewController statusBarWindowViewController,
             LockscreenLockIconController lockscreenLockIconController,
             DozeParameters dozeParameters,
             ScrimController scrimController,
@@ -175,6 +175,7 @@
             VolumeComponent volumeComponent,
             CommandQueue commandQueue,
             Optional<Recents> recentsOptional,
+            Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
             PluginManager pluginManager,
             RemoteInputUriController remoteInputUriController,
             Optional<Divider> dividerOptional,
@@ -186,7 +187,6 @@
             ViewMediatorCallback viewMediatorCallback,
             DismissCallbackRegistry dismissCallbackRegistry,
             CarServiceProvider carServiceProvider,
-            Lazy<DrivingStateHelper> drivingStateHelperLazy,
             Lazy<PowerManagerHelper> powerManagerHelperLazy,
             Lazy<FullscreenUserSwitcher> fullscreenUserSwitcherLazy,
             CarNavigationBarController carNavigationBarController) {
@@ -240,7 +240,6 @@
                 notificationListener,
                 configurationController,
                 statusBarWindowController,
-                statusBarWindowViewController,
                 lockscreenLockIconController,
                 dozeParameters,
                 scrimController,
@@ -253,6 +252,7 @@
                 volumeComponent,
                 commandQueue,
                 recentsOptional,
+                statusBarComponentBuilder,
                 pluginManager,
                 remoteInputUriController,
                 dividerOptional,
@@ -263,7 +263,6 @@
                 viewMediatorCallback,
                 dismissCallbackRegistry,
                 carServiceProvider,
-                drivingStateHelperLazy,
                 powerManagerHelperLazy,
                 fullscreenUserSwitcherLazy,
                 carNavigationBarController);
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java
deleted file mode 100644
index 60934ab..0000000
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java
+++ /dev/null
@@ -1,101 +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.car.Car;
-import android.car.drivingstate.CarDrivingStateEvent;
-import android.car.drivingstate.CarDrivingStateManager;
-import android.car.drivingstate.CarDrivingStateManager.CarDrivingStateEventListener;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-import com.android.systemui.car.CarServiceProvider;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/**
- * Helper class for connecting to the {@link CarDrivingStateManager} and listening for driving state
- * changes.
- */
-@Singleton
-public class DrivingStateHelper {
-    public static final String TAG = "DrivingStateHelper";
-
-    private final CarServiceProvider mCarServiceProvider;
-
-    private CarDrivingStateManager mDrivingStateManager;
-    private CarDrivingStateEventListener mDrivingStateHandler;
-
-    @Inject
-    public DrivingStateHelper(CarServiceProvider carServiceProvider) {
-        mCarServiceProvider = carServiceProvider;
-    }
-
-    /**
-     * Sets the {@link CarDrivingStateEventListener}. Should be set before calling {@link
-     * #connectToCarService()}.
-     */
-    public void setCarDrivingStateEventListener(
-            @NonNull CarDrivingStateEventListener carDrivingStateEventListener) {
-        mDrivingStateHandler = carDrivingStateEventListener;
-    }
-
-    /**
-     * Queries {@link CarDrivingStateManager} for current driving state. Returns {@code true} if car
-     * is idling or moving, {@code false} otherwise.
-     */
-    public boolean isCurrentlyDriving() {
-        if (mDrivingStateManager == null) {
-            return false;
-        }
-        CarDrivingStateEvent currentState = mDrivingStateManager.getCurrentCarDrivingState();
-        if (currentState != null) {
-            return currentState.eventValue == CarDrivingStateEvent.DRIVING_STATE_IDLING
-                    || currentState.eventValue == CarDrivingStateEvent.DRIVING_STATE_MOVING;
-        }
-        return false; // Default to false.
-    }
-
-    /**
-     * Establishes connection with the Car service.
-     */
-    public void connectToCarService() {
-        mCarServiceProvider.addListener(mCarServiceLifecycleListener);
-    }
-
-    private final CarServiceProvider.CarServiceOnConnectedListener mCarServiceLifecycleListener =
-            car -> {
-                logD("Car Service connected");
-                mDrivingStateManager = (CarDrivingStateManager) car.getCarManager(
-                        Car.CAR_DRIVING_STATE_SERVICE);
-                if (mDrivingStateManager != null) {
-                    mDrivingStateManager.registerListener(mDrivingStateHandler);
-                    mDrivingStateHandler.onDrivingStateChanged(
-                            mDrivingStateManager.getCurrentCarDrivingState());
-                } else {
-                    Log.e(TAG, "CarDrivingStateService service not available");
-                }
-            };
-
-    private void logD(String message) {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, message);
-        }
-    }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
index 4543019..291cdd5 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
@@ -35,6 +35,7 @@
 
 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.dagger.qualifiers.MainResources;
@@ -135,8 +136,9 @@
                 /* isAddUser= */ false,
                 /* isForeground= */ true);
 
-        // If the initial user has trusted device, display the unlock dialog on the keyguard.
-        if (hasTrustedDevice(initialUser)) {
+        // 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 {
@@ -178,7 +180,7 @@
      */
     private void onUserSelected(UserGridRecyclerView.UserRecord record) {
         mSelectedUser = record;
-        if (hasTrustedDevice(record.mInfo.id)) {
+        if (hasScreenLock(record.mInfo.id) && hasTrustedDevice(record.mInfo.id)) {
             mUnlockDialogHelper.showUnlockDialog(record.mInfo.id, mOnHideListener);
             return;
         }
@@ -216,6 +218,12 @@
 
     }
 
+    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;
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
index fb1870a..0a5f80f 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
@@ -21,6 +21,7 @@
 import static android.os.UserManager.DISALLOW_ADD_USER;
 import static android.os.UserManager.SWITCHABILITY_STATUS_OK;
 
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.AlertDialog;
 import android.app.AlertDialog.Builder;
@@ -266,7 +267,10 @@
 
                 if (userRecord.mIsStartGuestSession) {
                     notifyUserSelected(userRecord);
-                    mCarUserManagerHelper.startGuestSession(mGuestName);
+                    UserInfo guest = createNewOrFindExistingGuest(mContext);
+                    if (guest != null) {
+                        mCarUserManagerHelper.switchToUser(guest);
+                    }
                     return;
                 }
 
@@ -296,14 +300,42 @@
             }
         }
 
+        /**
+         * Get the maximum number of real (non-guest, non-managed profile) users that can be created
+         * on the device. This is a dynamic value and it decreases with the increase of the number
+         * of managed profiles on the device.
+         *
+         * <p> It excludes system user in headless system user model.
+         *
+         * @return Maximum number of real users that can be created.
+         */
+        private int getMaxSupportedRealUsers() {
+            int maxSupportedUsers = UserManager.getMaxSupportedUsers();
+            if (UserManager.isHeadlessSystemUserMode()) {
+                maxSupportedUsers -= 1;
+            }
+
+            List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
+
+            // Count all users that are managed profiles of another user.
+            int managedProfilesCount = 0;
+            for (UserInfo user : users) {
+                if (user.isManagedProfile()) {
+                    managedProfilesCount++;
+                }
+            }
+
+            return maxSupportedUsers - managedProfilesCount;
+        }
+
         private void showMaxUserLimitReachedDialog() {
             AlertDialog maxUsersDialog = new Builder(mContext,
                     com.android.internal.R.style.Theme_DeviceDefault_Dialog_Alert)
                     .setTitle(R.string.user_limit_reached_title)
                     .setMessage(getResources().getQuantityString(
                             R.plurals.user_limit_reached_message,
-                            mCarUserManagerHelper.getMaxSupportedRealUsers(),
-                            mCarUserManagerHelper.getMaxSupportedRealUsers()))
+                            getMaxSupportedRealUsers(),
+                            getMaxSupportedRealUsers()))
                     .setPositiveButton(android.R.string.ok, null)
                     .create();
             // Sets window flags for the SysUI dialog
@@ -353,6 +385,24 @@
             return circleIcon;
         }
 
+        /**
+         * Finds the existing Guest user, or creates one if it doesn't exist.
+         * @param context App context
+         * @return UserInfo representing the Guest user
+         */
+        @Nullable
+        public UserInfo createNewOrFindExistingGuest(Context context) {
+            // CreateGuest will return null if a guest already exists.
+            UserInfo newGuest = mUserManager.createGuest(context, mGuestName);
+            if (newGuest != null) {
+                new UserIconProvider().assignDefaultIcon(
+                        mUserManager, context.getResources(), newGuest);
+                return newGuest;
+            }
+
+            return mUserManager.findCurrentGuestUser();
+        }
+
         @Override
         public void onClick(DialogInterface dialog, int which) {
             if (which == BUTTON_POSITIVE) {
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserIconProvider.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserIconProvider.java
index 9464eab..9018290 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserIconProvider.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserIconProvider.java
@@ -88,7 +88,7 @@
      * @param userInfo User whose avatar is set to default icon.
      * @return Bitmap of the user icon.
      */
-    private Bitmap assignDefaultIcon(
+    public Bitmap assignDefaultIcon(
             UserManager userManager, Resources resources, UserInfo userInfo) {
         Bitmap bitmap = userInfo.isGuest()
                 ? getGuestUserDefaultIcon(resources)
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index 367959e..c9ac765 100644
--- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -90,6 +90,8 @@
     private final KeyguardManager mKeyguard;
     private final int mNormalTimeout;
     private final int mHoveringTimeout;
+    private final int mExpNormalTimeout;
+    private final int mExpHoveringTimeout;
 
     private Window mWindow;
     private CustomDialog mDialog;
@@ -176,6 +178,10 @@
                 R.integer.car_volume_dialog_display_normal_timeout);
         mHoveringTimeout = mContext.getResources().getInteger(
                 R.integer.car_volume_dialog_display_hovering_timeout);
+        mExpNormalTimeout = mContext.getResources().getInteger(
+                R.integer.car_volume_dialog_display_expanded_normal_timeout);
+        mExpHoveringTimeout = mContext.getResources().getInteger(
+                R.integer.car_volume_dialog_display_expanded_hovering_timeout);
     }
 
     /** Sets a {@link CarServiceProvider} which connects to the audio service. */
@@ -290,7 +296,7 @@
         mShowing = true;
         clearAllAndSetupDefaultCarVolumeLineItem(mCurrentlyDisplayingGroupId);
         mDialog.show();
-        Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked());
+        Events.writeEvent(Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked());
     }
 
     private void clearAllAndSetupDefaultCarVolumeLineItem(int groupId) {
@@ -313,7 +319,11 @@
     }
 
     private int computeTimeoutH() {
-        return mHovering ? mHoveringTimeout : mNormalTimeout;
+        if (mExpanded) {
+            return mHovering ? mExpHoveringTimeout : mExpNormalTimeout;
+        } else {
+            return mHovering ? mHoveringTimeout : mNormalTimeout;
+        }
     }
 
     private void dismissH(int reason) {
@@ -349,7 +359,7 @@
                 }, DISMISS_DELAY_IN_MILLIS))
                 .start();
 
-        Events.writeEvent(mContext, Events.EVENT_DISMISS_DIALOG, reason);
+        Events.writeEvent(Events.EVENT_DISMISS_DIALOG, reason);
     }
 
     private void loadAudioUsageItems() {
@@ -532,6 +542,7 @@
         public void onClick(final View v) {
             mExpandIcon = v;
             toggleDialogExpansion(true);
+            rescheduleTimeoutH();
         }
     }
 
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index 142078e..9e49826 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -32,9 +32,11 @@
 import static android.os.image.DynamicSystemClient.STATUS_NOT_STARTED;
 import static android.os.image.DynamicSystemClient.STATUS_READY;
 
+import static com.android.dynsystem.InstallationAsyncTask.RESULT_CANCELLED;
 import static com.android.dynsystem.InstallationAsyncTask.RESULT_ERROR_EXCEPTION;
-import static com.android.dynsystem.InstallationAsyncTask.RESULT_ERROR_INVALID_URL;
 import static com.android.dynsystem.InstallationAsyncTask.RESULT_ERROR_IO;
+import static com.android.dynsystem.InstallationAsyncTask.RESULT_ERROR_UNSUPPORTED_FORMAT;
+import static com.android.dynsystem.InstallationAsyncTask.RESULT_ERROR_UNSUPPORTED_URL;
 import static com.android.dynsystem.InstallationAsyncTask.RESULT_OK;
 
 import android.app.Notification;
@@ -66,11 +68,10 @@
  * cancel and confirm commnands.
  */
 public class DynamicSystemInstallationService extends Service
-        implements InstallationAsyncTask.InstallStatusListener {
+        implements InstallationAsyncTask.ProgressListener {
 
     private static final String TAG = "DynSystemInstallationService";
 
-
     // TODO (b/131866826): This is currently for test only. Will move this to System API.
     static final String KEY_ENABLE_WHEN_COMPLETED = "KEY_ENABLE_WHEN_COMPLETED";
 
@@ -121,9 +122,12 @@
     private DynamicSystemManager mDynSystem;
     private NotificationManager mNM;
 
-    private long mSystemSize;
-    private long mUserdataSize;
-    private long mInstalledSize;
+    private int mNumInstalledPartitions;
+
+    private String mCurrentPartitionName;
+    private long mCurrentPartitionSize;
+    private long mCurrentPartitionInstalledSize;
+
     private boolean mJustCancelledByUser;
 
     // This is for testing only now
@@ -176,8 +180,12 @@
     }
 
     @Override
-    public void onProgressUpdate(long installedSize) {
-        mInstalledSize = installedSize;
+    public void onProgressUpdate(InstallationAsyncTask.Progress progress) {
+        mCurrentPartitionName = progress.mPartitionName;
+        mCurrentPartitionSize = progress.mPartitionSize;
+        mCurrentPartitionInstalledSize = progress.mInstalledSize;
+        mNumInstalledPartitions = progress.mNumInstalledPartitions;
+
         postStatus(STATUS_IN_PROGRESS, CAUSE_NOT_SPECIFIED, null);
     }
 
@@ -197,11 +205,16 @@
         resetTaskAndStop();
 
         switch (result) {
+            case RESULT_CANCELLED:
+                postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED, null);
+                break;
+
             case RESULT_ERROR_IO:
                 postStatus(STATUS_NOT_STARTED, CAUSE_ERROR_IO, detail);
                 break;
 
-            case RESULT_ERROR_INVALID_URL:
+            case RESULT_ERROR_UNSUPPORTED_URL:
+            case RESULT_ERROR_UNSUPPORTED_FORMAT:
                 postStatus(STATUS_NOT_STARTED, CAUSE_ERROR_INVALID_URL, detail);
                 break;
 
@@ -211,12 +224,6 @@
         }
     }
 
-    @Override
-    public void onCancelled() {
-        resetTaskAndStop();
-        postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED, null);
-    }
-
     private void executeInstallCommand(Intent intent) {
         if (!verifyRequest(intent)) {
             Log.e(TAG, "Verification failed. Did you use VerificationActivity?");
@@ -234,12 +241,13 @@
         }
 
         String url = intent.getDataString();
-        mSystemSize = intent.getLongExtra(DynamicSystemClient.KEY_SYSTEM_SIZE, 0);
-        mUserdataSize = intent.getLongExtra(DynamicSystemClient.KEY_USERDATA_SIZE, 0);
+        long systemSize = intent.getLongExtra(DynamicSystemClient.KEY_SYSTEM_SIZE, 0);
+        long userdataSize = intent.getLongExtra(DynamicSystemClient.KEY_USERDATA_SIZE, 0);
         mEnableWhenCompleted = intent.getBooleanExtra(KEY_ENABLE_WHEN_COMPLETED, false);
 
+        // TODO: better constructor or builder
         mInstallTask = new InstallationAsyncTask(
-                url, mSystemSize, mUserdataSize, this, mDynSystem, this);
+                url, systemSize, userdataSize, this, mDynSystem, this);
 
         mInstallTask.execute();
 
@@ -257,7 +265,7 @@
         mJustCancelledByUser = true;
 
         if (mInstallTask.cancel(false)) {
-            // Will cleanup and post status in onCancelled()
+            // Will cleanup and post status in onResult()
             Log.d(TAG, "Cancel request filed successfully");
         } else {
             Log.e(TAG, "Trying to cancel installation while it's already completed.");
@@ -288,7 +296,7 @@
     private void executeRebootToDynSystemCommand() {
         boolean enabled = false;
 
-        if (mInstallTask != null && mInstallTask.getResult() == RESULT_OK) {
+        if (mInstallTask != null && mInstallTask.isCompleted()) {
             enabled = mInstallTask.commit();
         } else if (isDynamicSystemInstalled()) {
             enabled = mDynSystem.setEnable(true, true);
@@ -380,8 +388,16 @@
             case STATUS_IN_PROGRESS:
                 builder.setContentText(getString(R.string.notification_install_inprogress));
 
-                int max = (int) Math.max((mSystemSize + mUserdataSize) >> 20, 1);
-                int progress = (int) (mInstalledSize >> 20);
+                int max = 1024;
+                int progress = 0;
+
+                int currentMax = max >> (mNumInstalledPartitions + 1);
+                progress = max - currentMax * 2;
+
+                long currentProgress = (mCurrentPartitionInstalledSize >> 20) * currentMax
+                        / Math.max(mCurrentPartitionSize >> 20, 1);
+
+                progress += (int) currentProgress;
 
                 builder.setProgress(max, progress, false);
 
@@ -464,7 +480,8 @@
             throws RemoteException {
         Bundle bundle = new Bundle();
 
-        bundle.putLong(DynamicSystemClient.KEY_INSTALLED_SIZE, mInstalledSize);
+        // TODO: send more info to the clients
+        bundle.putLong(DynamicSystemClient.KEY_INSTALLED_SIZE, mCurrentPartitionInstalledSize);
 
         if (detail != null) {
             bundle.putSerializable(DynamicSystemClient.KEY_EXCEPTION_DETAIL,
@@ -492,9 +509,7 @@
                 return STATUS_IN_PROGRESS;
 
             case FINISHED:
-                int result = mInstallTask.getResult();
-
-                if (result == RESULT_OK) {
+                if (mInstallTask.isCompleted()) {
                     return STATUS_READY;
                 } else {
                     throw new IllegalStateException("A failed InstallationTask is not reset");
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
index 19ae970..b206a1f 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
@@ -17,7 +17,6 @@
 package com.android.dynsystem;
 
 import android.content.Context;
-import android.gsi.GsiProgress;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.MemoryFile;
@@ -27,35 +26,70 @@
 import android.webkit.URLUtil;
 
 import java.io.BufferedInputStream;
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.List;
 import java.util.Locale;
 import java.util.zip.GZIPInputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipInputStream;
 
-class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> {
+class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Progress, Throwable> {
 
     private static final String TAG = "InstallationAsyncTask";
 
     private static final int READ_BUFFER_SIZE = 1 << 13;
+    private static final long MIN_PROGRESS_TO_PUBLISH = 1 << 27;
 
-    private class InvalidImageUrlException extends RuntimeException {
-        private InvalidImageUrlException(String message) {
+    private static final List<String> UNSUPPORTED_PARTITIONS =
+            Arrays.asList("vbmeta", "boot", "userdata", "dtbo", "super_empty", "system_other");
+
+    private class UnsupportedUrlException extends RuntimeException {
+        private UnsupportedUrlException(String message) {
             super(message);
         }
     }
 
-    /** Not completed, including being cancelled */
-    static final int NO_RESULT = 0;
+    private class UnsupportedFormatException extends RuntimeException {
+        private UnsupportedFormatException(String message) {
+            super(message);
+        }
+    }
+
+    /** UNSET means the installation is not completed */
+    static final int RESULT_UNSET = 0;
     static final int RESULT_OK = 1;
-    static final int RESULT_ERROR_IO = 2;
-    static final int RESULT_ERROR_INVALID_URL = 3;
+    static final int RESULT_CANCELLED = 2;
+    static final int RESULT_ERROR_IO = 3;
+    static final int RESULT_ERROR_UNSUPPORTED_URL = 4;
+    static final int RESULT_ERROR_UNSUPPORTED_FORMAT = 5;
     static final int RESULT_ERROR_EXCEPTION = 6;
 
-    interface InstallStatusListener {
-        void onProgressUpdate(long installedSize);
+    class Progress {
+        String mPartitionName;
+        long mPartitionSize;
+        long mInstalledSize;
+
+        int mNumInstalledPartitions;
+
+        Progress(String partitionName, long partitionSize, long installedSize,
+                int numInstalled) {
+            mPartitionName = partitionName;
+            mPartitionSize = partitionSize;
+            mInstalledSize = installedSize;
+
+            mNumInstalledPartitions = numInstalled;
+        }
+    }
+
+    interface ProgressListener {
+        void onProgressUpdate(Progress progress);
         void onResult(int resultCode, Throwable detail);
-        void onCancelled();
     }
 
     private final String mUrl;
@@ -63,16 +97,17 @@
     private final long mUserdataSize;
     private final Context mContext;
     private final DynamicSystemManager mDynSystem;
-    private final InstallStatusListener mListener;
+    private final ProgressListener mListener;
     private DynamicSystemManager.Session mInstallationSession;
 
-    private int mResult = NO_RESULT;
+    private boolean mIsZip;
+    private boolean mIsCompleted;
 
     private InputStream mStream;
-
+    private ZipFile mZipFile;
 
     InstallationAsyncTask(String url, long systemSize, long userdataSize, Context context,
-            DynamicSystemManager dynSystem, InstallStatusListener listener) {
+            DynamicSystemManager dynSystem, ProgressListener listener) {
         mUrl = url;
         mSystemSize = systemSize;
         mUserdataSize = userdataSize;
@@ -82,133 +117,292 @@
     }
 
     @Override
-    protected void onPreExecute() {
-        mListener.onProgressUpdate(0);
-    }
-
-    @Override
     protected Throwable doInBackground(String... voids) {
         Log.d(TAG, "Start doInBackground(), URL: " + mUrl);
 
         try {
-            long installedSize = 0;
-            long reportedInstalledSize = 0;
+            // call DynamicSystemManager to cleanup stuff
+            mDynSystem.remove();
 
-            long minStepToReport = (mSystemSize + mUserdataSize) / 100;
+            verifyAndPrepare();
 
-            // init input stream before calling startInstallation(), which takes 90 seconds.
-            initInputStream();
+            mDynSystem.startInstallation();
 
-            Thread thread =
-                    new Thread(
-                            () -> {
-                                mDynSystem.startInstallation();
-                                mDynSystem.createPartition("userdata", mUserdataSize, false);
-                                mInstallationSession =
-                                        mDynSystem.createPartition("system", mSystemSize, true);
-                            });
-
-            thread.start();
-
-            while (thread.isAlive()) {
-                if (isCancelled()) {
-                    boolean aborted = mDynSystem.abort();
-                    Log.d(TAG, "Called DynamicSystemManager.abort(), result = " + aborted);
-                    return null;
-                }
-
-                GsiProgress progress = mDynSystem.getInstallationProgress();
-                installedSize = progress.bytes_processed;
-
-                if (installedSize > reportedInstalledSize + minStepToReport) {
-                    publishProgress(installedSize);
-                    reportedInstalledSize = installedSize;
-                }
-
-                Thread.sleep(10);
+            installUserdata();
+            if (isCancelled()) {
+                mDynSystem.remove();
+                return null;
             }
 
-            if (mInstallationSession == null) {
-                throw new IOException(
-                        "Failed to start installation with requested size: "
-                                + (mSystemSize + mUserdataSize));
+            installImages();
+            if (isCancelled()) {
+                mDynSystem.remove();
+                return null;
             }
 
-            installedSize = mUserdataSize;
-
-            MemoryFile memoryFile = new MemoryFile("dsu", READ_BUFFER_SIZE);
-            byte[] bytes = new byte[READ_BUFFER_SIZE];
-            mInstallationSession.setAshmem(
-                    new ParcelFileDescriptor(memoryFile.getFileDescriptor()), READ_BUFFER_SIZE);
-            int numBytesRead;
-            Log.d(TAG, "Start installation loop");
-            while ((numBytesRead = mStream.read(bytes, 0, READ_BUFFER_SIZE)) != -1) {
-                memoryFile.writeBytes(bytes, 0, 0, numBytesRead);
-                if (isCancelled()) {
-                    break;
-                }
-                if (!mInstallationSession.submitFromAshmem(numBytesRead)) {
-                    throw new IOException("Failed write() to DynamicSystem");
-                }
-
-                installedSize += numBytesRead;
-
-                if (installedSize > reportedInstalledSize + minStepToReport) {
-                    publishProgress(installedSize);
-                    reportedInstalledSize = installedSize;
-                }
-            }
             mDynSystem.finishInstallation();
-            return null;
-
         } catch (Exception e) {
             e.printStackTrace();
+            mDynSystem.remove();
             return e;
         } finally {
             close();
         }
+
+        return null;
+    }
+
+    @Override
+    protected void onPostExecute(Throwable detail) {
+        int result = RESULT_UNSET;
+
+        if (detail == null) {
+            result = RESULT_OK;
+            mIsCompleted = true;
+        } else if (detail instanceof IOException) {
+            result = RESULT_ERROR_IO;
+        } else if (detail instanceof UnsupportedUrlException) {
+            result = RESULT_ERROR_UNSUPPORTED_URL;
+        } else if (detail instanceof UnsupportedFormatException) {
+            result = RESULT_ERROR_UNSUPPORTED_FORMAT;
+        } else {
+            result = RESULT_ERROR_EXCEPTION;
+        }
+
+        Log.d(TAG, "onPostExecute(), URL: " + mUrl + ", result: " + result);
+
+        mListener.onResult(result, detail);
     }
 
     @Override
     protected void onCancelled() {
         Log.d(TAG, "onCancelled(), URL: " + mUrl);
 
-        mListener.onCancelled();
-    }
-
-    @Override
-    protected void onPostExecute(Throwable detail) {
-        if (detail == null) {
-            mResult = RESULT_OK;
-        } else if (detail instanceof IOException) {
-            mResult = RESULT_ERROR_IO;
-        } else if (detail instanceof InvalidImageUrlException) {
-            mResult = RESULT_ERROR_INVALID_URL;
+        if (mDynSystem.abort()) {
+            Log.d(TAG, "Installation aborted");
         } else {
-            mResult = RESULT_ERROR_EXCEPTION;
+            Log.w(TAG, "DynamicSystemManager.abort() returned false");
         }
 
-        Log.d(TAG, "onPostExecute(), URL: " + mUrl + ", result: " + mResult);
-
-        mListener.onResult(mResult, detail);
+        mListener.onResult(RESULT_CANCELLED, null);
     }
 
     @Override
-    protected void onProgressUpdate(Long... values) {
-        long progress = values[0];
+    protected void onProgressUpdate(Progress... values) {
+        Progress progress = values[0];
         mListener.onProgressUpdate(progress);
     }
 
-    private void initInputStream() throws IOException, InvalidImageUrlException {
-        if (URLUtil.isNetworkUrl(mUrl) || URLUtil.isFileUrl(mUrl)) {
-            mStream = new BufferedInputStream(new GZIPInputStream(new URL(mUrl).openStream()));
-        } else if (URLUtil.isContentUrl(mUrl)) {
-            Uri uri = Uri.parse(mUrl);
-            mStream = new BufferedInputStream(new GZIPInputStream(
-                    mContext.getContentResolver().openInputStream(uri)));
+    private void verifyAndPrepare() throws Exception {
+        String extension = mUrl.substring(mUrl.lastIndexOf('.') + 1);
+
+        if ("gz".equals(extension) || "gzip".equals(extension)) {
+            mIsZip = false;
+        } else if ("zip".equals(extension)) {
+            mIsZip = true;
         } else {
-            throw new InvalidImageUrlException(
-                    String.format(Locale.US, "Unsupported file source: %s", mUrl));
+            throw new UnsupportedFormatException(
+                String.format(Locale.US, "Unsupported file format: %s", mUrl));
+        }
+
+        if (URLUtil.isNetworkUrl(mUrl)) {
+            mStream = new URL(mUrl).openStream();
+        } else if (URLUtil.isFileUrl(mUrl)) {
+            if (mIsZip) {
+                mZipFile = new ZipFile(new File(new URL(mUrl).toURI()));
+            } else {
+                mStream = new URL(mUrl).openStream();
+            }
+        } else if (URLUtil.isContentUrl(mUrl)) {
+            mStream = mContext.getContentResolver().openInputStream(Uri.parse(mUrl));
+        } else {
+            throw new UnsupportedUrlException(
+                    String.format(Locale.US, "Unsupported URL: %s", mUrl));
+        }
+    }
+
+    private void installUserdata() throws Exception {
+        Thread thread = new Thread(() -> {
+            mInstallationSession = mDynSystem.createPartition("userdata", mUserdataSize, false);
+        });
+
+        Log.d(TAG, "Creating partition: userdata");
+        thread.start();
+
+        long installedSize = 0;
+        Progress progress = new Progress("userdata", mUserdataSize, installedSize, 0);
+
+        while (thread.isAlive()) {
+            if (isCancelled()) {
+                return;
+            }
+
+            installedSize = mDynSystem.getInstallationProgress().bytes_processed;
+
+            if (installedSize > progress.mInstalledSize + MIN_PROGRESS_TO_PUBLISH) {
+                progress.mInstalledSize = installedSize;
+                publishProgress(progress);
+            }
+
+            Thread.sleep(10);
+        }
+
+        if (mInstallationSession == null) {
+            throw new IOException(
+                    "Failed to start installation with requested size: " + mUserdataSize);
+        }
+    }
+
+    private void installImages() throws IOException, InterruptedException {
+        if (mStream != null) {
+            if (mIsZip) {
+                installStreamingZipUpdate();
+            } else {
+                installStreamingGzUpdate();
+            }
+        } else {
+            installLocalZipUpdate();
+        }
+    }
+
+    private void installStreamingGzUpdate() throws IOException, InterruptedException {
+        Log.d(TAG, "To install a streaming GZ update");
+        installImage("system", mSystemSize, new GZIPInputStream(mStream), 1);
+    }
+
+    private void installStreamingZipUpdate() throws IOException, InterruptedException {
+        Log.d(TAG, "To install a streaming ZIP update");
+
+        ZipInputStream zis = new ZipInputStream(mStream);
+        ZipEntry zipEntry = null;
+
+        int numInstalledPartitions = 1;
+
+        while ((zipEntry = zis.getNextEntry()) != null) {
+            if (installImageFromAnEntry(zipEntry, zis, numInstalledPartitions)) {
+                numInstalledPartitions++;
+            }
+
+            if (isCancelled()) {
+                break;
+            }
+        }
+    }
+
+    private void installLocalZipUpdate() throws IOException, InterruptedException {
+        Log.d(TAG, "To install a local ZIP update");
+
+        Enumeration<? extends ZipEntry> entries = mZipFile.entries();
+        int numInstalledPartitions = 1;
+
+        while (entries.hasMoreElements()) {
+            ZipEntry entry = entries.nextElement();
+            if (installImageFromAnEntry(
+                    entry, mZipFile.getInputStream(entry), numInstalledPartitions)) {
+                numInstalledPartitions++;
+            }
+
+            if (isCancelled()) {
+                break;
+            }
+        }
+    }
+
+    private boolean installImageFromAnEntry(ZipEntry entry, InputStream is,
+            int numInstalledPartitions) throws IOException, InterruptedException {
+        String name = entry.getName();
+
+        Log.d(TAG, "ZipEntry: " + name);
+
+        if (!name.endsWith(".img")) {
+            return false;
+        }
+
+        String partitionName = name.substring(0, name.length() - 4);
+
+        if (UNSUPPORTED_PARTITIONS.contains(partitionName)) {
+            Log.d(TAG, name + " installation is not supported, skip it.");
+            return false;
+        }
+
+        long uncompressedSize = entry.getSize();
+
+        installImage(partitionName, uncompressedSize, is, numInstalledPartitions);
+
+        return true;
+    }
+
+    private void installImage(String partitionName, long uncompressedSize, InputStream is,
+            int numInstalledPartitions) throws IOException, InterruptedException {
+
+        SparseInputStream sis = new SparseInputStream(new BufferedInputStream(is));
+
+        long unsparseSize = sis.getUnsparseSize();
+
+        final long partitionSize;
+
+        if (unsparseSize != -1) {
+            partitionSize = unsparseSize;
+            Log.d(TAG, partitionName + " is sparse, raw size = " + unsparseSize);
+        } else if (uncompressedSize != -1) {
+            partitionSize = uncompressedSize;
+            Log.d(TAG, partitionName + " is already unsparse, raw size = " + uncompressedSize);
+        } else {
+            throw new IOException("Cannot get raw size for " + partitionName);
+        }
+
+        Thread thread = new Thread(() -> {
+            mInstallationSession =
+                    mDynSystem.createPartition(partitionName, partitionSize, true);
+        });
+
+        Log.d(TAG, "Start creating partition: " + partitionName);
+        thread.start();
+
+        while (thread.isAlive()) {
+            if (isCancelled()) {
+                return;
+            }
+
+            Thread.sleep(10);
+        }
+
+        if (mInstallationSession == null) {
+            throw new IOException(
+                    "Failed to start installation with requested size: " + partitionSize);
+        }
+
+        Log.d(TAG, "Start installing: " + partitionName);
+
+        MemoryFile memoryFile = new MemoryFile("dsu_" + partitionName, READ_BUFFER_SIZE);
+        ParcelFileDescriptor pfd = new ParcelFileDescriptor(memoryFile.getFileDescriptor());
+
+        mInstallationSession.setAshmem(pfd, READ_BUFFER_SIZE);
+
+        long installedSize = 0;
+        Progress progress = new Progress(
+                partitionName, partitionSize, installedSize, numInstalledPartitions);
+
+        byte[] bytes = new byte[READ_BUFFER_SIZE];
+        int numBytesRead;
+
+        while ((numBytesRead = sis.read(bytes, 0, READ_BUFFER_SIZE)) != -1) {
+            if (isCancelled()) {
+                return;
+            }
+
+            memoryFile.writeBytes(bytes, 0, 0, numBytesRead);
+
+            if (!mInstallationSession.submitFromAshmem(numBytesRead)) {
+                throw new IOException("Failed write() to DynamicSystem");
+            }
+
+            installedSize += numBytesRead;
+
+            if (installedSize > progress.mInstalledSize + MIN_PROGRESS_TO_PUBLISH) {
+                progress.mInstalledSize = installedSize;
+                publishProgress(progress);
+            }
         }
     }
 
@@ -218,20 +412,20 @@
                 mStream.close();
                 mStream = null;
             }
+            if (mZipFile != null) {
+                mZipFile.close();
+                mZipFile = null;
+            }
         } catch (IOException e) {
             // ignore
         }
     }
 
-    int getResult() {
-        return mResult;
+    boolean isCompleted() {
+        return mIsCompleted;
     }
 
     boolean commit() {
-        if (mInstallationSession == null) {
-            return false;
-        }
-
-        return mInstallationSession.commit();
+        return mDynSystem.setEnable(true, true);
     }
 }
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/SparseInputStream.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/SparseInputStream.java
new file mode 100644
index 0000000..72230b4
--- /dev/null
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/SparseInputStream.java
@@ -0,0 +1,199 @@
+/*
+ * 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.dynsystem;
+
+import static java.lang.Math.min;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+
+/**
+ * SparseInputStream read from upstream and detects the data format. If the upstream is a valid
+ * sparse data, it will unsparse it on the fly. Otherwise, it just passthrough as is.
+ */
+public class SparseInputStream extends InputStream {
+    static final int FILE_HDR_SIZE = 28;
+    static final int CHUNK_HDR_SIZE = 12;
+
+    /**
+     * This class represents a chunk in the Android sparse image.
+     *
+     * @see system/core/libsparse/sparse_format.h
+     */
+    private class SparseChunk {
+        static final short RAW = (short) 0xCAC1;
+        static final short FILL = (short) 0xCAC2;
+        static final short DONTCARE = (short) 0xCAC3;
+        public short mChunkType;
+        public int mChunkSize;
+        public int mTotalSize;
+        public byte[] fill;
+        public String toString() {
+            return String.format(
+                    "type: %x, chunk_size: %d, total_size: %d", mChunkType, mChunkSize, mTotalSize);
+        }
+    }
+
+    private byte[] readFull(InputStream in, int size) throws IOException {
+        byte[] buf = new byte[size];
+        for (int done = 0, n = 0; done < size; done += n) {
+            if ((n = in.read(buf, done, size - done)) < 0) {
+                throw new IOException("Failed to readFull");
+            }
+        }
+        return buf;
+    }
+
+    private ByteBuffer readBuffer(InputStream in, int size) throws IOException {
+        return ByteBuffer.wrap(readFull(in, size)).order(ByteOrder.LITTLE_ENDIAN);
+    }
+
+    private SparseChunk readChunk(InputStream in) throws IOException {
+        SparseChunk chunk = new SparseChunk();
+        ByteBuffer buf = readBuffer(in, CHUNK_HDR_SIZE);
+        chunk.mChunkType = buf.getShort();
+        buf.getShort();
+        chunk.mChunkSize = buf.getInt();
+        chunk.mTotalSize = buf.getInt();
+        return chunk;
+    }
+
+    private BufferedInputStream mIn;
+    private boolean mIsSparse;
+    private long mBlockSize;
+    private long mTotalBlocks;
+    private long mTotalChunks;
+    private SparseChunk mCur;
+    private long mLeft;
+    private int mCurChunks;
+
+    public SparseInputStream(BufferedInputStream in) throws IOException {
+        mIn = in;
+        in.mark(FILE_HDR_SIZE * 2);
+        ByteBuffer buf = readBuffer(mIn, FILE_HDR_SIZE);
+        mIsSparse = (buf.getInt() == 0xed26ff3a);
+        if (!mIsSparse) {
+            mIn.reset();
+            return;
+        }
+        int major = buf.getShort();
+        int minor = buf.getShort();
+
+        if (major > 0x1 || minor > 0x0) {
+            throw new IOException("Unsupported sparse version: " + major + "." + minor);
+        }
+
+        if (buf.getShort() != FILE_HDR_SIZE) {
+            throw new IOException("Illegal file header size");
+        }
+        if (buf.getShort() != CHUNK_HDR_SIZE) {
+            throw new IOException("Illegal chunk header size");
+        }
+        mBlockSize = buf.getInt();
+        if ((mBlockSize & 0x3) != 0) {
+            throw new IOException("Illegal block size, must be a multiple of 4");
+        }
+        mTotalBlocks = buf.getInt();
+        mTotalChunks = buf.getInt();
+        mLeft = mCurChunks = 0;
+    }
+
+    /**
+     * Check if it needs to open a new chunk.
+     *
+     * @return true if it's EOF
+     */
+    private boolean prepareChunk() throws IOException {
+        if (mCur == null || mLeft <= 0) {
+            if (++mCurChunks > mTotalChunks) return true;
+            mCur = readChunk(mIn);
+            if (mCur.mChunkType == SparseChunk.FILL) {
+                mCur.fill = readFull(mIn, 4);
+            }
+            mLeft = mCur.mChunkSize * mBlockSize;
+        }
+        return mLeft == 0;
+    }
+
+    /**
+     * It overrides the InputStream.read(byte[] buf)
+     */
+    public int read(byte[] buf) throws IOException {
+        if (!mIsSparse) {
+            return mIn.read(buf);
+        }
+        if (prepareChunk()) return -1;
+        int n = -1;
+        switch (mCur.mChunkType) {
+            case SparseChunk.RAW:
+                n = mIn.read(buf, 0, (int) min(mLeft, buf.length));
+                mLeft -= n;
+                return n;
+            case SparseChunk.DONTCARE:
+                n = (int) min(mLeft, buf.length);
+                Arrays.fill(buf, 0, n - 1, (byte) 0);
+                mLeft -= n;
+                return n;
+            case SparseChunk.FILL:
+                // The FILL type is rarely used, so use a simple implmentation.
+                return super.read(buf);
+            default:
+                throw new IOException("Unsupported Chunk:" + mCur.toString());
+        }
+    }
+
+    /**
+     * It overrides the InputStream.read()
+     */
+    public int read() throws IOException {
+        if (!mIsSparse) {
+            return mIn.read();
+        }
+        if (prepareChunk()) return -1;
+        int ret = -1;
+        switch (mCur.mChunkType) {
+            case SparseChunk.RAW:
+                ret = mIn.read();
+                break;
+            case SparseChunk.DONTCARE:
+                ret = 0;
+                break;
+            case SparseChunk.FILL:
+                ret = mCur.fill[(4 - ((int) mLeft & 0x3)) & 0x3];
+                break;
+            default:
+                throw new IOException("Unsupported Chunk:" + mCur.toString());
+        }
+        mLeft--;
+        return ret;
+    }
+
+    /**
+     * Get the unsparse size
+     * @return -1 if unknown
+     */
+    public long getUnsparseSize() {
+        if (!mIsSparse) {
+            return -1;
+        }
+        return mBlockSize * mTotalBlocks;
+    }
+}
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 4a50210..7b2922ba 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -50,6 +50,7 @@
 import android.util.Pair;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.FileSystemProvider;
 import com.android.internal.util.IndentingPrintWriter;
 
@@ -308,37 +309,26 @@
     @Override
     protected boolean shouldBlockFromTree(@NonNull String docId) {
         try {
-            final File dir = getFileForDocId(docId, true /* visible */).getCanonicalFile();
-            if (!dir.isDirectory()) {
+            final File dir = getFileForDocId(docId, false /* visible */);
+
+            // the file is null or it is not a directory
+            if (dir == null || !dir.isDirectory()) {
                 return false;
             }
 
-            final String path = dir.getAbsolutePath();
+            final String path = getPathFromDocId(docId);
 
-            // Block Download folder from tree
-            if (MediaStore.Downloads.isDownloadDir(path)) {
+            // Block the root of the storage
+            if (path.isEmpty()) {
                 return true;
             }
 
-            final ArrayMap<String, RootInfo> roots = new ArrayMap<>();
-
-            synchronized (mRootsLock) {
-                roots.putAll(mRoots);
+            // Block Download folder from tree
+            if (TextUtils.equals(Environment.DIRECTORY_DOWNLOADS.toLowerCase(),
+                    path.toLowerCase())) {
+                return true;
             }
 
-            // block root of storage
-            for (int i = 0; i < roots.size(); i++) {
-                RootInfo rootInfo = roots.valueAt(i);
-                // skip home root
-                if (TextUtils.equals(rootInfo.rootId, ROOT_ID_HOME)) {
-                    continue;
-                }
-
-                // block the root of storage
-                if (TextUtils.equals(path, rootInfo.visiblePath.getAbsolutePath())) {
-                    return true;
-                }
-            }
             return false;
         } catch (IOException e) {
             throw new IllegalArgumentException(
@@ -430,6 +420,23 @@
         return Pair.create(root, buildFile(root, docId, visible, true));
     }
 
+    @VisibleForTesting
+    static String getPathFromDocId(String docId) {
+        final int splitIndex = docId.indexOf(':', 1);
+        final String path = docId.substring(splitIndex + 1);
+
+        if (path.isEmpty()) {
+            return path;
+        }
+
+        // remove trailing "/"
+        if (path.charAt(path.length() - 1) == '/') {
+            return path.substring(0, path.length() - 1);
+        } else {
+            return path;
+        }
+    }
+
     private RootInfo getRootFromDocId(String docId) throws FileNotFoundException {
         final int splitIndex = docId.indexOf(':', 1);
         final String tag = docId.substring(0, splitIndex);
diff --git a/packages/ExternalStorageProvider/tests/src/com/android/externalstorage/ExternalStorageProviderTest.java b/packages/ExternalStorageProvider/tests/src/com/android/externalstorage/ExternalStorageProviderTest.java
index fbf2e4b..ed8320f 100644
--- a/packages/ExternalStorageProvider/tests/src/com/android/externalstorage/ExternalStorageProviderTest.java
+++ b/packages/ExternalStorageProvider/tests/src/com/android/externalstorage/ExternalStorageProviderTest.java
@@ -17,7 +17,10 @@
 package com.android.externalstorage;
 
 import static com.android.externalstorage.ExternalStorageProvider.AUTHORITY;
+import static com.android.externalstorage.ExternalStorageProvider.getPathFromDocId;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -51,4 +54,18 @@
 
         verify(spyProvider, atLeast(1)).updateVolumes();
     }
+
+    @Test
+    public void testGetPathFromDocId() throws Exception {
+        final String root = "root";
+        final String path = "abc/def/ghi";
+        String docId = root + ":" + path;
+        assertEquals(getPathFromDocId(docId), path);
+
+        docId = root + ":" + path + "/";
+        assertEquals(getPathFromDocId(docId), path);
+
+        docId = root + ":";
+        assertTrue(getPathFromDocId(docId).isEmpty());
+    }
 }
diff --git a/packages/SettingsLib/SearchProvider/Android.bp b/packages/SettingsLib/SearchProvider/Android.bp
new file mode 100644
index 0000000..5254dde
--- /dev/null
+++ b/packages/SettingsLib/SearchProvider/Android.bp
@@ -0,0 +1,8 @@
+android_library {
+    name: "SettingsLibSearchProvider",
+
+    srcs: ["src/**/*.java"],
+
+    sdk_version: "system_current",
+    min_sdk_version: "21",
+}
diff --git a/packages/SettingsLib/SearchProvider/AndroidManifest.xml b/packages/SettingsLib/SearchProvider/AndroidManifest.xml
new file mode 100644
index 0000000..2c06673
--- /dev/null
+++ b/packages/SettingsLib/SearchProvider/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.settingslib.search">
+
+    <uses-sdk android:minSdkVersion="21" />
+
+</manifest>
diff --git a/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java b/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java
new file mode 100644
index 0000000..0b711ec
--- /dev/null
+++ b/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java
@@ -0,0 +1,120 @@
+/*
+ * 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.settingslib.searchprovider;
+
+import static android.provider.SearchIndexablesContract.INDEXABLES_XML_RES_COLUMNS;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.provider.SearchIndexableResource;
+import android.provider.SearchIndexablesContract.XmlResource;
+import android.provider.SearchIndexablesProvider;
+import android.text.TextUtils;
+
+import java.util.Collection;
+
+/**
+ * An abstract SearchIndexProvider using {@link SearchIndexableIntentResource} for indexing
+ */
+public abstract class SettingsXmlIndexProvider extends SearchIndexablesProvider {
+    private static final String TAG = "XmlIndexProvider";
+
+    @Override
+    public boolean onCreate() {
+        return true;
+    }
+
+    @Override
+    public Cursor queryXmlResources(String[] projection) {
+        final Context context = getContext();
+        final MatrixCursor cursor = new MatrixCursor(INDEXABLES_XML_RES_COLUMNS);
+        final Collection<SearchIndexableIntentResource> resources = getIntentResources();
+
+        for (SearchIndexableIntentResource indexableResource : resources) {
+            cursor.newRow()
+                    .add(XmlResource.COLUMN_RANK, indexableResource.rank)
+                    .add(XmlResource.COLUMN_XML_RESID, indexableResource.xmlResId)
+                    .add(XmlResource.COLUMN_CLASS_NAME, indexableResource.className)
+                    .add(XmlResource.COLUMN_INTENT_ACTION, indexableResource.intentAction)
+                    .add(XmlResource.COLUMN_INTENT_TARGET_PACKAGE, context.getPackageName())
+                    .add(XmlResource.COLUMN_INTENT_TARGET_CLASS,
+                            indexableResource.intentTargetClass);
+        }
+        return cursor;
+    }
+
+    /**
+     * Returns all {@link android.provider.SearchIndexablesContract.RawData}.
+     *
+     * Those are the raw indexable data.
+     *
+     * @param projection list of {@link android.provider.SearchIndexablesContract.RawData} columns
+     *                   to put into the cursor. If {@code null} all supported columns should be
+     *                   included.
+     */
+    public Cursor queryRawData(String[] projection) {
+        return null;
+    }
+
+    /**
+     * Returns all {@link android.provider.SearchIndexablesContract.NonIndexableKey}.
+     *
+     * Those are the non indexable data keys.
+     *
+     * @param projection list of {@link android.provider.SearchIndexablesContract.NonIndexableKey}
+     *                   columns to put into the cursor. If {@code null} all supported columns
+     *                   should be included.
+     */
+    public Cursor queryNonIndexableKeys(String[] projection) {
+        return null;
+    }
+
+    /**
+     * Returns a Collection of {@link SearchIndexableIntentResource} that should be indexed for
+     * search.
+     */
+    protected abstract Collection<SearchIndexableIntentResource> getIntentResources();
+
+    /**
+     * Wrapper class of {@link SearchIndexableResource}. It is for setting the search indexable
+     * resource of corresponding XML and intent action with class.
+     */
+    public static final class SearchIndexableIntentResource extends SearchIndexableResource {
+        /**
+         * Constructor of {@link SearchIndexableIntentResource}.
+         *
+         * @param xmlResId preference xml of target {@link prefereceFragment}
+         * @param intentAction the intent to open target {@link Activity}
+         * @param className the target {@link Activity} class name
+         */
+        public SearchIndexableIntentResource(int xmlResId, String intentAction,
+                String className) {
+            super(
+                    0 /* rank */,
+                    xmlResId,
+                    className,
+                    0 /* icon resource id */);
+            if (TextUtils.isEmpty(intentAction)) {
+                this.intentAction = "android.intent.action.MAIN";
+            } else {
+                this.intentAction = intentAction;
+            }
+            this.intentTargetClass = className;
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
index 9672fea..9f16d03 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
@@ -408,23 +408,6 @@
     }
 
     /**
-     * Checks if {@link android.app.admin.DevicePolicyManager#setAutoTimeRequired} is enforced
-     * on the device.
-     *
-     * @return EnforcedAdmin Object containing the device owner component and
-     * userId the device owner is running as, or {@code null} setAutoTimeRequired is not enforced.
-     */
-    public static EnforcedAdmin checkIfAutoTimeRequired(Context context) {
-        DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
-                Context.DEVICE_POLICY_SERVICE);
-        if (dpm == null || !dpm.getAutoTimeRequired()) {
-            return null;
-        }
-        ComponentName adminComponent = dpm.getDeviceOwnerComponentOnCallingUser();
-        return new EnforcedAdmin(adminComponent, getUserHandleOf(UserHandle.myUserId()));
-    }
-
-    /**
      * Checks if an admin has enforced minimum password quality requirements on the given user.
      *
      * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 785dd56..96aee51 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -44,8 +44,8 @@
     private final CachedBluetoothDeviceManager mDeviceManager;
 
     static final ParcelUuid[] SINK_UUIDS = {
-        BluetoothUuid.AudioSink,
-        BluetoothUuid.AdvAudioDist,
+        BluetoothUuid.A2DP_SINK,
+        BluetoothUuid.ADV_AUDIO_DIST,
     };
 
     static final String NAME = "A2DP";
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
index 4ce9d3e..55765dd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
@@ -40,8 +40,8 @@
     private final CachedBluetoothDeviceManager mDeviceManager;
 
     static final ParcelUuid[] SRC_UUIDS = {
-        BluetoothUuid.AudioSource,
-        BluetoothUuid.AdvAudioDist,
+        BluetoothUuid.A2DP_SOURCE,
+        BluetoothUuid.ADV_AUDIO_DIST,
     };
 
     static final String NAME = "A2DPSink";
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java
index 8dec86a..b8ad321 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java
@@ -22,6 +22,8 @@
 import android.os.ParcelUuid;
 import android.util.Log;
 
+import com.android.internal.util.ArrayUtils;
+
 /**
  * BluetoothDeviceFilter contains a static method that returns a
  * Filter object that returns whether or not the BluetoothDevice
@@ -130,7 +132,7 @@
         @Override
         boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) {
             if (uuids != null) {
-                if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush)) {
+                if (ArrayUtils.contains(uuids, BluetoothUuid.OBEX_OBJECT_PUSH)) {
                     return true;
                 }
             }
@@ -144,7 +146,7 @@
         @Override
         boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) {
             if (uuids != null) {
-                if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.PANU)) {
+                if (ArrayUtils.contains(uuids, BluetoothUuid.PANU)) {
                     return true;
                 }
             }
@@ -158,7 +160,7 @@
         @Override
         boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) {
             if (uuids != null) {
-                if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP)) {
+                if (ArrayUtils.contains(uuids, BluetoothUuid.NAP)) {
                     return true;
                 }
             }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 833c4ac..0666596 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -35,6 +35,7 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.settingslib.R;
 import com.android.settingslib.Utils;
 
@@ -685,9 +686,9 @@
         ParcelUuid[] uuids = mDevice.getUuids();
 
         long timeout = MAX_UUID_DELAY_FOR_AUTO_CONNECT;
-        if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hogp)) {
+        if (ArrayUtils.contains(uuids, BluetoothUuid.HOGP)) {
             timeout = MAX_HOGP_DELAY_FOR_AUTO_CONNECT;
-        } else if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HearingAid)) {
+        } else if (ArrayUtils.contains(uuids, BluetoothUuid.HEARING_AID)) {
             timeout = MAX_HEARING_AIDS_DELAY_FOR_AUTO_CONNECT;
         }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index c1933fd..9f7b718 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -45,7 +45,7 @@
 
     static final ParcelUuid[] UUIDS = {
         BluetoothUuid.HSP,
-        BluetoothUuid.Handsfree,
+        BluetoothUuid.HFP,
     };
 
     static final String NAME = "HEADSET";
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
index 4bdbc31..860b77d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
@@ -44,7 +44,7 @@
 
     static final ParcelUuid[] SRC_UUIDS = {
         BluetoothUuid.HSP_AG,
-        BluetoothUuid.Handsfree_AG,
+        BluetoothUuid.HFP_AG,
     };
 
     static final String NAME = "HEADSET_CLIENT";
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 29c6d71..ae2acbe 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -30,8 +30,8 @@
 import android.bluetooth.BluetoothPan;
 import android.bluetooth.BluetoothPbap;
 import android.bluetooth.BluetoothPbapClient;
-import android.bluetooth.BluetoothSap;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothSap;
 import android.bluetooth.BluetoothUuid;
 import android.content.Context;
 import android.content.Intent;
@@ -40,6 +40,7 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.CollectionUtils;
 
 import java.util.ArrayList;
@@ -471,43 +472,40 @@
         }
 
         if (mHeadsetProfile != null) {
-            if ((BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.HSP_AG) &&
-                    BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP)) ||
-                    (BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree_AG) &&
-                            BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree))) {
+            if ((ArrayUtils.contains(localUuids, BluetoothUuid.HSP_AG)
+                    && ArrayUtils.contains(uuids, BluetoothUuid.HSP))
+                    || (ArrayUtils.contains(localUuids, BluetoothUuid.HFP_AG)
+                    && ArrayUtils.contains(uuids, BluetoothUuid.HFP))) {
                 profiles.add(mHeadsetProfile);
                 removedProfiles.remove(mHeadsetProfile);
             }
         }
 
         if ((mHfpClientProfile != null) &&
-                BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree_AG) &&
-                BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree)) {
+                ArrayUtils.contains(uuids, BluetoothUuid.HFP_AG)
+                && ArrayUtils.contains(localUuids, BluetoothUuid.HFP)) {
             profiles.add(mHfpClientProfile);
             removedProfiles.remove(mHfpClientProfile);
         }
 
-        if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS) &&
-            mA2dpProfile != null) {
+        if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS) && mA2dpProfile != null) {
             profiles.add(mA2dpProfile);
             removedProfiles.remove(mA2dpProfile);
         }
 
-        if (BluetoothUuid.containsAnyUuid(uuids, A2dpSinkProfile.SRC_UUIDS) &&
-                mA2dpSinkProfile != null) {
+        if (BluetoothUuid.containsAnyUuid(uuids, A2dpSinkProfile.SRC_UUIDS)
+                && mA2dpSinkProfile != null) {
                 profiles.add(mA2dpSinkProfile);
                 removedProfiles.remove(mA2dpSinkProfile);
         }
 
-        if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush) &&
-            mOppProfile != null) {
+        if (ArrayUtils.contains(uuids, BluetoothUuid.OBEX_OBJECT_PUSH) && mOppProfile != null) {
             profiles.add(mOppProfile);
             removedProfiles.remove(mOppProfile);
         }
 
-        if ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hid) ||
-             BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hogp)) &&
-            mHidProfile != null) {
+        if ((ArrayUtils.contains(uuids, BluetoothUuid.HID)
+                || ArrayUtils.contains(uuids, BluetoothUuid.HOGP)) && mHidProfile != null) {
             profiles.add(mHidProfile);
             removedProfiles.remove(mHidProfile);
         }
@@ -520,8 +518,8 @@
 
         if(isPanNapConnected)
             if(DEBUG) Log.d(TAG, "Valid PAN-NAP connection exists.");
-        if ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP) &&
-            mPanProfile != null) || isPanNapConnected) {
+        if ((ArrayUtils.contains(uuids, BluetoothUuid.NAP) && mPanProfile != null)
+                || isPanNapConnected) {
             profiles.add(mPanProfile);
             removedProfiles.remove(mPanProfile);
         }
@@ -545,20 +543,18 @@
             removedProfiles.remove(mMapClientProfile);
         }
 
-        if ((mPbapClientProfile != null) &&
-                BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.PBAP_PCE) &&
-                BluetoothUuid.containsAnyUuid(uuids, PbapClientProfile.SRC_UUIDS)) {
+        if ((mPbapClientProfile != null) && ArrayUtils.contains(localUuids, BluetoothUuid.PBAP_PCE)
+                && BluetoothUuid.containsAnyUuid(uuids, PbapClientProfile.SRC_UUIDS)) {
             profiles.add(mPbapClientProfile);
             removedProfiles.remove(mPbapClientProfile);
         }
 
-        if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HearingAid) &&
-            mHearingAidProfile != null) {
+        if (ArrayUtils.contains(uuids, BluetoothUuid.HEARING_AID) && mHearingAidProfile != null) {
             profiles.add(mHearingAidProfile);
             removedProfiles.remove(mHearingAidProfile);
         }
 
-        if (mSapProfile != null && BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.SAP)) {
+        if (mSapProfile != null && ArrayUtils.contains(uuids, BluetoothUuid.SAP)) {
             profiles.add(mSapProfile);
             removedProfiles.remove(mSapProfile);
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
index 17104e4..d91226e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
@@ -46,7 +46,7 @@
     // The UUIDs indicate that remote device might access pbap server
     static final ParcelUuid[] PBAB_CLIENT_UUIDS = {
         BluetoothUuid.HSP,
-        BluetoothUuid.Handsfree,
+        BluetoothUuid.HFP,
         BluetoothUuid.PBAP_PCE
     };
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
index 1c62879..0a1a122 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
@@ -76,6 +76,19 @@
     }
 
     /**
+     * Logs the elapsed time from onAttach to calling {@link #writeElapsedTimeMetric(int, String)}.
+     * @param action : The value of the Action Enums.
+     * @param key : The value of special key string.
+     */
+    public void writeElapsedTimeMetric(int action, String key) {
+        if (mMetricsFeature == null || mMetricsCategory == METRICS_CATEGORY_UNKNOWN) {
+            return;
+        }
+        final int elapse = (int) (SystemClock.elapsedRealtime() - mTimestamp);
+        mMetricsFeature.action(METRICS_CATEGORY_UNKNOWN, action, mMetricsCategory, key, elapse);
+    }
+
+    /**
      * Sets source metrics category for this logger. Source is the caller that opened this UI.
      */
     public void setSourceMetricsCategory(Activity activity) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java b/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
index 5ac788e..3b41fa9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
@@ -32,7 +32,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.DrawableWrapper;
 import android.os.Handler;
-import android.telephony.SignalStrength;
+import android.telephony.CellSignalStrength;
 import android.util.LayoutDirection;
 import android.util.PathParser;
 
@@ -145,7 +145,7 @@
 
     private int unpackLevel(int packedState) {
         int numBins = (packedState & NUM_LEVEL_MASK) >> NUM_LEVEL_SHIFT;
-        int levelOffset = numBins == (SignalStrength.NUM_SIGNAL_STRENGTH_BINS + 1) ? 10 : 0;
+        int levelOffset = numBins == (CellSignalStrength.getNumSignalStrengthLevels() + 1) ? 10 : 0;
         int level = (packedState & LEVEL_MASK);
         return level + levelOffset;
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java b/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
index f14def1..653c8ad 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/EnableZenModeDialog.java
@@ -328,7 +328,6 @@
             boolean enabled, int rowId, Uri conditionId) {
         if (tag.lines == null) {
             tag.lines = row.findViewById(android.R.id.content);
-            tag.lines.setAccessibilityLiveRegion(View.ACCESSIBILITY_LIVE_REGION_POLITE);
         }
         if (tag.line1 == null) {
             tag.line1 = (TextView) row.findViewById(android.R.id.text1);
@@ -364,6 +363,7 @@
             @Override
             public void onClick(View v) {
                 onClickTimeButton(row, tag, false /*down*/, rowId);
+                tag.lines.setAccessibilityLiveRegion(View.ACCESSIBILITY_LIVE_REGION_POLITE);
             }
         });
 
@@ -373,6 +373,7 @@
             @Override
             public void onClick(View v) {
                 onClickTimeButton(row, tag, true /*up*/, rowId);
+                tag.lines.setAccessibilityLiveRegion(View.ACCESSIBILITY_LIVE_REGION_POLITE);
             }
         });
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/ZenDurationDialog.java b/packages/SettingsLib/src/com/android/settingslib/notification/ZenDurationDialog.java
index 66ee802..01a5789 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/ZenDurationDialog.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/ZenDurationDialog.java
@@ -234,6 +234,7 @@
             @Override
             public void onClick(View v) {
                 onClickTimeButton(row, tag, false /*down*/, rowIndex);
+                tag.lines.setAccessibilityLiveRegion(View.ACCESSIBILITY_LIVE_REGION_POLITE);
             }
         });
 
@@ -243,6 +244,7 @@
             @Override
             public void onClick(View v) {
                 onClickTimeButton(row, tag, true /*up*/, rowIndex);
+                tag.lines.setAccessibilityLiveRegion(View.ACCESSIBILITY_LIVE_REGION_POLITE);
             }
         });
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index f2af40e..328bfb2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -33,7 +33,6 @@
 import android.net.NetworkScoreManager;
 import android.net.NetworkScorerAppData;
 import android.net.ScoredNetwork;
-import android.net.wifi.IWifiManager;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
@@ -47,7 +46,6 @@
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -190,6 +188,8 @@
     static final String KEY_SUBSCRIPTION_EXPIRATION_TIME_IN_MILLIS  =
             "key_subscription_expiration_time_in_millis";
     static final String KEY_PASSPOINT_CONFIGURATION_VERSION = "key_passpoint_configuration_version";
+    static final String KEY_IS_PSK_SAE_TRANSITION_MODE = "key_is_psk_sae_transition_mode";
+    static final String KEY_IS_OWE_TRANSITION_MODE = "key_is_owe_transition_mode";
     static final AtomicInteger sLastId = new AtomicInteger(0);
 
     /*
@@ -204,15 +204,12 @@
     public static final int SECURITY_OWE = 4;
     public static final int SECURITY_SAE = 5;
     public static final int SECURITY_EAP_SUITE_B = 6;
-    public static final int SECURITY_PSK_SAE_TRANSITION = 7;
-    public static final int SECURITY_OWE_TRANSITION = 8;
-    public static final int SECURITY_MAX_VAL = 9; // Has to be the last
+    public static final int SECURITY_MAX_VAL = 7; // Has to be the last
 
     private static final int PSK_UNKNOWN = 0;
     private static final int PSK_WPA = 1;
     private static final int PSK_WPA2 = 2;
     private static final int PSK_WPA_WPA2 = 3;
-    private static final int PSK_SAE = 4;
 
     private static final int EAP_UNKNOWN = 0;
     private static final int EAP_WPA = 1; // WPA-EAP
@@ -276,6 +273,9 @@
     private String mOsuFailure;
     private boolean mOsuProvisioningComplete = false;
 
+    private boolean mIsPskSaeTransitionMode = false;
+    private boolean mIsOweTransitionMode = false;
+
     /**
      * The EAP type {@link WifiEnterpriseConfig.Eap} associated with this AP if it is a carrier AP.
      */
@@ -346,6 +346,13 @@
         if (savedState.containsKey(KEY_PASSPOINT_CONFIGURATION_VERSION)) {
             mPasspointConfigurationVersion = savedState.getInt(KEY_PASSPOINT_CONFIGURATION_VERSION);
         }
+        if (savedState.containsKey(KEY_IS_PSK_SAE_TRANSITION_MODE)) {
+            mIsPskSaeTransitionMode = savedState.getBoolean(KEY_IS_PSK_SAE_TRANSITION_MODE);
+        }
+        if (savedState.containsKey(KEY_IS_OWE_TRANSITION_MODE)) {
+            mIsOweTransitionMode = savedState.getBoolean(KEY_IS_OWE_TRANSITION_MODE);
+        }
+
         update(mConfig, mInfo, mNetworkInfo);
 
         // Calculate required fields
@@ -677,8 +684,15 @@
         return oldMetering == mIsScoredNetworkMetered;
     }
 
-    public static String getKey(ScanResult result) {
-        return getKey(result.SSID, result.BSSID, getSecurity(result));
+    /**
+     * Generates an AccessPoint key for a given scan result
+     *
+     * @param context
+     * @param result Scan result
+     * @return AccessPoint key
+     */
+    public static String getKey(Context context, ScanResult result) {
+        return getKey(result.SSID, result.BSSID, getSecurity(context, result));
     }
 
     /**
@@ -736,7 +750,42 @@
      * Determines if the other AccessPoint represents the same network as this AccessPoint
      */
     public boolean matches(AccessPoint other) {
-        return getKey().equals(other.getKey());
+        if (isPasspoint() || isPasspointConfig() || isOsuProvider()) {
+            return getKey().equals(other.getKey());
+        }
+
+        if (!isSameSsidOrBssid(other)) {
+            return false;
+        }
+
+        final int otherApSecurity = other.getSecurity();
+        if (mIsPskSaeTransitionMode) {
+            if (otherApSecurity == SECURITY_SAE && getWifiManager().isWpa3SaeSupported()) {
+                return true;
+            } else if (otherApSecurity == SECURITY_PSK) {
+                return true;
+            }
+        } else {
+            if ((security == SECURITY_SAE || security == SECURITY_PSK)
+                    && other.isPskSaeTransitionMode()) {
+                return true;
+            }
+        }
+
+        if (mIsOweTransitionMode) {
+            if (otherApSecurity == SECURITY_OWE && getWifiManager().isEnhancedOpenSupported()) {
+                return true;
+            } else if (otherApSecurity == SECURITY_NONE) {
+                return true;
+            }
+        } else {
+            if ((security == SECURITY_OWE || security == SECURITY_NONE)
+                    && other.isOweTransitionMode()) {
+                return true;
+            }
+        }
+
+        return security == other.getSecurity();
     }
 
     public boolean matches(WifiConfiguration config) {
@@ -750,18 +799,77 @@
         }
 
         final int configSecurity = getSecurity(config);
-        final WifiManager wifiManager = getWifiManager();
-        switch (security) {
-            case SECURITY_PSK_SAE_TRANSITION:
-                return configSecurity == SECURITY_PSK
-                        || (wifiManager.isWpa3SaeSupported() && configSecurity == SECURITY_SAE);
-            case SECURITY_OWE_TRANSITION:
-                return configSecurity == SECURITY_NONE
-                        || (wifiManager.isEnhancedOpenSupported()
-                                && configSecurity == SECURITY_OWE);
-            default:
-                return security == configSecurity;
+        if (mIsPskSaeTransitionMode) {
+            if (configSecurity == SECURITY_SAE && getWifiManager().isWpa3SaeSupported()) {
+                return true;
+            } else if (configSecurity == SECURITY_PSK) {
+                return true;
+            }
         }
+
+        if (mIsOweTransitionMode) {
+            if (configSecurity == SECURITY_OWE && getWifiManager().isEnhancedOpenSupported()) {
+                return true;
+            } else if (configSecurity == SECURITY_NONE) {
+                return true;
+            }
+        }
+
+        return security == getSecurity(config);
+    }
+
+    private boolean matches(WifiConfiguration config, WifiInfo wifiInfo) {
+        if (config == null || wifiInfo == null) {
+            return false;
+        }
+        if (!config.isPasspoint() && !isSameSsidOrBssid(wifiInfo)) {
+            return false;
+        }
+        return matches(config);
+    }
+
+    @VisibleForTesting
+    boolean matches(ScanResult scanResult) {
+        if (scanResult == null) {
+            return false;
+        }
+        if (isPasspoint() || isOsuProvider()) {
+            throw new IllegalStateException("Should not matches a Passpoint by ScanResult");
+        }
+
+        if (!isSameSsidOrBssid(scanResult)) {
+            return false;
+        }
+
+        if (mIsPskSaeTransitionMode) {
+            if (scanResult.capabilities.contains("SAE")
+                    && getWifiManager().isWpa3SaeSupported()) {
+                return true;
+            } else if (scanResult.capabilities.contains("PSK")) {
+                return true;
+            }
+        } else {
+            if ((security == SECURITY_SAE || security == SECURITY_PSK)
+                    && AccessPoint.isPskSaeTransitionMode(scanResult)) {
+                return true;
+            }
+        }
+
+        if (mIsOweTransitionMode) {
+            final int scanResultSccurity = getSecurity(mContext, scanResult);
+            if (scanResultSccurity == SECURITY_OWE && getWifiManager().isEnhancedOpenSupported()) {
+                return true;
+            } else if (scanResultSccurity == SECURITY_NONE) {
+                return true;
+            }
+        } else {
+            if ((security == SECURITY_OWE || security == SECURITY_NONE)
+                    && AccessPoint.isOweTransitionMode(scanResult)) {
+                return true;
+            }
+        }
+
+        return security == getSecurity(mContext, scanResult);
     }
 
     public WifiConfiguration getConfig() {
@@ -848,14 +956,17 @@
         if (bestResult != null) {
             ssid = bestResult.SSID;
             bssid = bestResult.BSSID;
-            security = getSecurity(bestResult);
-            if (security == SECURITY_PSK || security == SECURITY_SAE
-                    || security == SECURITY_PSK_SAE_TRANSITION) {
+            security = getSecurity(mContext, bestResult);
+            if (security == SECURITY_PSK || security == SECURITY_SAE) {
                 pskType = getPskType(bestResult);
             }
             if (security == SECURITY_EAP) {
                 mEapType = getEapType(bestResult);
             }
+
+            mIsPskSaeTransitionMode = AccessPoint.isPskSaeTransitionMode(bestResult);
+            mIsOweTransitionMode = AccessPoint.isOweTransitionMode(bestResult);
+
             mIsCarrierAp = bestResult.isCarrierAp;
             mCarrierApEapType = bestResult.carrierApEapType;
             mCarrierName = bestResult.carrierName;
@@ -888,6 +999,12 @@
             return concise ? context.getString(R.string.wifi_security_short_eap) :
                 context.getString(R.string.wifi_security_eap);
         }
+
+        if (mIsPskSaeTransitionMode) {
+            return concise ? context.getString(R.string.wifi_security_short_psk_sae) :
+                    context.getString(R.string.wifi_security_psk_sae);
+        }
+
         switch(security) {
             case SECURITY_EAP:
                 switch (mEapType) {
@@ -927,20 +1044,8 @@
                 return concise ? context.getString(R.string.wifi_security_short_wep) :
                     context.getString(R.string.wifi_security_wep);
             case SECURITY_SAE:
-            case SECURITY_PSK_SAE_TRANSITION:
-                if (pskType == PSK_SAE) {
-                    return concise ? context.getString(R.string.wifi_security_short_psk_sae) :
-                            context.getString(R.string.wifi_security_psk_sae);
-                } else {
-                    return concise ? context.getString(R.string.wifi_security_short_sae) :
-                            context.getString(R.string.wifi_security_sae);
-                }
-            case SECURITY_OWE_TRANSITION:
-                if (mConfig != null && getSecurity(mConfig) == SECURITY_OWE) {
-                    return concise ? context.getString(R.string.wifi_security_short_owe) :
-                            context.getString(R.string.wifi_security_owe);
-                }
-                return concise ? "" : context.getString(R.string.wifi_security_none);
+                return concise ? context.getString(R.string.wifi_security_short_sae) :
+                        context.getString(R.string.wifi_security_sae);
             case SECURITY_OWE:
                 return concise ? context.getString(R.string.wifi_security_short_owe) :
                     context.getString(R.string.wifi_security_owe);
@@ -1252,7 +1357,7 @@
         if (networkId != WifiConfiguration.INVALID_NETWORK_ID) {
             return networkId == info.getNetworkId();
         } else if (config != null) {
-            return isKeyEqual(getKey(config));
+            return matches(config, info);
         } else {
             // Might be an ephemeral connection with no WifiConfiguration. Try matching on SSID.
             // (Note that we only do this if the WifiConfiguration explicitly equals INVALID).
@@ -1324,43 +1429,14 @@
         savedState.putLong(KEY_SUBSCRIPTION_EXPIRATION_TIME_IN_MILLIS,
                 mSubscriptionExpirationTimeInMillis);
         savedState.putInt(KEY_PASSPOINT_CONFIGURATION_VERSION, mPasspointConfigurationVersion);
+        savedState.putBoolean(KEY_IS_PSK_SAE_TRANSITION_MODE, mIsPskSaeTransitionMode);
+        savedState.putBoolean(KEY_IS_OWE_TRANSITION_MODE, mIsOweTransitionMode);
     }
 
     public void setListener(AccessPointListener listener) {
         mAccessPointListener = listener;
     }
 
-    private static final String sPskSuffix = "," + String.valueOf(SECURITY_PSK);
-    private static final String sSaeSuffix = "," + String.valueOf(SECURITY_SAE);
-    private static final String sPskSaeSuffix = "," + String.valueOf(SECURITY_PSK_SAE_TRANSITION);
-    private static final String sOweSuffix = "," + String.valueOf(SECURITY_OWE);
-    private static final String sOpenSuffix = "," + String.valueOf(SECURITY_NONE);
-    private static final String sOweTransSuffix = "," + String.valueOf(SECURITY_OWE_TRANSITION);
-
-    private boolean isKeyEqual(String compareTo) {
-        if (mKey == null) {
-            return false;
-        }
-
-        if (compareTo.endsWith(sPskSuffix) || compareTo.endsWith(sSaeSuffix)) {
-            if (mKey.endsWith(sPskSaeSuffix)) {
-                // Special handling for PSK-SAE transition mode. If the AP has advertised both,
-                // we compare the key with both PSK and SAE for a match.
-                return TextUtils.equals(mKey.substring(0, mKey.lastIndexOf(',')),
-                        compareTo.substring(0, compareTo.lastIndexOf(',')));
-            }
-        }
-        if (compareTo.endsWith(sOpenSuffix) || compareTo.endsWith(sOweSuffix)) {
-            if (mKey.endsWith(sOweTransSuffix)) {
-                // Special handling for OWE/Open networks. If AP advertises OWE in transition mode
-                // and we have an Open network saved, allow this connection to be established.
-                return TextUtils.equals(mKey.substring(0, mKey.lastIndexOf(',')),
-                        compareTo.substring(0, compareTo.lastIndexOf(',')));
-            }
-        }
-        return mKey.equals(compareTo);
-    }
-
     /**
      * Sets {@link #mScanResults} to the given collection and updates info based on the best RSSI
      * scan result.
@@ -1377,11 +1453,10 @@
         // Passpoint networks are not bound to a specific SSID/BSSID, so skip this for passpoint.
         if (mKey != null && !isPasspoint() && !isOsuProvider()) {
             for (ScanResult result : scanResults) {
-                String scanResultKey = AccessPoint.getKey(result);
-                if (!isKeyEqual(scanResultKey)) {
+                if (!matches(result)) {
                     Log.d(TAG, String.format(
-                                    "ScanResult %s\nkey of %s did not match current AP key %s",
-                                    result, scanResultKey, mKey));
+                            "ScanResult %s\nkey of %s did not match current AP key %s",
+                            result, getKey(mContext, result), mKey));
                     return;
                 }
             }
@@ -1612,13 +1687,8 @@
         final ConnectivityManager cm = (ConnectivityManager)
                 context.getSystemService(Context.CONNECTIVITY_SERVICE);
         if (state == DetailedState.CONNECTED) {
-            IWifiManager wifiManager = IWifiManager.Stub.asInterface(
-                    ServiceManager.getService(Context.WIFI_SERVICE));
-            NetworkCapabilities nc = null;
-
-            try {
-                nc = cm.getNetworkCapabilities(wifiManager.getCurrentNetwork());
-            } catch (RemoteException e) {}
+            WifiManager wifiManager = context.getSystemService(WifiManager.class);
+            NetworkCapabilities nc = cm.getNetworkCapabilities(wifiManager.getCurrentNetwork());
 
             if (nc != null) {
                 if (nc.hasCapability(nc.NET_CAPABILITY_CAPTIVE_PORTAL)) {
@@ -1660,11 +1730,8 @@
     private static int getPskType(ScanResult result) {
         boolean wpa = result.capabilities.contains("WPA-PSK");
         boolean wpa2 = result.capabilities.contains("RSN-PSK");
-        boolean wpa3TransitionMode = result.capabilities.contains("PSK+SAE");
         boolean wpa3 = result.capabilities.contains("RSN-SAE");
-        if (wpa3TransitionMode) {
-            return PSK_SAE;
-        } else if (wpa2 && wpa) {
+        if (wpa2 && wpa) {
             return PSK_WPA_WPA2;
         } else if (wpa2) {
             return PSK_WPA2;
@@ -1691,22 +1758,37 @@
         return EAP_UNKNOWN;
     }
 
-    private static int getSecurity(ScanResult result) {
-        if (result.capabilities.contains("WEP")) {
+    private static int getSecurity(Context context, ScanResult result) {
+        final boolean isWep = result.capabilities.contains("WEP");
+        final boolean isSae = result.capabilities.contains("SAE");
+        final boolean isPsk = result.capabilities.contains("PSK");
+        final boolean isEapSuiteB192 = result.capabilities.contains("EAP_SUITE_B_192");
+        final boolean isEap = result.capabilities.contains("EAP");
+        final boolean isOwe = result.capabilities.contains("OWE");
+        final boolean isOweTransition = result.capabilities.contains("OWE_TRANSITION");
+
+        if (isSae && isPsk) {
+            final WifiManager wifiManager = (WifiManager)
+                    context.getSystemService(Context.WIFI_SERVICE);
+            return wifiManager.isWpa3SaeSupported() ? SECURITY_SAE : SECURITY_PSK;
+        }
+        if (isOweTransition) {
+            final WifiManager wifiManager = (WifiManager)
+                    context.getSystemService(Context.WIFI_SERVICE);
+            return wifiManager.isEnhancedOpenSupported() ? SECURITY_OWE : SECURITY_NONE;
+        }
+
+        if (isWep) {
             return SECURITY_WEP;
-        } else if (result.capabilities.contains("PSK+SAE")) {
-            return SECURITY_PSK_SAE_TRANSITION;
-        } else if (result.capabilities.contains("SAE")) {
+        } else if (isSae) {
             return SECURITY_SAE;
-        } else if (result.capabilities.contains("PSK")) {
+        } else if (isPsk) {
             return SECURITY_PSK;
-        } else if (result.capabilities.contains("EAP_SUITE_B_192")) {
+        } else if (isEapSuiteB192) {
             return SECURITY_EAP_SUITE_B;
-        } else if (result.capabilities.contains("EAP")) {
+        } else if (isEap) {
             return SECURITY_EAP;
-        } else if (result.capabilities.contains("OWE_TRANSITION")) {
-            return SECURITY_OWE_TRANSITION;
-        } else if (result.capabilities.contains("OWE")) {
+        } else if (isOwe) {
             return SECURITY_OWE;
         }
         return SECURITY_NONE;
@@ -1752,10 +1834,6 @@
             return "SUITE_B";
         } else if (security == SECURITY_OWE) {
             return "OWE";
-        } else if (security == SECURITY_PSK_SAE_TRANSITION) {
-            return "PSK+SAE";
-        } else if (security == SECURITY_OWE_TRANSITION) {
-            return "OWE_TRANSITION";
         }
         return "NONE";
     }
@@ -1783,8 +1861,7 @@
      * Return true if this is an open network AccessPoint.
      */
     public boolean isOpenNetwork() {
-        return security == SECURITY_NONE || security == SECURITY_OWE
-                || security == SECURITY_OWE_TRANSITION;
+        return security == SECURITY_NONE || security == SECURITY_OWE;
     }
 
     /**
@@ -1933,4 +2010,61 @@
             }
         }
     }
+
+    public boolean isPskSaeTransitionMode() {
+        return mIsPskSaeTransitionMode;
+    }
+
+    public boolean isOweTransitionMode() {
+        return mIsOweTransitionMode;
+    }
+
+    private static boolean isPskSaeTransitionMode(ScanResult scanResult) {
+        return scanResult.capabilities.contains("PSK")
+                && scanResult.capabilities.contains("SAE");
+    }
+
+    private static boolean isOweTransitionMode(ScanResult scanResult) {
+        return scanResult.capabilities.contains("OWE_TRANSITION");
+    }
+
+    private boolean isSameSsidOrBssid(ScanResult scanResult) {
+        if (scanResult == null) {
+            return false;
+        }
+
+        if (TextUtils.equals(ssid, scanResult.SSID)) {
+            return true;
+        } else if (scanResult.BSSID != null && TextUtils.equals(bssid, scanResult.BSSID)) {
+            return true;
+        }
+        return false;
+    }
+
+    private boolean isSameSsidOrBssid(WifiInfo wifiInfo) {
+        if (wifiInfo == null) {
+            return false;
+        }
+
+        if (TextUtils.equals(ssid, removeDoubleQuotes(wifiInfo.getSSID()))) {
+            return true;
+        } else if (wifiInfo.getBSSID() != null && TextUtils.equals(bssid, wifiInfo.getBSSID())) {
+            return true;
+        }
+        return false;
+    }
+
+    private boolean isSameSsidOrBssid(AccessPoint accessPoint) {
+        if (accessPoint == null) {
+            return false;
+        }
+
+        if (TextUtils.equals(ssid, accessPoint.getSsid())) {
+            return true;
+        } else if (accessPoint.getBssid() != null
+                && TextUtils.equals(bssid, accessPoint.getBssid())) {
+            return true;
+        }
+        return false;
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index dae5464..6269a71 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -201,8 +201,7 @@
             return;
         }
         if ((mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE)
-                && (mAccessPoint.getSecurity() != AccessPoint.SECURITY_OWE)
-                && (mAccessPoint.getSecurity() != AccessPoint.SECURITY_OWE_TRANSITION)) {
+                && (mAccessPoint.getSecurity() != AccessPoint.SECURITY_OWE)) {
             mFrictionSld.setState(STATE_SECURED);
         } else if (mAccessPoint.isMetered()) {
             mFrictionSld.setState(STATE_METERED);
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 23b16e8..ba6a8ea 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -70,8 +70,10 @@
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
 
 /**
  * Tracks saved or available wifi networks and their state.
@@ -475,7 +477,7 @@
                 continue;
             }
 
-            String apKey = AccessPoint.getKey(result);
+            String apKey = AccessPoint.getKey(mContext, result);
             List<ScanResult> resultList;
             if (scanResultsByApKey.containsKey(apKey)) {
                 resultList = scanResultsByApKey.get(apKey);
@@ -547,14 +549,6 @@
     private void updateAccessPoints(final List<ScanResult> newScanResults,
             List<WifiConfiguration> configs) {
 
-        // Map configs and scan results necessary to make AccessPoints
-        final Map<String, WifiConfiguration> configsByKey = new ArrayMap(configs.size());
-        if (configs != null) {
-            for (WifiConfiguration config : configs) {
-                configsByKey.put(AccessPoint.getKey(config), config);
-            }
-        }
-
         WifiConfiguration connectionConfig = null;
         if (mLastInfo != null) {
             connectionConfig = getWifiConfigurationForNetworkId(mLastInfo.getNetworkId(), configs);
@@ -586,7 +580,26 @@
                         getCachedOrCreate(entry.getValue(), cachedAccessPoints);
 
                 // Update the matching config if there is one, to populate saved network info
-                accessPoint.update(configsByKey.get(entry.getKey()));
+                final List<WifiConfiguration> matchedConfigs = configs.stream()
+                        .filter(config -> accessPoint.matches(config))
+                        .collect(Collectors.toList());
+
+                final int matchedConfigCount = matchedConfigs.size();
+                if (matchedConfigCount == 0) {
+                    accessPoint.update(null);
+                } else if (matchedConfigCount == 1) {
+                    accessPoint.update(matchedConfigs.get(0));
+                } else {
+                    // We may have 2 matched configured WifiCongiguration if the AccessPoint is
+                    // of PSK/SAE transition mode or open/OWE transition mode.
+                    Optional<WifiConfiguration> preferredConfig = matchedConfigs.stream()
+                            .filter(config -> isSaeOrOwe(config)).findFirst();
+                    if (preferredConfig.isPresent()) {
+                        accessPoint.update(preferredConfig.get());
+                    } else {
+                        accessPoint.update(matchedConfigs.get(0));
+                    }
+                }
 
                 accessPoints.add(accessPoint);
             }
@@ -652,6 +665,11 @@
         conditionallyNotifyListeners();
     }
 
+    private static boolean isSaeOrOwe(WifiConfiguration config) {
+        final int security = AccessPoint.getSecurity(config);
+        return security == AccessPoint.SECURITY_SAE || security == AccessPoint.SECURITY_OWE;
+    }
+
     @VisibleForTesting
     List<AccessPoint> updatePasspointAccessPoints(
             List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> passpointConfigsAndScans,
@@ -700,7 +718,8 @@
     private AccessPoint getCachedOrCreate(
             List<ScanResult> scanResults,
             List<AccessPoint> cache) {
-        AccessPoint accessPoint = getCachedByKey(cache, AccessPoint.getKey(scanResults.get(0)));
+        AccessPoint accessPoint = getCachedByKey(cache,
+                AccessPoint.getKey(mContext, scanResults.get(0)));
         if (accessPoint == null) {
             accessPoint = new AccessPoint(mContext, scanResults);
         } else {
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 7d06e6c..325366e 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -39,6 +39,7 @@
 import android.net.WifiKey;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.net.wifi.WifiEnterpriseConfig;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
@@ -120,7 +121,7 @@
     private OsuProvider createOsuProvider() {
         Map<String, String> friendlyNames = new HashMap<>();
         friendlyNames.put("en", OSU_FRIENDLY_NAME);
-        return new OsuProvider((WifiSsid) null, friendlyNames, null, null, null, null, null);
+        return new OsuProvider((WifiSsid) null, friendlyNames, null, null, null, null);
     }
 
     @Before
@@ -1273,7 +1274,7 @@
     @Test
     public void testGetKey_matchesKeysCorrectly() {
         AccessPoint ap = new AccessPoint(mContext, mScanResults);
-        assertThat(ap.getKey()).isEqualTo(AccessPoint.getKey(mScanResults.get(0)));
+        assertThat(ap.getKey()).isEqualTo(AccessPoint.getKey(mContext, mScanResults.get(0)));
 
         WifiConfiguration spyConfig = spy(new WifiConfiguration());
         when(spyConfig.isPasspoint()).thenReturn(true);
@@ -1295,6 +1296,44 @@
     }
 
     /**
+     * Test that getKey returns a key of SAE type for a PSK/SAE transition mode ScanResult.
+     */
+    @Test
+    public void testGetKey_supportSaeTransitionMode_shouldGetSaeKey() {
+        ScanResult scanResult = createScanResult(TEST_SSID, TEST_BSSID, DEFAULT_RSSI);
+        scanResult.capabilities =
+                "[WPA2-FT/PSK-CCMP][RSN-FT/PSK+PSK-SHA256+SAE+FT/SAE-CCMP][ESS][WPS]";
+        when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(true);
+        when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
+        StringBuilder key = new StringBuilder();
+        key.append(AccessPoint.KEY_PREFIX_AP);
+        key.append(TEST_SSID);
+        key.append(',');
+        key.append(AccessPoint.SECURITY_SAE);
+
+        assertThat(AccessPoint.getKey(mMockContext, scanResult)).isEqualTo(key.toString());
+    }
+
+    /**
+     * Test that getKey returns a key of PSK type for a PSK/SAE transition mode ScanResult.
+     */
+    @Test
+    public void testGetKey_notSupportSaeTransitionMode_shouldGetPskKey() {
+        ScanResult scanResult = createScanResult(TEST_SSID, TEST_BSSID, DEFAULT_RSSI);
+        scanResult.capabilities =
+                "[WPA2-FT/PSK-CCMP][RSN-FT/PSK+PSK-SHA256+SAE+FT/SAE-CCMP][ESS][WPS]";
+        when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(false);
+        when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
+        StringBuilder key = new StringBuilder();
+        key.append(AccessPoint.KEY_PREFIX_AP);
+        key.append(TEST_SSID);
+        key.append(',');
+        key.append(AccessPoint.SECURITY_PSK);
+
+        assertThat(AccessPoint.getKey(mMockContext, scanResult)).isEqualTo(key.toString());
+    }
+
+    /**
      * Verifies that the Passpoint AccessPoint constructor creates AccessPoints whose isPasspoint()
      * returns true.
      */
@@ -1537,12 +1576,120 @@
             bundle.putInt("key_security", i);
             ap = new AccessPoint(InstrumentationRegistry.getTargetContext(), bundle);
 
-            if (i == AccessPoint.SECURITY_NONE || i == AccessPoint.SECURITY_OWE
-                    || i == AccessPoint.SECURITY_OWE_TRANSITION) {
+            if (i == AccessPoint.SECURITY_NONE || i == AccessPoint.SECURITY_OWE) {
                 assertThat(ap.isOpenNetwork()).isTrue();
             } else {
                 assertThat(ap.isOpenNetwork()).isFalse();
             }
         }
     }
+
+    /**
+     * Verifies that matches(AccessPoint other) matches a PSK/SAE transition mode AP to a PSK or a
+     * SAE AP.
+     */
+    @Test
+    public void testMatches1_transitionModeApMatchesNotTransitionModeAp_shouldMatchCorrectly() {
+        when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
+        when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(true);
+        AccessPoint pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
+
+        // Transition mode AP matches a SAE AP.
+        AccessPoint saeAccessPoint = new TestAccessPointBuilder(mContext)
+                .setSsid(AccessPoint.removeDoubleQuotes(TEST_SSID))
+                .setSecurity(AccessPoint.SECURITY_SAE)
+                .build();
+        assertThat(pskSaeTransitionModeAp.matches(saeAccessPoint)).isTrue();
+
+        // Transition mode AP matches a PSK AP.
+        AccessPoint pskAccessPoint = new TestAccessPointBuilder(mContext)
+                .setSsid(AccessPoint.removeDoubleQuotes(TEST_SSID))
+                .setSecurity(AccessPoint.SECURITY_PSK)
+                .build();
+
+        assertThat(pskSaeTransitionModeAp.matches(pskAccessPoint)).isTrue();
+
+        // Transition mode AP does not match a SAE AP if the device does not support SAE.
+        when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(false);
+        pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
+        saeAccessPoint = new TestAccessPointBuilder(mContext)
+            .setSsid(AccessPoint.removeDoubleQuotes(TEST_SSID))
+            .setSecurity(AccessPoint.SECURITY_SAE)
+            .build();
+
+        assertThat(pskSaeTransitionModeAp.matches(saeAccessPoint)).isFalse();
+    }
+
+    /**
+     * Verifies that matches(WifiConfiguration config) matches a PSK/SAE transition mode AP to a PSK
+     * or a SAE WifiConfiguration.
+     */
+    @Test
+    public void testMatches2_transitionModeApMatchesNotTransitionModeAp_shouldMatchCorrectly() {
+        when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
+        when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(true);
+        AccessPoint pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
+
+        // Transition mode AP matches a SAE WifiConfiguration.
+        WifiConfiguration saeConfig = new WifiConfiguration();
+        saeConfig.SSID = TEST_SSID;
+        saeConfig.allowedKeyManagement.set(KeyMgmt.SAE);
+
+        assertThat(pskSaeTransitionModeAp.matches(saeConfig)).isTrue();
+
+        // Transition mode AP matches a PSK WifiConfiguration.
+        WifiConfiguration pskConfig = new WifiConfiguration();
+        pskConfig.SSID = TEST_SSID;
+        pskConfig.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
+
+        assertThat(pskSaeTransitionModeAp.matches(pskConfig)).isTrue();
+
+        // Transition mode AP does not matches a SAE WifiConfiguration if the device does not
+        // support SAE.
+        when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(false);
+        pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
+
+        assertThat(pskSaeTransitionModeAp.matches(saeConfig)).isFalse();
+    }
+
+    /**
+     * Verifies that matches(ScanResult scanResult) matches a PSK/SAE transition mode AP to a PSK
+     * or a SAE ScanResult.
+     */
+    @Test
+    public void testMatches3_transitionModeApMatchesNotTransitionModeAp_shouldMatchCorrectly() {
+        when(mMockContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mMockWifiManager);
+        when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(true);
+        AccessPoint pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
+
+        // Transition mode AP matches a SAE ScanResult.
+        ScanResult saeScanResult = createScanResult(AccessPoint.removeDoubleQuotes(TEST_SSID),
+                TEST_BSSID, DEFAULT_RSSI);
+        saeScanResult.capabilities = "[SAE-CCMP][ESS][WPS]";
+
+        assertThat(pskSaeTransitionModeAp.matches(saeScanResult)).isTrue();
+
+        // Transition mode AP matches a PSK ScanResult.
+        ScanResult pskScanResult = createScanResult(AccessPoint.removeDoubleQuotes(TEST_SSID),
+                TEST_BSSID, DEFAULT_RSSI);
+        pskScanResult.capabilities = "[RSN-PSK-CCMP][ESS][WPS]";
+
+        assertThat(pskSaeTransitionModeAp.matches(pskScanResult)).isTrue();
+
+        // Transition mode AP does not matches a SAE ScanResult if the device does not support SAE.
+        when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(false);
+        pskSaeTransitionModeAp = getPskSaeTransitionModeAp();
+
+        assertThat(pskSaeTransitionModeAp.matches(saeScanResult)).isFalse();
+    }
+
+    private AccessPoint getPskSaeTransitionModeAp() {
+        ScanResult scanResult = createScanResult(AccessPoint.removeDoubleQuotes(TEST_SSID),
+                TEST_BSSID, DEFAULT_RSSI);
+        scanResult.capabilities =
+                "[WPA2-FT/PSK-CCMP][RSN-FT/PSK+PSK-SHA256+SAE+FT/SAE-CCMP][ESS][WPS]";
+        return new TestAccessPointBuilder(mMockContext)
+                .setScanResults(new ArrayList<ScanResult>(Arrays.asList(scanResult)))
+                .build();
+    }
 }
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 94fbc54..81cf118 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -336,7 +336,7 @@
     private static OsuProvider buildOsuProvider(String friendlyName) {
         Map<String, String> friendlyNames = new HashMap<>();
         friendlyNames.put("en", friendlyName);
-        return new OsuProvider((WifiSsid) null, friendlyNames, null, null, null, null, null);
+        return new OsuProvider((WifiSsid) null, friendlyNames, null, null, null, null);
     }
 
     private WifiTracker createTrackerWithImmediateBroadcastsAndInjectInitialScanResults(
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
index 5d5872e..fd5b053 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
@@ -132,7 +132,7 @@
         mShadowBluetoothAdapter.setSupportedProfiles(generateList(
                 new int[] {BluetoothProfile.HID_HOST}));
         mProfileManager.updateLocalProfiles();
-        ParcelUuid[] uuids = new ParcelUuid[]{BluetoothUuid.Hid};
+        ParcelUuid[] uuids = new ParcelUuid[]{BluetoothUuid.HID};
         ParcelUuid[] localUuids = new ParcelUuid[]{};
         List<LocalBluetoothProfile> profiles = new ArrayList<>();
         List<LocalBluetoothProfile> removedProfiles = new ArrayList<>();
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 05246a4..21b3ba3 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -39,7 +39,6 @@
     <bool name="def_bluetooth_on">true</bool>
     <bool name="def_wifi_display_on">false</bool>
     <bool name="def_install_non_market_apps">false</bool>
-    <bool name="def_package_verifier_enable">true</bool>
     <!-- 0 == off, 3 == on -->
     <integer name="def_location_mode">3</integer>
     <bool name="assisted_gps_enabled">true</bool>
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
index 1527de1..1f68742 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
@@ -70,5 +70,7 @@
         Settings.Global.CHARGING_VIBRATION_ENABLED,
         Settings.Global.AWARE_ALLOWED,
         Settings.Global.NOTIFICATION_BUBBLES,
+        Settings.Global.CUSTOM_BUGREPORT_HANDLER_APP,
+        Settings.Global.CUSTOM_BUGREPORT_HANDLER_USER,
     };
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 146f30d..3b929b9 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -126,6 +126,7 @@
         Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
         Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS,
         Settings.Secure.SHOW_NOTIFICATION_SNOOZE,
+        Settings.Secure.NOTIFICATION_HISTORY_ENABLED,
         Settings.Secure.ZEN_DURATION,
         Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION,
         Settings.Secure.SHOW_ZEN_SETTINGS_SUGGESTION,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/AccessibilityShortcutTargetListValidator.java b/packages/SettingsProvider/src/android/provider/settings/validators/AccessibilityShortcutTargetListValidator.java
new file mode 100644
index 0000000..5f3d7f1
--- /dev/null
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/AccessibilityShortcutTargetListValidator.java
@@ -0,0 +1,46 @@
+/*
+ * 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.provider.settings.validators;
+
+import static android.provider.settings.validators.SettingsValidators.COMPONENT_NAME_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.PACKAGE_NAME_VALIDATOR;
+
+import android.text.TextUtils;
+
+/**
+ * Ensure a restored value is a string in the format the accessibility shortcut system handles
+ *
+ * @hide
+ */
+public final class AccessibilityShortcutTargetListValidator extends ListValidator {
+    public AccessibilityShortcutTargetListValidator() {
+        super(":");
+    }
+
+    @Override
+    protected boolean isEntryValid(String entry) {
+        return !TextUtils.isEmpty(entry);
+    }
+
+    @Override
+    protected boolean isItemValid(String item) {
+        if (TextUtils.isEmpty(item)) {
+            return false;
+        }
+        return (COMPONENT_NAME_VALIDATOR.validate(item) || PACKAGE_NAME_VALIDATOR.validate(item));
+    }
+}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index 4a0ed6f..3d278db 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -149,5 +149,7 @@
         VALIDATORS.put(
                 Global.POWER_BUTTON_VERY_LONG_PRESS, new InclusiveIntegerRangeValidator(0, 1));
         VALIDATORS.put(Global.NOTIFICATION_BUBBLES, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.CUSTOM_BUGREPORT_HANDLER_APP, ANY_STRING_VALIDATOR);
+        VALIDATORS.put(Global.CUSTOM_BUGREPORT_HANDLER_USER, ANY_INTEGER_VALIDATOR);
     }
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/ListValidator.java b/packages/SettingsProvider/src/android/provider/settings/validators/ListValidator.java
index a6001d2..104fa11 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/ListValidator.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/ListValidator.java
@@ -35,7 +35,7 @@
         if (!isEntryValid(value)) {
             return false;
         }
-        String[] items = value.split(",");
+        String[] items = value.split(mListSplitRegex);
         for (String item : items) {
             if (!isItemValid(item)) {
                 return false;
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 0c3254a..090af98 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -16,6 +16,7 @@
 
 package android.provider.settings.validators;
 
+import static android.provider.settings.validators.SettingsValidators.ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.ANY_INTEGER_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.COLON_SEPARATED_COMPONENT_LIST_VALIDATOR;
@@ -71,10 +72,13 @@
         VALIDATORS.put(Secure.TOUCH_EXPLORATION_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.ACCESSIBILITY_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(
-                Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, NULLABLE_COMPONENT_NAME_VALIDATOR);
+                Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+                ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR);
         // technically either ComponentName or class name, but there's proper value
         // validation at callsites, so allow any non-null string
-        VALIDATORS.put(Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT, value -> value != null);
+        VALIDATORS.put(
+                Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT,
+                ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR);
         VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, BOOLEAN_VALIDATOR);
@@ -182,6 +186,7 @@
         VALIDATORS.put(Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.SHOW_NOTIFICATION_SNOOZE, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.NOTIFICATION_HISTORY_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.ZEN_DURATION, ANY_INTEGER_VALIDATOR);
         VALIDATORS.put(Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.SHOW_ZEN_SETTINGS_SUGGESTION, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
index 224042c..71c7544 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
@@ -204,4 +204,7 @@
             new InclusiveIntegerRangeValidator(0, 100);
 
     static final Validator VIBRATION_INTENSITY_VALIDATOR = new InclusiveIntegerRangeValidator(0, 3);
+
+    static final Validator ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR =
+            new AccessibilityShortcutTargetListValidator();
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 0c4db49..2027345 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -1191,19 +1191,7 @@
         }
 
         if (upgradeVersion == 81) {
-            // Add package verification setting
-            db.beginTransaction();
-            SQLiteStatement stmt = null;
-            try {
-                stmt = db.compileStatement("INSERT OR REPLACE INTO secure(name,value)"
-                        + " VALUES(?,?);");
-                loadBooleanSetting(stmt, Settings.Global.PACKAGE_VERIFIER_ENABLE,
-                        R.bool.def_package_verifier_enable);
-                db.setTransactionSuccessful();
-            } finally {
-                db.endTransaction();
-                if (stmt != null) stmt.close();
-            }
+            // package_verifier_enable has been removed
             upgradeVersion = 82;
         }
 
@@ -1305,7 +1293,6 @@
                 db.beginTransaction();
                 try {
                     String[] settingsToMove = {
-                            Settings.Global.PACKAGE_VERIFIER_ENABLE,
                             Settings.Global.PACKAGE_VERIFIER_TIMEOUT,
                             Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE
                     };
@@ -2470,9 +2457,6 @@
             loadDefaultAnimationSettings(stmt);
 
             // --- Previously in 'secure'
-            loadBooleanSetting(stmt, Settings.Global.PACKAGE_VERIFIER_ENABLE,
-                    R.bool.def_package_verifier_enable);
-
             loadBooleanSetting(stmt, Settings.Global.WIFI_ON,
                     R.bool.def_wifi_on);
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 33e0fd2..0a2dd38 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1162,9 +1162,6 @@
 
         final long pkgVerifierToken = p.start(GlobalSettingsProto.PACKAGE_VERIFIER);
         dumpSetting(s, p,
-                Settings.Global.PACKAGE_VERIFIER_ENABLE,
-                GlobalSettingsProto.PackageVerifier.ENABLED);
-        dumpSetting(s, p,
                 Settings.Global.PACKAGE_VERIFIER_TIMEOUT,
                 GlobalSettingsProto.PackageVerifier.TIMEOUT);
         dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 0959de9..93a1407 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -967,11 +967,6 @@
                     final long identity = Binder.clearCallingIdentity();
                     try {
                         synchronized (mLock) {
-                            Setting enable = getGlobalSetting(
-                                    Settings.Global.PACKAGE_VERIFIER_ENABLE);
-                            String enableValue = enable != null ? enable.getValue() : null;
-                            updateGlobalSetting(Settings.Global.PACKAGE_VERIFIER_ENABLE,
-                                    enableValue, null, true, userId, true);
                             Setting include = getGlobalSetting(
                                     Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB);
                             String includeValue = include != null ? include.getValue() : null;
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index eefba5d..c23a494 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -268,6 +268,7 @@
                     Settings.Global.ERROR_LOGCAT_PREFIX,
                     Settings.Global.EUICC_PROVISIONED,
                     Settings.Global.EUICC_SUPPORTED_COUNTRIES,
+                    Settings.Global.EUICC_UNSUPPORTED_COUNTRIES,
                     Settings.Global.EUICC_FACTORY_RESET_TIMEOUT_MILLIS,
                     Settings.Global.EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS,
                     Settings.Global.FANCY_IME_ANIMATIONS,
@@ -387,7 +388,6 @@
                     Settings.Global.OVERLAY_DISPLAY_DEVICES,
                     Settings.Global.PAC_CHANGE_DELAY,
                     Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE,
-                    Settings.Global.PACKAGE_VERIFIER_ENABLE,
                     Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB,
                     Settings.Global.PACKAGE_VERIFIER_SETTING_VISIBLE,
                     Settings.Global.PACKAGE_VERIFIER_TIMEOUT,
diff --git a/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java b/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java
index a3b0835..bb9e6f6 100644
--- a/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java
@@ -297,6 +297,18 @@
     }
 
     @Test
+    public void testAccessibilityShortcutTargetValidator() {
+        assertTrue(SettingsValidators.ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR.validate(
+                "com.google.android/.AccessibilityShortcutTarget"));
+        assertTrue(SettingsValidators.ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR.validate(
+                "com.google.android"));
+        assertTrue(SettingsValidators.ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR.validate(
+                "com.google.android/.AccessibilityShortcutTarget:com.google.android"));
+        assertFalse(SettingsValidators.ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR.validate(
+                "com.google.android/.AccessibilityShortcutTarget:com.google.@android"));
+    }
+
+    @Test
     public void ensureAllBackedUpGlobalSettingsHaveValidators() {
         String offenders = getOffenders(concat(GlobalSettings.SETTINGS_TO_BACKUP,
                 Settings.Global.LEGACY_RESTORE_SETTINGS), GlobalSettingsValidators.VALIDATORS);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 1a658f4..b89f141 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -215,9 +215,15 @@
     <!-- Permission required for CTS test - CrossProfileAppsHostSideTest -->
     <uses-permission android:name="android.permission.INTERACT_ACROSS_PROFILES"/>
 
-    <!-- Permission requried for CTS test - UiModeManagerTest -->
+    <!-- Permission required for CTS test - UiModeManagerTest -->
     <uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED"/>
 
+      <!-- Permission required for CTS test - CarModeInCallServiceTest -->
+    <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
+
+    <!-- Permission requried for CTS test - CellBroadcastIntentsTest -->
+    <uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS"/>
+
     <application android:label="@string/app_label"
                 android:theme="@android:style/Theme.DeviceDefault.DayNight"
                 android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 0c582c4..2a5bdc7 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -37,6 +37,7 @@
         "src/**/I*.aidl",
     ],
     resource_dirs: [
+        "res-product",
         "res-keyguard",
         "res",
     ],
@@ -91,6 +92,7 @@
     manifest: "tests/AndroidManifest.xml",
     resource_dirs: [
         "tests/res",
+        "res-product",
         "res-keyguard",
         "res",
     ],
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index e9c20db..6f68038 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -206,6 +206,9 @@
     <!-- shortcut manager -->
     <uses-permission android:name="android.permission.RESET_SHORTCUT_MANAGER_THROTTLING" />
 
+    <!-- launcher apps -->
+    <uses-permission android:name="android.permission.ACCESS_SHORTCUTS" />
+
     <uses-permission android:name="android.permission.MODIFY_THEME_OVERLAY" />
 
     <!-- accessibility -->
@@ -285,6 +288,11 @@
             android:exported="false"
             android:permission="com.android.systemui.permission.SELF" />
 
+        <service android:name=".assist.AssistHandleService"
+            android:exported="true"
+            android:enabled="false"
+        />
+
         <!-- started from PhoneWindowManager
              TODO: Should have an android:permission attribute -->
         <service android:name=".screenshot.TakeScreenshotService"
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 281406f..9f13a7b 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -9,10 +9,7 @@
             "include-filter": "android.platform.test.scenario.sysui"
         },
         {
-            "include-filter": "android.platform.test.scenario.quicksettings"
-        },
-        {
-            "include-filter": "android.platform.test.scenario.notification"
+            "include-annotation": "android.platform.test.scenario.annotation.Scenario"
         },
         {
             "exclude-annotation": "androidx.test.filters.FlakyTest"
diff --git a/packages/SystemUI/docs/executors.md b/packages/SystemUI/docs/executors.md
new file mode 100644
index 0000000..8520ce2
--- /dev/null
+++ b/packages/SystemUI/docs/executors.md
@@ -0,0 +1,321 @@
+# Executors
+
+go/sysui-executors
+
+[TOC]
+
+## TLDR
+
+In SystemUI, we are encouraging the use of Java's [Executor][Executor] over
+Android's [Handler][Handler] when shuffling a [Runnable][Runnable] between
+threads or delaying the execution of a Runnable. We have an implementation of
+Executor available, as well as our own sub-interface,
+[DelayableExecutor][DelayableExecutor] available. For test,
+[FakeExecutor][FakeExecutor] is available.
+
+[Executor]: https://developer.android.com/reference/java/util/concurrent/Executor.html
+[Handler]: https://developer.android.com/reference/android/os/Handler
+[Runnable]: https://developer.android.com/reference/java/lang/Runnable.html
+[DelayableExecutor]: /packages/SystemUI/src/com/android/systemui/util/concurrency/DelayableExecutor.java
+[FakeExecutor]: /packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutor.java
+
+## Rationale
+
+Executors make testing easier and are generally more flexible than Handlers.
+They are defined as an interface, making it easy to swap in fake implementations
+for testing. This also makes it easier to supply alternate implementations
+generally speaking - shared thread pools; priority queues; etc.
+
+For testing, whereas a handler involves trying to directly control its
+underlying Looper (using things like `Thread.sleep()` as well as overriding
+internal behaviors), an Executor implementation can be made to be directly
+controllable and inspectable.
+
+See also go/executors-for-the-android-engineer
+
+## Available Executors
+
+At present, there are two interfaces of Executor avaiable, each implemented, and
+each with two instances - `@Background` and `@Main`.
+
+### Executor
+
+The simplest Executor available implements the interface directly, making
+available one method: `Executor.execute()`. You can access an implementation of
+this Executor through Dependency Injection:
+
+```java
+   public class Foobar {
+       @Inject
+       public Foobar(@Background Executor bgExecutor) {
+           bgExecutor.execute(new Runnable() {
+             // ...
+           });
+       }
+   }
+```
+
+`@Main` will give you an Executor that runs on the ui thread. `@Background` will
+give you one that runs on a _shared_ non-ui thread. If you ask for an
+non-annotated Executor, you will get the `@Background` Executor.
+
+We do not currently have support for creating an Executor on a new, virgin
+thread. We do not currently support any sort of shared pooling of threads. If
+you require either of these, please reach out.
+
+### DelayableExecutor
+
+[DelayableExecutor][DelayableExecutor] is the closest analogue we provide to
+Handler. It adds `executeDelayed(Runnable r, long delayMillis)` and
+`executeAtTime(Runnable r, long uptimeMillis)` to the interface, just like
+Handler's [postDelayed][postDelayed] and [postAtTime][postAttime]. It also adds
+the option to supply a [TimeUnit][TimeUnit] as a third argument.
+
+A DelayableExecutor can be accessed via Injection just like a standard Executor.
+In fact, at this time, it shares the same underlying thread as our basic
+Executor.
+
+```java
+ public class Foobar {
+     @Inject
+     public Foobar(@Background DelayableExecutor bgExecutor) {
+         bgExecutor.executeDelayed(new Runnable() {
+           // ...
+         }, 1, TimeUnit.MINUTES);
+     }
+ }
+```
+
+Unlike Handler, the added methods return a Runnable that, when run, cancels the
+originally supplied Runnable if it has not yet started execution:
+
+```java
+ public class Foobar {
+     @Inject
+     public Foobar(@Background DelayableExecutor bgExecutor) {
+         Runnable cancel = bgExecutor.executeDelayed(new Runnable() {
+           // ...
+         }, 1, TimeUnit.MINUTES);
+
+         cancel.run();  // The supplied Runnable will (probably) not run.
+     }
+ }
+```
+
+[postDelayed]: https://developer.android.com/reference/android/os/Handler#postDelayed(java.lang.Runnable,%20long)
+[postAttime]: https://developer.android.com/reference/android/os/Handler#postAtTime(java.lang.Runnable,%20long)
+[TimeUnit]: https://developer.android.com/reference/java/util/concurrent/TimeUnit
+
+## Moving From Handler
+
+Most use cases of Handlers can easily be handled by the above two interfaces
+above. A minor refactor makes the switch:
+
+Handler       | Executor  | DelayableExecutor
+------------- | --------- | -----------------
+post()        | execute() | execute()
+postDelayed() | `none`    | executeDelayed()
+postAtTime()  | `none`    | executeAtTime()
+
+There is one notable gap in this implementation: `Handler.postAtFrontOfQueue()`.
+If you require this method, or similar, please reach out. The idea of a
+PriorityQueueExecutor has been floated, but will not be implemented until there
+is a clear need.
+
+Note also that "canceling" semantics are different. Instead of passing a `token`
+object to `Handler.postDelayed()`, you receive a Runnable that, when run,
+cancels the originally supplied Runnable.
+
+### Message Handling
+
+Executors have no concept of message handling. This is an oft used feature of
+Handlers. There are (as of 2019-12-05) 37 places where we subclass Handler to
+take advantage of this. However, by-and-large, these subclases take the
+following form:
+
+```Java
+mHandler = new Handler(looper) {
+    @Override
+    public void handleMessage(Message msg) {
+        switch (msg.what) {
+            case MSG_A:
+                handleMessageA();
+                break;
+            case MSG_B:
+                handleMessageB((String) msg.obj);
+                break;
+            case MSG_C:
+                handleMessageC((Foobar) msg.obj);
+                break;
+            // ...
+        }
+    }
+};
+
+// Elsewhere in the class
+void doSomething() {
+    mHandler.obtainMessage(MSG_B, "some string");
+    mHandler.sendMessage(msg);
+}
+```
+
+This could easily be replaced by equivalent, more direct Executor code:
+
+```Java
+void doSomething() {
+    mExecutor.execute(() -> handleMessageB("some string"));
+}
+```
+
+If you are posting Runnables frequently and you worry that the cost of creating
+anonymous Runnables is too high, consider creating pre-defined Runnables as
+fields in your class.
+
+If you feel that you have a use case that this does not cover, please reach out.
+
+### Handlers Are Still Necessary
+
+Handlers aren't going away. There are Android APIs that still require them (even
+if future API development discourages them). A simple example is
+[ContentObserver][ContentObserver]. Use them where necessary.
+
+[ContentObserver]: https://developer.android.com/reference/android/database/ContentObserver
+
+## Testing (FakeExecutor)
+
+We have a [FakeExecutor][FakeExecutor] available. It implements
+DelayableExecutor (which in turn is an Executor). It takes a FakeSystemClock in
+its constructor that allows you to control the flow of time, executing supplied
+Runnables in a deterministic manner.
+
+The implementation is well documented and tested. You are encouraged to read and
+reference it, but here is a quick overview:
+
+<table>
+    <tr>
+        <th>Method</th>
+        <th>Description</th>
+    </tr>
+    <tr>
+        <td>execute()</td>
+        <td>
+            Queues a Runnable so that it is "ready"
+            to run. (A Runnable is "ready" when its
+            scheduled time is less than or equal to
+            the clock.)
+        </td>
+    </tr>
+    <tr>
+        <td>postDelayed() & postAtTime()</td>
+        <td>
+            Queues a runnable to be run at some
+            point in the future.
+        </td>
+    </tr>
+    <tr>
+        <td>runNextReady()</td>
+        <td>
+            Run one runnable if it is ready to run
+            according to the supplied clock.
+        </td>
+    </tr>
+    <tr>
+        <td>runAllReady()</td>
+        <td>
+            Calls runNextReady() in a loop until
+            there are no more "ready" runnables.
+        </td>
+    </tr>
+    <tr>
+        <td>advanceClockToNext()</td>
+        <td>
+            Move the internal clock to the item at
+            the front of the queue, making it
+            "ready".
+        </td>
+    </tr>
+    <tr>
+        <td>advanceClockToLast()</td>
+        <td>
+            Makes all currently queued items ready.
+        </td>
+    </tr>
+    <tr>
+        <td>numPending()</td>
+        <td>
+            The number of runnables waiting to be run
+            They are not necessarily "ready".
+        </td>
+    </tr>
+    <tr>
+        <td>(static method) exhaustExecutors()</td>
+        <td>
+            Given a number of FakeExecutors, it
+            calls runAllReady() repeated on them
+            until none of them have ready work.
+            Useful if you have Executors that post
+            work to one another back and forth.
+        </td>
+    </tr>
+</table>
+
+_If you advance the supplied FakeSystemClock directly, the FakeExecutor will
+execute pending Runnables accordingly._ If you use the FakeExecutors
+`advanceClockToNext()` and `advanceClockToLast()`, this behavior will not be
+seen. You will need to tell the Executor to run its ready items. A quick example
+shows the difference:
+
+Here we advance the clock directly:
+
+```java
+FakeSystemClock clock = new FakeSystemClock();
+FakeExecutor executor = new FakeExecutor(clock);
+executor.execute(() -> {});             // Nothing run yet. Runs at time-0
+executor.executeDelayed(() -> {}, 100); // Nothing run yet. Runs at time-100.
+executor.executeDelayed(() -> {}, 500); // Nothing run yet. Runs at time-500.
+
+clock.synchronizeListeners(); // The clock just told the Executor it's time-0.
+                              // One thing run.
+clock.setUptimeMillis(500);   // The clock just told the Executor it's time-500.
+                              // Two more items run.
+```
+
+Here we have more fine-grained control:
+
+```java
+FakeSystemClock clock = new FakeSystemClock();
+FakeExecutor executor = new FakeExecutor(clock);
+executor.execute(() -> {});             // Nothing run yet. Runs at time-0
+executor.executeDelayed(() -> {}, 100); // Nothing run yet. Runs at time-100.
+executor.executeDelayed(() -> {}, 500); // Nothing run yet. Runs at time-500.
+
+executor.runNextReady();        // One thing run.
+executor.advanceClockToNext();  // One more thing ready to run.
+executor.runNextReady();        // One thing run.
+executor.runNextReady();        // Extra calls do nothing. (Returns false).
+executor.advanceClockToNext();  // One more thing ready to run.
+executor.runNextReady();        // Last item run.
+```
+
+One gotcha of direct-clock-advancement: If you have interleaved Runnables split
+between two executors like the following:
+
+```java
+FakeSystemClock clock = new FakeSystemClock();
+FakeExecutor executorA = new FakeExecutor(clock);
+FakeExecutor executorB = new FakeExecutor(clock);
+executorA.executeDelayed(() -> {}, 100);
+executorB.executeDelayed(() -> {}, 200);
+executorA.executeDelayed(() -> {}, 300);
+executorB.executeDelayed(() -> {}, 400);
+clock.setUptimeMillis(500);
+```
+
+The Runnables _will not_ interleave. All of one Executor's callbacks will run,
+then all of the other's.
+
+### TestableLooper.RunWithLooper
+
+As long as you're using FakeExecutors in all the code under test (and no
+Handlers or Loopers) you don't need it. Get rid of it. No more TestableLooper;
+no more Looper at all, for that matter.
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
index b21a9f7..6c4cbdf 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
@@ -34,7 +34,8 @@
     int getState();
 
     /**
-     * Is device dozing
+     * Is device dozing. Dozing is when the screen is in AOD or asleep given that
+     * {@link com.android.systemui.doze.DozeService} is configured.
      */
     boolean isDozing();
 
diff --git a/packages/SystemUI/res-keyguard/values-af/strings.xml b/packages/SystemUI/res-keyguard/values-af/strings.xml
index b285f11..b7f29a1 100644
--- a/packages/SystemUI/res-keyguard/values-af/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-af/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Druk Kieslys om te ontsluit."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Netwerk is gesluit"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Geen SIM-kaart nie"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Geen SIM-kaart in tablet nie."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Geen SIM-kaart in foon nie."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Steek \'n SIM-kaart in."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Die SIM-kaart is weg of nie leesbaar nie. Steek \'n SIM-kaart in."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Onbruikbare SIM-kaart."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Tik \'n PIN wat 4 to 8 syfers lank is, in."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-kode moet 8 of meer syfers wees."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Voer die korrekte PUK-kode weer in. Herhaalde pogings sal die SIM permanent deaktiveer."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-kodes stem nie ooreen nie"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Te veel patroonpogings"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Jy het jou PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd ingetik. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%2$d</xliff:g> sekondes."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Jy het jou wagwoord <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd ingetik. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%2$d</xliff:g> sekondes."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd geteken. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%2$d</xliff:g> sekondes."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Jy het die tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal hierdie tablet teruggestel word, wat al sy data sal uitvee."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Jy het die foon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal hierdie foon teruggestel word, wat al sy data sal uitvee."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Jy het die tablet <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Hierdie tablet sal teruggestel word, wat al sy data sal uitvee."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Jy het die foon <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Hierdie foon sal teruggestel word, wat al sy data sal uitvee."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Jy het die tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal hierdie gebruiker verwyder word, wat alle gebruikerdata sal uitvee."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Jy het die foon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal hierdie gebruiker verwyder word, wat alle gebruikerdata sal uitvee."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Jy het die tablet <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Die werkprofiel sal verwyder word, wat alle profieldata sal uitvee."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Jy het die foon <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Die werkprofiel sal verwyder word, wat alle profieldata sal uitvee."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd geteken. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal jy gevra word om jou e-posrekening te gebruik om jou tablet te ontsluit.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%3$d</xliff:g> sekondes."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd geteken. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal jy gevra word om jou e-posrekening te gebruik om jou foon te ontsluit.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%3$d</xliff:g> sekondes."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Verkeerde SIM-PIN-kode. Jy sal nou jou diensverskaffer moet kontak om jou toestel te ontsluit."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">Verkeerde SIM-PIN-kode. Jy het <xliff:g id="NUMBER_1">%d</xliff:g> pogings oor.</item>
diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml
index 855db55..c94ba8b 100644
--- a/packages/SystemUI/res-keyguard/values-am/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-am/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"ለመክፈት ምናሌ ተጫን።"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"አውታረ መረብ ተቆልፏል"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"ምንም ሲም ካርድ የለም"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"በጡባዊ ውስጥ ምንም ሲም ካርድ የለም።"</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"በስልክ ውስጥ ምንም ሲም ካርድ የለም።"</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"ሲም ካርድ ያስገቡ።"</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"ሲም ካርዱ ጠፍቷል ወይም መነበብ አይችልም። እባክዎ ሲም ካርድ ያስገቡ።"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"የማይሰራ ሲም ካርድ።"</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"ከ4 እስከ 8 ቁጥሮች የያዘ ፒን ይተይቡ።"</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"የPUK ኮድ 8 ወይም ከዚያ በላይ ቁጥሮች ሊኖረው ይገባል።"</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"ትክክለኛውን የPUK ኮድ እንደገና ያስገቡ። ተደጋጋሚ ሙከራዎች ሲሙን እስከመጨረሻው ያሰናክሉታል።"</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ፒን ኮዶቹ አይገጣጠሙም"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"በጣም ብዙ የስርዓተ ጥለት ሙከራዎች"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"ፒንዎን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ በትክክል አልተየቡም። \n\nበ<xliff:g id="NUMBER_1">%2$d</xliff:g> ሰኮንዶች ውስጥ እንደገና ይሞክሩ።"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"የይለፍ ቃልዎን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ ትክክል ባልሆነ መንገድ ተይበዋል።\n\nበ<xliff:g id="NUMBER_1">%2$d</xliff:g> ሰኮንዶች ውስጥ እንደገና ይሞክሩ።"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ ትክክል ባልሆነ መንገድ ስለውታል።\n\nበ<xliff:g id="NUMBER_1">%2$d</xliff:g> ሰኮንዶች ውስጥ እንደገና ይሞክሩ።"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ጡባዊውን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ጡባዊ ዳግም ይጀመራል፣ ይህም ሁሉንም ውሂብ ይሰርዛል።"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ስልኩን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ስልክ ዳግም ይጀመራል፣ ይህም ሁሉንም ውሂብ ይሰርዛል።"</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ጡባዊውን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ ሁኔታ ለማስከፈት ሞክረዋል። ስልኩ ዳግም ይጀመራል፣ ይህም ሁሉንም ውሂቡን ይሰርዛል።"</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ስልኩን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ ሁኔታ ለማስከፈት ሞክረዋል። ስልኩ ዳግም ይጀመራል፣ ይህም ሁሉንም ውሂቡን ይሰርዛል።"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ጡባዊውን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ተጠቃሚ ይወገዳል፣ ይህም ሁሉንም የተጠቃሚ ውሂብ ይሰርዛል።"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ስልኩን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ተጠቃሚ ይወገዳል፣ ይህም ሁሉንም የተጠቃሚ ውሂብ ይሰርዛል።"</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ጡባዊውን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለመክፈት ሞክረዋል። የስራ መገለጫው ይወገዳል፣ ይህም ሁሉንም የመገለጫ ውሂብ ይሰርዛል።"</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ስልኩን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለመክፈት ሞክረዋል። የስራ መገለጫው ይወገዳል፣ ይህም ሁሉንም የመገለጫ ውሂብ ይሰርዛል።"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ጡባዊዎን እንዲከፍቱ ይጠየቃሉ።\n\n ከ<xliff:g id="NUMBER_2">%3$d</xliff:g> ከሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ስልክዎን እንዲከፍቱ ይጠየቃሉ።\n\nእባክዎ ከ<xliff:g id="NUMBER_2">%3$d</xliff:g> ሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"ልክ ያልሆነ የሲም ፒን ኮድ። አሁን መሣሪያዎን ለማስከፈት አገልግሎት አቅራቢዎን ማነጋገር አለብዎት።"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">ልክ ያልሆነ የሲም ፒን ኮድ፣ <xliff:g id="NUMBER_1">%d</xliff:g> ሙከራዎች ይቀረዎታል።</item>
diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml
index 668957a..fe10afa 100644
--- a/packages/SystemUI/res-keyguard/values-ar/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"اضغط على \"القائمة\" لإلغاء التأمين."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"الشبكة مؤمّنة"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"‏ليست هناك شريحة SIM"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"‏ليست هناك شريحة SIM في الجهاز اللوحي."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"‏ليست هناك شريحة SIM في الهاتف."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"‏أدخل شريحة SIM."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"‏شريحة SIM مفقودة أو غير قابلة للقراءة. أدخل شريحة SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"‏شريحة SIM غير قابلة للاستخدام."</string>
@@ -87,17 +85,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"اكتب رمز رقم التعريف الشخصي المكوّن من ٤ إلى ٨ أرقام."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"‏يجب أن يتضمن رمز PUK‏ ۸ أرقام أو أكثر."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"‏أعد إدخال رمز PUK الصحيح. وستؤدي المحاولات المتكررة إلى إيقاف شريحة SIM نهائيًا."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"لا يتطابق رمز رقم التعريف الشخصي"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"محاولات النقش كثيرة جدًا"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"لقد كتبت رقم التعريف الشخصي بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. \n\nأعد المحاولة خلال <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانية."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"لقد كتبت كلمة المرور بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. \n\nأعد المحاولة خلال <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانية."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"لقد رسمت نقش فتح القفل بطريقة غير صحيحة <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. \n\nأعد المحاولة خلال <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانية."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة غير ناجحة أخرى، ستتم إعادة تعيين هذا الجهاز، ومن ثم يتم حذف جميع بياناته."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة غير ناجحة أخرى، ستتم إعادة تعيين هذا الهاتف، ومن ثم يتم حذف جميع بياناته."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <xliff:g id="NUMBER">%d</xliff:g> مرة. ستتم إعادة تعيين هذا الجهاز، ومن ثم يتم حذف جميع بياناته."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER">%d</xliff:g> مرة. ستتم إعادة تعيين هذا الهاتف، ومن ثم يتم حذف جميع بياناته."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة غير ناجحة أخرى، ستتم إزالة هذا المستخدم، ومن ثم يتم حذف جميع بيانات المستخدم."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة غير ناجحة أخرى، ستتم إزالة هذا المستخدم، ومن ثم يتم حذف جميع بيانات المستخدم."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -106,10 +97,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <xliff:g id="NUMBER">%d</xliff:g> مرة. ستتم إزالة الملف الشخصي للعمل، ومن ثم يتم حذف جميع بياناته."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER">%d</xliff:g> مرة. ستتم إزالة الملف الشخصي للعمل، ومن ثم يتم حذف جميع بياناته."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"لقد رسمت نقش فتح القفل بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة الأخرى، ستطالَب بإلغاء تأمين الجهاز اللوحي باستخدام معلومات حساب بريد إلكتروني.\n\n أعد المحاولة خلال <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"لقد رسمت نقش فتح القفل بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة الأخرى، ستُطالب بإلغاء تأمين الهاتف باستخدام حساب بريد إلكتروني لإلغاء تأمين الهاتف.\n\n أعد المحاولة خلال <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"‏رمز \"رقم التعريف الشخصي\" لشريحة SIM غير صحيح، ويلزمك الاتصال الآن بمشغّل شبكة الجوّال لإلغاء قفل الجهاز."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="zero">‏رمز رقم التعريف الشخصي لشريحة SIM غير صحيح، ولم تتبق لديك أي محاولات (<xliff:g id="NUMBER_1">%d</xliff:g>).</item>
diff --git a/packages/SystemUI/res-keyguard/values-as/strings.xml b/packages/SystemUI/res-keyguard/values-as/strings.xml
index 3fef9d7..f814c3a 100644
--- a/packages/SystemUI/res-keyguard/values-as/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-as/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"আনলক কৰিবলৈ মেনু টিপক।"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"নেটৱর্ক লক কৰা অৱস্থাত আছে"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"কোনো ছিম কাৰ্ড নাই"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"টেবলেটত ছিম কার্ড নাই।"</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ফ\'নত ছিম কার্ড নাই।"</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"এখন ছিম কাৰ্ড ভৰাওক।"</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"ছিম কাৰ্ডখন নাই বা চিনাক্ত কৰিব নোৱাৰি। এখন ছিম কাৰ্ড ভৰাওক।"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"ব্যৱহাৰৰ অযোগ্য ছিম কাৰ্ড।"</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"৪টাৰ পৰা ৮টা সংখ্যাযুক্ত এটা পিন লিখক।"</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK ক\'ডটো ৮টা বা তাতকৈ অধিক সংখ্যা থকা হ\'ব লাগিব।"</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"শুদ্ধ PUK ক\'ডটো পুনৰ দিয়ক। বাৰে বাৰে ভুল ক\'ড দিলে ছিমখন স্থায়ীভাৱে অক্ষম হ\'ব।"</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"পিন ক\'ড মিলা নাই"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"বহুতবাৰ ভুলকৈ আর্হি অঁকা হৈছে"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"আপুনি আপোনাৰ পিন <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ লিখিছে। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g>ছেকেণ্ডৰ পিছত আকৌ চেষ্টা কৰক।"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"আপুনি আপোনাৰ পাছৱৰ্ড <xliff:g id="NUMBER_0">%1$d</xliff:g>বাৰ ভুলকৈ লিখিছে। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ছেকেণ্ডৰ পাছত আকৌ চেষ্টা কৰক।"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"আপুনি আপোনাৰ আনলক আৰ্হি <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আঁকিছে। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g>ছেকেণ্ডৰ পিছত আকৌ চেষ্টা কৰক।"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"আপুনি টেবলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে টেবলেটটো ৰিছেট কৰা হ\'ব, যি কার্যই টেবলেটটোত থকা সকলো ডেটা মচিব।"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"আপুনি ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে ফ\'নটো ৰিছেট কৰা হ\'ব, যি কার্যই ফ\'নটোত থকা সকলো ডেটা মচিব।"</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"আপুনি টেবলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। এই টেবলেটটো ৰিছেট কৰা হ\'ব, যি কার্যই ইয়াৰ সকলো ডেটা মচিব।"</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"আপুনি ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। এই ফ\'নটো ৰিছেট কৰা হ\'ব, যিয়ে ইয়াৰ সকলো ডেটা মচিব।"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"আপুনি টেবলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে এই ব্যৱহাৰকাৰীক আঁতৰোৱা হ\'ব, যিয়ে ব্যৱহাৰকাৰীৰ সকলো ডেটা মচিব।"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"আপুনি ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে এই ব্যৱহাৰকাৰীক আঁতৰোৱা হ\'ব, যিয়ে ব্যৱহাৰকাৰীৰ সকলো ডেটা মচিব।"</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"আপুনি টেবলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইলটো আঁতৰোৱা হ\'ব, যি কার্যই প্ৰ\'ফাইলটোৰ সকলো ডেটা মচিব।"</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"আপুনি ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইলটো আঁতৰোৱা হ\'ব, যিয়ে প্ৰ\'ফাইলটোৰ সকলো ডেটা মচিব।"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"আপুনি আপোনাৰ আনলক আৰ্হিটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আঁকিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g>তকৈ বেছি বাৰ ভুল আৰ্হি আঁকিলে আপোনাৰ টেবলেটটো কোনো একাউণ্টৰ জৰিয়তে আনলক কৰিবলৈ কোৱা হ\'ব।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> ছেকেণ্ডৰ পিছত আকৌ চেষ্টা কৰক।"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"আপুনি আপোনাৰ আনলক আৰ্হিটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আঁকিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g>তকৈ বেছি বাৰ ভুল আৰ্হি আঁকিলে আপোনাৰ ফ\'নটো কোনো একাউণ্টৰ জৰিয়তে আনলক কৰিবলৈ কোৱা হ\'ব।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> ছেকেণ্ডৰ পিছত আকৌ চেষ্টা কৰক।"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"ছিমৰ ভুল পিন ক\'ড, আপোনাৰ ডিভাইচটো আনলক কৰিবলৈ আপুনি এতিয়া আপোনাৰ বাহকৰ সৈতে যোগাযোগ কৰিবই লাগিব।"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">ছিমৰ ভুল পিন ক’ড, আপুনি আৰু <xliff:g id="NUMBER_1">%d</xliff:g> বাৰ প্ৰয়াস কৰিব পাৰিব।</item>
diff --git a/packages/SystemUI/res-keyguard/values-az/strings.xml b/packages/SystemUI/res-keyguard/values-az/strings.xml
index 8bc953e..e04f305 100644
--- a/packages/SystemUI/res-keyguard/values-az/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-az/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Kilidi açmaq üçün Menyu düyməsinə basın."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Şəbəkə kilidlidir"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM kart yoxdur."</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Planşetdə SIM kart yoxdur."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefonda SIM kart yoxdur."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM kart daxil edin."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM kart yoxdur və ya oxuna bilinmir. SIM kart daxil edin."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Yararsız SIM kart."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4-8 rəqəmli PIN daxil edin."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK kod 8 rəqəm və ya daha çox olmalıdır."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Yenidən düzgün PUK kod daxil edin. Təkrarlanan cəhdlər SIM-i birdəfəlik sıradan çıxaracaq."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodlar uyğun gəlmir"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Həddindən çox model cəhdi"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"PIN kodu <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış daxil etdiniz. \n \n<xliff:g id="NUMBER_1">%2$d</xliff:g> saniyə sonra yenidən cəhd edin."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Parolu <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış daxil etdiniz. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> saniyə sonra yenidən cəhd edin."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Kilid modelini <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkdiniz. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> saniyə sonra yenidən cəhd edin."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Planşetin kilidini açmaq üçün <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış cəhdlər etmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bu planşet sıfırlanacaq və bütün data silinəcək."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış cəhdlər etmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bu telefon sıfırlanacaq və bütün data silinəcək."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Planşetin kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhdlər etmisiniz. Bu planşet sıfırlanacaq və bütün data silinəcək."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhdlər etmisiniz. Bu telefon sıfırlanacaq və bütün data silinəcək."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Planşetin kilidini açmaq üçün <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bu istifadəçi silinəcək və bütün istifadəçi datası ləğv ediləcək."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bu istifadəçi silinəcək və bütün istifadəçi datası ləğv ediləcək."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Planşetin kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhdlər etmisiniz. İş profili silinəcək və bütün data ləğv ediləcək."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhdlər etmisiniz. İş profili silinəcək və bütün data ləğv ediləcək."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Kilid açma modelini <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra planşet kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra yenidən cəhd edin."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Kilid açma modelini artıq <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra telefon kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra yenidən cəhd edin."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Yanlış SIM PIN kodu  cihazın açılması üçün operatorla indi əlaqə saxlamalısınız."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">Yanlış SIM PIN kodu, <xliff:g id="NUMBER_1">%d</xliff:g> cəhdiniz qalır.</item>
diff --git a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
index 116e096..82dca6b 100644
--- a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Pritisnite Meni da biste otključali."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Mreža je zaključana"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Nema SIM kartice"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"U tabletu nema SIM kartice."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"U telefonu nema SIM kartice."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Umetnite SIM karticu."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM kartica nedostaje ili ne može da se pročita. Umetnite SIM karticu."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM kartica je neupotrebljiva."</string>
@@ -84,17 +82,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Unesite PIN koji ima 4–8 brojeva."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK kôd treba da ima 8 ili više brojeva."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Ponovo unesite tačan PUK kôd. Ponovljeni pokušaji će trajno onemogućiti SIM."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodovi se ne podudaraju"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Previše pokušaja unosa šablona"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Uneli ste pogrešan PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sek."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Uneli ste pogrešnu lozinku <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sek."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Nacrtali ste netačan šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sek."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, ovaj tablet će se resetovati, čime se brišu svi podaci korisnika."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, ovaj telefon će se resetovati, čime se brišu svi podaci korisnika."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER">%d</xliff:g> puta. Ovaj tablet će se resetovati, čime se brišu svi podaci."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Ovaj telefon će se resetovati, čime se brišu svi podaci."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, uklonićemo ovog korisnika, čime se brišu svi podaci korisnika."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, uklonićemo ovog korisnika, čime se brišu svi podaci korisnika."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -103,10 +94,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER">%d</xliff:g> puta. Uklonićemo profil za Work, čime se brišu svi podaci sa profila."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Uklonićemo profil za Work, čime se brišu svi podaci sa profila."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Netačno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, zatražićemo da otključate tablet pomoću imejl naloga.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Netačno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, zatražićemo da otključate telefon pomoću imejl naloga.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Netačan PIN kôd za SIM. Sada morate da kontaktirate mobilnog operatera da biste otključali uređaj."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">Netačan PIN kôd za SIM. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj.</item>
diff --git a/packages/SystemUI/res-keyguard/values-be/strings.xml b/packages/SystemUI/res-keyguard/values-be/strings.xml
index 5bb89ae..d9a4508 100644
--- a/packages/SystemUI/res-keyguard/values-be/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-be/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Націсніце кнопку \"Меню\", каб разблакіраваць."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Сетка заблакіравана"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Няма SIM-карты"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"У планшэце няма SIM-карты."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"У тэлефоне няма SIM-карты."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Устаўце SIM-карту."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM-карта адсутнічае ці не чытаецца. Устаўце SIM-карту."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM-карту немагчыма выкарыстоўваць."</string>
@@ -85,17 +83,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Увядзіце PIN-код, які змяшчае ад 4 да 8 лічбаў."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-код павінен утрымліваць 8 лічбаў ці больш."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Паўторна ўвядзіце правільны PUK-код. Паўторныя спробы прывядуць да адключэння SIM-карты назаўсёды."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-коды не супадаюць"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Занадта шмат спроб уводу ўзору"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Вы няправільна ўвялі PIN-код столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nПаўтарыце спробу праз <xliff:g id="NUMBER_1">%2$d</xliff:g> с."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Вы няправільна ўвялі пароль столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nПаўтарыце спробу праз <xliff:g id="NUMBER_1">%2$d</xliff:g> с."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Вы няправільна ўвялі ўзор разблакіроўкі столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nПаўтарыце спробу праз <xliff:g id="NUMBER_1">%2$d</xliff:g> с."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Вы не змаглі разблакіраваць планшэт столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) ён будзе скінуты да заводскіх налад, гэта прывядзе да выдалення ўсіх даных."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) ён будзе скінуты да заводскіх налад, гэта прывядзе да выдалення ўсіх даных."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Вы не змаглі разблакіраваць планшэт столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Цяпер ён будзе скінуты да заводскіх налад, гэта прывядзе да выдалення ўсіх даных."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Цяпер ён будзе скінуты да заводскіх налад, гэта прывядзе да выдалення ўсіх даных."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Вы не змаглі разблакіраваць планшэт столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) гэты карыстальнік будзе выдалены, гэта прывядзе да выдалення ўсіх карыстальніцкіх даных."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) гэты карыстальнік будзе выдалены, гэта прывядзе да выдалення ўсіх карыстальніцкіх даных."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -104,10 +95,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Вы не змаглі разблакіраваць планшэт столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Працоўны профіль будзе выдалены, гэта прывядзе да выдалення ўсіх даных у профілі."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Працоўны профіль будзе выдалены, гэта прывядзе да выдалення ўсіх даных у профілі."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Вы няправільна ўвялі ўзор разблакіроўкі столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакіраваць планшэт, увайшоўшы ва ўліковы запіс электроннай пошты.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Вы няправільна ўвялі ўзор разблакіроўкі столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакіраваць тэлефон, увайшоўшы ва ўліковы запіс электроннай пошты.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Няправільны PIN-код SIM-карты, цяпер вы павінны звязацца з аператарам для разблакіроўкі прылады."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">Няправільны PIN-код SIM-карты, у вас засталася <xliff:g id="NUMBER_1">%d</xliff:g> спроба.</item>
diff --git a/packages/SystemUI/res-keyguard/values-bg/strings.xml b/packages/SystemUI/res-keyguard/values-bg/strings.xml
index 2b37c52..3b68a42 100644
--- a/packages/SystemUI/res-keyguard/values-bg/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bg/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Натиснете „Меню“, за да отключите."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Мрежата е заключена"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Няма SIM карта"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"В таблета няма SIM карта."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"В телефона няма SIM карта."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Поставете SIM карта."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM картата липсва или е нечетлива. Поставете SIM карта."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Неизползваема SIM карта."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Въведете ПИН код с четири до осем цифри."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK кодът трябва да е с осем или повече цифри."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Въведете отново правилния PUK код. Многократните опити ще деактивират за постоянно SIM картата."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ПИН кодовете не съвпадат"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Опитите за фигурата са твърде много"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Въведохте неправилно ПИН кода си <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. \n\nОпитайте отново след <xliff:g id="NUMBER_1">%2$d</xliff:g> секунди."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Въведохте неправилно паролата си <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. \n\nОпитайте отново след <xliff:g id="NUMBER_1">%2$d</xliff:g> секунди."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. \n\nОпитайте отново след <xliff:g id="NUMBER_1">%2$d</xliff:g> секунди."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Опитахте да отключите таблета и сбъркахте <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита той ще бъде нулиран, при което ще се изтрият всичките му данни."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Опитахте да отключите телефона и сбъркахте <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита той ще бъде нулиран, при което ще се изтрият всичките му данни."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Опитахте да отключите таблета и сбъркахте <xliff:g id="NUMBER">%d</xliff:g> пъти. Той ще бъде нулиран, при което ще се изтрият всичките му данни."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Опитахте да отключите телефона и сбъркахте <xliff:g id="NUMBER">%d</xliff:g> пъти. Той ще бъде нулиран, при което ще се изтрият всичките му данни."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Опитахте да отключите таблета и сбъркахте <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита този потребител ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Опитахте да отключите телефона и сбъркахте <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита този потребител ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Опитахте да отключите таблета и сбъркахте <xliff:g id="NUMBER">%d</xliff:g> пъти. Служебният потребителски профил ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Опитахте да отключите телефона и сбъркахте <xliff:g id="NUMBER">%d</xliff:g> пъти. Служебният потребителски профил ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита ще бъдете помолени да отключите таблета си посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита ще бъдете помолени да отключите телефона посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Неправилен ПИН код за SIM картата – сега трябва да се свържете с оператора си, за да отключите устройството."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">Неправилен ПИН код за SIM картата – остават ви <xliff:g id="NUMBER_1">%d</xliff:g> опита.</item>
diff --git a/packages/SystemUI/res-keyguard/values-bn/strings.xml b/packages/SystemUI/res-keyguard/values-bn/strings.xml
index 26881d8..7d0d4b9 100644
--- a/packages/SystemUI/res-keyguard/values-bn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bn/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"আনলক করতে মেনুতে টিপুন।"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"নেটওয়ার্ক লক করা আছে"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"কোনো সিম কার্ড নেই"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ট্যাবলেটের মধ্যে কোনো সিম কার্ড নেই।"</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ফোনের মধ্যে কোনো সিম কার্ড নেই।"</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"একটি সিম কার্ড লাগান।"</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"সিম কার্ড নেই বা সেটি পড়া যাচ্ছে না। একটি সিম কার্ড লাগান।"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"অব্যবহারযোগ্য সিম কার্ড।"</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"একটি ৪ থেকে ৮ সংখ্যার পিন লিখুন।"</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK কোডটি ৮ বা তার বেশি সংখ্যার হতে হবে।"</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"সঠিক PUK কোডটি পুনরায় লিখুন। বার বার চেষ্টা করা হলে সিমটি স্থায়ীভাবে অক্ষম হয়ে যাবে।"</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"পিন কোডগুলি মিলছে না"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"বিভিন্ন প্যাটার্নের সাহায্যে খুব বেশি বার প্রচেষ্টা করা হয়ে গেছে"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"আপনি আপনার পিন টাইপ করতে <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুল করেছেন৷ \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে আপনার পাসওয়ার্ড লিখেছেন।\n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন।"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে আপনার আনলকের প্যাটার্ন এঁকেছেন।\n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন।"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে ট্যাবলেটটি আনলক করার চেষ্টা করেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর এই ট্যাবলেটটিকে রিসেট করা হবে, যার ফলে এর সমস্ত ডেটা মুছে যাবে।"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে ফোনটি আনলক করার চেষ্টা করেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর এই ফোনটিকে রিসেট করা হবে, যার ফলে এর সমস্ত ডেটা মুছে যাবে।"</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুলভাবে ট্যাবলেটটি আনলক করার চেষ্টা করেছেন। এই ফোনটিকে রিসেট করা হবে, যার ফলে এর সমস্ত ডেটা মুছে যাবে।"</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুলভাবে ফোনটি আনলক করার চেষ্টা করেছেন। এই ফোনটিকে রিসেট করা হবে, যার ফলে এর সমস্ত ডেটা মুছে যাবে।"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে ট্যাবলেটটি আনলক করার চেষ্টা করেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর এই ব্যবহারকারীকে সরিয়ে দেওয়া হবে, যার ফলে ব্যবহারকারীর সমস্ত ডেটা মুছে যাবে।"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে ফোনটি আনলক করার চেষ্টা করেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর এই ব্যবহারকারীকে সরিয়ে দেওয়া হবে, যার ফলে ব্যবহারকারীর সমস্ত ডেটা মুছে যাবে।"</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুলভাবে ট্যাবলেটটি আনলক করার চেষ্টা করেছেন। কাজের প্রোফাইলটি সরিয়ে দেওয়া হবে, যার ফলে প্রোফাইলের সমস্ত ডেটা মুছে যাবে।"</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুলভাবে ফোনটি আনলক করার চেষ্টা করেছেন। কাজের প্রোফাইলটি সরিয়ে দেওয়া হবে, যার ফলে প্রোফাইলের সমস্ত ডেটা মুছে যাবে।"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে আনলকের প্যাটার্ন এঁকেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর আপনাকে একটি ইমেল অ্যাকাউন্টের মাধ্যমে আপনার ট্যাবলেটটি আনলক করতে বলা হবে।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন।"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে আনলকের প্যাটার্ন এঁকেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর আপনাকে একটি ইমেল অ্যাকাউন্টের মাধ্যমে আপনার ফোনটি আনলক করতে বলা হবে।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন।"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"ভুল সিম পিন কোড দিয়েছেন, আপনার ডিভাইসটি আনলক করতে এখন আপনাকে অবশ্যই আপনার পরিষেবা প্রদানকারীর সাথে যোগাযোগ করতে হবে।"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">সিমের পিন কোডটি ভুল, আপনি আর <xliff:g id="NUMBER_1">%d</xliff:g> বার চেষ্টা করতে পারেন।</item>
diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml
index 9e36a72..99140ce 100644
--- a/packages/SystemUI/res-keyguard/values-bs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Pritisnite meni da otključate."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Mreža je zaključana"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Nema SIM kartice"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nema SIM kartice u tabletu."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Nema SIM kartice u telefonu."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Umetnite SIM karticu."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM kartica nije umetnuta ili je uređaj ne može očitati. Umetnite SIM karticu."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Neupotrebljiva SIM kartica."</string>
@@ -84,17 +82,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Unesite PIN koji sadrži 4 do 8 brojeva."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK kôd treba sadržavati najmanje 8 brojeva."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Ponovo unesite ispravan PUK kôd. Ponovljeni pokušaji će trajno onemogućiti SIM karticu."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-ovi se ne poklapaju"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Previše puta ste pokušali otključati uređaj crtanjem uzorka"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Pogrešno ste unijeli PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Pogrešno ste unijeli lozinku <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Pogrešno ste nacrtali svoj uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati tablet. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, tablet će se vratiti na fabričke postavke i svi podaci će se izbrisati."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati telefon. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, telefon će se vratiti na fabričke postavke i svi podaci će se izbrisati."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati tablet. Tablet će se sada vratiti na fabričke postavke i svi podaci će se izbrisati."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati telefon. Telefon će se sada vratiti na fabričke postavke i svi podaci će se izbrisati."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati tablet. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, ovaj korisnik će se ukloniti i svi podaci korisnika će se izbrisati."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati telefon. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, ovaj korisnik će se ukloniti i svi podaci korisnika će se izbrisati."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -103,10 +94,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati tablet. Poslovni profil će se ukloniti i svi podaci s profila će se izbrisati."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati telefon. Poslovni profil će se ukloniti i svi podaci s profila će se izbrisati."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da tablet otključate koristeći račun e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da telefon otključate koristeći račun e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"PIN za SIM karticu je netačan. Za otključavanje uređaja sada se morate obratiti svom operateru."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">PIN za SIM karticu je netačan. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj.</item>
diff --git a/packages/SystemUI/res-keyguard/values-ca/strings.xml b/packages/SystemUI/res-keyguard/values-ca/strings.xml
index 8059ec3..7bb3677 100644
--- a/packages/SystemUI/res-keyguard/values-ca/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ca/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Prem Menú per desbloquejar."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"La xarxa està bloquejada"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"No hi ha cap SIM"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No hi ha cap SIM a la tauleta."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No hi ha cap SIM al telèfon."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Insereix una targeta SIM."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Falta la targeta SIM o no es pot llegir. Insereix-ne una."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"La targeta SIM no es pot fer servir."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Escriu un PIN que tingui entre 4 i 8 números."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"El codi PUK ha de tenir 8 números o més."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Torna a introduir el codi PUK correcte. Si ho intentes diverses vegades, es desactivarà la SIM permanentment."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Els codis PIN no coincideixen"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Has intentat dibuixar el patró massa vegades"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Has escrit el PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%2$d</xliff:g> segons."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Has escrit la contrasenya <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%2$d</xliff:g> segons."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%2$d</xliff:g> segons."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, la tauleta es restablirà i se\'n suprimiran totes les dades."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, el telèfon es restablirà i se\'n suprimiran totes les dades."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. La tauleta es restablirà i se\'n suprimiran totes les dades."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. El telèfon es restablirà i se\'n suprimiran totes les dades."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, l\'usuari se suprimirà, juntament amb totes les seves dades."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, l\'usuari se suprimirà, juntament amb totes les seves dades."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. El perfil professional se suprimirà, juntament amb totes les dades que contingui."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. El perfil professional se suprimirà, juntament amb totes les dades que contingui."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, se\'t demanarà que desbloquegis la tauleta amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%3$d</xliff:g> segons."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, se\'t demanarà que desbloquegis el telèfon amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%3$d</xliff:g> segons."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"El codi PIN de la SIM no és correcte. Contacta amb l\'operador de telefonia mòbil per desbloquejar el dispositiu."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">El codi PIN de la SIM no és correcte. Et queden <xliff:g id="NUMBER_1">%d</xliff:g> intents.</item>
diff --git a/packages/SystemUI/res-keyguard/values-cs/strings.xml b/packages/SystemUI/res-keyguard/values-cs/strings.xml
index b8bfe07..7e430d6 100644
--- a/packages/SystemUI/res-keyguard/values-cs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-cs/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Klávesy odemknete stisknutím tlačítka nabídky."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Síť je blokována"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Chybí SIM karta"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"V tabletu není SIM karta."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"V telefonu není SIM karta."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Vložte SIM kartu."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM karta chybí nebo je nečitelná. Vložte SIM kartu."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Nepoužitelná SIM karta."</string>
@@ -85,17 +83,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Zadejte kód PIN o délce 4–8 číslic."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Minimální délka kódu PUK je 8 číslic."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Znovu zadejte správný kód PUK. Opakovanými pokusy SIM kartu trvale zablokujete."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kódy PIN se neshodují"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Příliš mnoho pokusů o zadání gesta"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste zadali nesprávný kód PIN. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste nesprávně zadali heslo. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste zadali nesprávné bezpečnostní gesto. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Již jste se <xliff:g id="NUMBER_0">%1$d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech bude tablet resetován, čímž se z něj smažou všechna data."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Již jste se <xliff:g id="NUMBER_0">%1$d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech bude telefon resetován, čímž se z něj smažou všechna data."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Tablet bude resetován, čímž z něj budou smazána všechna data."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Telefon bude resetován, čímž z něj budou smazána všechna data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Již jste se <xliff:g id="NUMBER_0">%1$d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech bude tento uživatel odstraněn, čímž se smažou všechna jeho data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Již jste se <xliff:g id="NUMBER_0">%1$d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech bude tento uživatel odstraněn, čímž se smažou všechna jeho data."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -104,10 +95,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Pracovní profil bude odstraněn, čímž budou smazána všechna jeho data."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Pracovní profil bude odstraněn, čímž budou smazána všechna jeho data."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste nesprávně zadali své bezpečnostní gesto. Po <xliff:g id="NUMBER_1">%2$d</xliff:g>dalších neúspěšných pokusech budete požádáni o odemčení tabletu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste nesprávně zadali své bezpečnostní gesto. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech budete požádáni o odemčení telefonu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Zadali jste nesprávný kód PIN SIM karty. Nyní musíte za účelem odemknutí zařízení kontaktovat svého operátora."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="few">Zadali jste nesprávný kód PIN SIM karty. Máte ještě <xliff:g id="NUMBER_1">%d</xliff:g> pokusy.</item>
diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml
index f134734..a66f02b 100644
--- a/packages/SystemUI/res-keyguard/values-da/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-da/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Tryk på menuen for at låse op."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Netværket er låst"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Intet SIM-kort"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Der er ikke noget SIM-kort i denne tablet."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Der er ikke noget SIM-kort i telefonen."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Indsæt et SIM-kort."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM-kortet mangler eller kan ikke læses. Indsæt et SIM-kort."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Ubrugeligt SIM-kort."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Angiv en pinkode på mellem 4 og 8 tal."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-koden skal være på 8 tal eller mere."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Angiv den korrekte PUK-kode. Gentagne forsøg deaktiverer permanent SIM-kortet."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Pinkoderne stemmer ikke overens"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Du har brugt for mange forsøg på at tegne mønsteret korrekt"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Du har indtastet en forkert pinkode <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Du har indtastet din adgangskode forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Du har forsøgt at låse denne tablet op med den forkerte adgangskode <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg nulstilles denne tablet, hvilket sletter alle dens data."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Du har forsøgt at låse telefonen op med den forkerte adgangskode <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg nulstilles denne telefon, hvilket sletter alle dens data."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Du har forsøgt at låse denne tablet op på forkert vis <xliff:g id="NUMBER">%d</xliff:g> gange. Denne tablet nulstilles, hvilket sletter alle dens data."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Du har forsøgt at låse telefonen op på forkert vis <xliff:g id="NUMBER">%d</xliff:g> gange. Telefonen nulstilles, hvilket sletter alle dens data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Du har forsøgt at låse denne tablet op med den forkerte adgangskode <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg fjernes denne bruger, hvilket sletter alle brugerdata."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Du har forsøgt at låse telefonen op med den forkerte adgangskode <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg fjernes denne bruger, hvilket sletter alle brugerdata."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Du har forsøgt at låse denne tablet op på forkert vis <xliff:g id="NUMBER">%d</xliff:g> gange. Arbejdsprofilen fjernes, hvilket sletter alle profildata."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Du har forsøgt at låse telefonen op på forkert vis <xliff:g id="NUMBER">%d</xliff:g> gange. Arbejdsprofilen fjernes, hvilket sletter alle profildata."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg bliver du bedt om at låse din tablet op ved hjælp af en mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg bliver du bedt om at låse din telefon op ved hjælp af en mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Forkert pinkode til SIM-kort. Du er nu nødt til at kontakte dit mobilselskab for at låse din enhed op."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">Forkert pinkode til SIM-kort. Du har <xliff:g id="NUMBER_1">%d</xliff:g> forsøg tilbage.</item>
diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml
index abc43da..7c0839a 100644
--- a/packages/SystemUI/res-keyguard/values-de/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-de/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Zum Entsperren die Menütaste drücken."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Netzwerk gesperrt"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Keine SIM-Karte"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Keine SIM-Karte im Tablet."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Keine SIM-Karte im Telefon."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM-Karte einlegen."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM-Karte fehlt oder ist nicht lesbar. Bitte lege eine SIM-Karte ein."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM-Karte unbrauchbar."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Gib eine 4- bis 8-stellige PIN ein."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Der PUK-Code muss mindestens 8 Ziffern aufweisen."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Gib den richtigen PUK-Code ein. Bei wiederholten Versuchen wird die SIM-Karte dauerhaft deaktiviert."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-Codes stimmen nicht überein"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Zu viele Musterversuche"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Du hast deine PIN <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch eingegeben.\n\nBitte versuche es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden noch einmal."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Du hast dein Passwort <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch eingegeben.\n\nBitte versuche es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden noch einmal."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. \n\nBitte versuche es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden noch einmal."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird dieses Tablet zurückgesetzt. Dadurch werden alle Gerätedaten gelöscht."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird dieses Telefon zurückgesetzt. Dadurch werden alle Gerätedaten gelöscht."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Dieses Tablet wird nun zurückgesetzt und alle Gerätedaten werden gelöscht."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Dieses Telefon wird nun zurückgesetzt und alle Gerätedaten werden gelöscht."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird dieser Nutzer entfernt. Dadurch werden alle Nutzerdaten gelöscht."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird dieser Nutzer entfernt. Dadurch werden alle Nutzerdaten gelöscht."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Das Arbeitsprofil wird nun entfernt und alle Profildaten werden gelöscht."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Das Arbeitsprofil wird nun entfernt und alle Profildaten werden gelöscht."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Tablet mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden noch einmal."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Telefon mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden noch einmal."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Falscher PIN-Code der SIM-Karte. Bitte wende dich an deinen Mobilfunkanbieter, damit er dein Gerät entsperrt."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">Falscher PIN-Code der SIM-Karte. Du hast noch <xliff:g id="NUMBER_1">%d</xliff:g> Versuche.</item>
diff --git a/packages/SystemUI/res-keyguard/values-el/strings.xml b/packages/SystemUI/res-keyguard/values-el/strings.xml
index 042a831..e9bd207 100644
--- a/packages/SystemUI/res-keyguard/values-el/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-el/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Πατήστε \"Μενού\" για ξεκλείδωμα."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Κλειδωμένο δίκτυο"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Δεν υπάρχει κάρτα SIM"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Δεν υπάρχει κάρτα SIM στο tablet."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Δεν υπάρχει κάρτα SIM στο τηλέφωνο."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Τοποθετήστε μια κάρτα SIM."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Η κάρτα SIM δεν υπάρχει ή δεν είναι δυνατή η ανάγνωσή της. Τοποθετήστε μια κάρτα SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Η κάρτα SIM δεν μπορεί να χρησιμοποιηθεί."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Πληκτρολογήστε έναν αριθμό PIN που να αποτελείται από 4 έως 8 αριθμούς."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Ο κωδικός PUK θα πρέπει να περιέχει τουλάχιστον 8 αριθμούς."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Εισαγάγετε ξανά τον κωδικό PUK. Οι επαναλαμβανόμενες προσπάθειες θα απενεργοποιήσουν οριστικά την κάρτα SIM."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Δεν υπάρχει αντιστοιχία μεταξύ των κωδικών PIN"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Πάρα πολλές προσπάθειες μοτίβου!"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Έχετε πληκτρολογήσει τον αριθμό PIN εσφαλμένα <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. \n\nΠροσπαθήστε ξανά σε <xliff:g id="NUMBER_1">%2$d</xliff:g> δευτερόλεπτα."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Έχετε πληκτρολογήσει τον κωδικό πρόσβασης εσφαλμένα <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. \n\nΠροσπαθήστε ξανά σε <xliff:g id="NUMBER_1">%2$d</xliff:g> δευτερόλεπτα."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Σχεδιάσατε εσφαλμένα το μοτίβο ξεκλειδώματος<xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. \n\nΠροσπαθήστε ξανά σε <xliff:g id="NUMBER_1">%2$d</xliff:g> δευτερόλεπτα."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Δοκιμάσατε να ξεκλειδώσετε το tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, αυτό το tablet θα ρυθμιστεί εκ νέου και θα διαγραφούν όλα τα δεδομένα του."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, αυτό το τηλέφωνο θα ρυθμιστεί εκ νέου και θα διαγραφούν όλα τα δεδομένα του."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Δοκιμάσατε να ξεκλειδώσετε αυτό το tablet <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Αυτό το tablet θα ρυθμιστεί εκ νέου και θα διαγραφούν όλα τα δεδομένα του."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Αυτό το τηλέφωνο θα ρυθμιστεί εκ νέου και θα διαγραφούν όλα τα δεδομένα του."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Δοκιμάσατε να ξεκλειδώσετε το tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, αυτός ο χρήστης θα καταργηθεί και θα διαγραφούν όλα τα δεδομένα χρήστη."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, αυτός ο χρήστης θα καταργηθεί και θα διαγραφούν όλα τα δεδομένα χρήστη."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Δοκιμάσατε να ξεκλειδώσετε το tablet <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Το προφίλ εργασίας θα καταργηθεί και θα διαγραφούν όλα τα δεδομένα προφίλ."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Το προφίλ εργασίας θα καταργηθεί και θα διαγραφούν όλα τα δεδομένα προφίλ."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, θα σας ζητηθεί να ξεκλειδώσετε το tablet με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε να συνδεθείτε ξανά σε <xliff:g id="NUMBER_2">%3$d</xliff:g> δευτερόλεπτα."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, θα σας ζητηθεί να ξεκλειδώσετε το τηλέφωνό σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε ξανά σε <xliff:g id="NUMBER_2">%3$d</xliff:g> δευτερόλεπτα."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Λανθασμένος κωδικός PIN κάρτας SIM. Θα πρέπει να επικοινωνήσετε με την εταιρεία κινητής τηλεφωνίας σας για να ξεκλειδώσετε τη συσκευή σας."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">Λανθασμένος κωδικός PIN κάρτας SIM. Απομένουν άλλες <xliff:g id="NUMBER_1">%d</xliff:g> προσπάθειες.</item>
diff --git a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
index 6d95c6a..969a8d6 100644
--- a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Press Menu to unlock."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Network locked"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"No SIM card"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No SIM card in tablet."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No SIM card in phone."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Insert a SIM card."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"The SIM card is missing or not readable. Insert a SIM card."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Unusable SIM card."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Type a PIN that is 4 to 8 numbers."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK code should be 8 numbers or more."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN codes do not match"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Too many pattern attempts"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This tablet will be reset, which will delete all its data."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This phone will be reset, which will delete all its data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Incorrect SIM PIN code; you must now contact your operator to unlock your device."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">Incorrect SIM PIN code. You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
diff --git a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
index d594cd0..fcc0887 100644
--- a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Press Menu to unlock."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Network locked"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"No SIM card"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No SIM card in tablet."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No SIM card in phone."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Insert a SIM card."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"The SIM card is missing or not readable. Insert a SIM card."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Unusable SIM card."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Type a PIN that is 4 to 8 numbers."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK code should be 8 numbers or more."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN codes do not match"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Too many pattern attempts"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This tablet will be reset, which will delete all its data."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This phone will be reset, which will delete all its data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Incorrect SIM PIN code; you must now contact your operator to unlock your device."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">Incorrect SIM PIN code. You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
diff --git a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
index 6d95c6a..969a8d6 100644
--- a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Press Menu to unlock."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Network locked"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"No SIM card"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No SIM card in tablet."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No SIM card in phone."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Insert a SIM card."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"The SIM card is missing or not readable. Insert a SIM card."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Unusable SIM card."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Type a PIN that is 4 to 8 numbers."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK code should be 8 numbers or more."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN codes do not match"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Too many pattern attempts"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This tablet will be reset, which will delete all its data."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This phone will be reset, which will delete all its data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Incorrect SIM PIN code; you must now contact your operator to unlock your device."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">Incorrect SIM PIN code. You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
diff --git a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
index 6d95c6a..969a8d6 100644
--- a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Press Menu to unlock."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Network locked"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"No SIM card"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No SIM card in tablet."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No SIM card in phone."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Insert a SIM card."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"The SIM card is missing or not readable. Insert a SIM card."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Unusable SIM card."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Type a PIN that is 4 to 8 numbers."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK code should be 8 numbers or more."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN codes do not match"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Too many pattern attempts"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%2$d</xliff:g> seconds."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This tablet will be reset, which will delete all its data."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This phone will be reset, which will delete all its data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Incorrect SIM PIN code; you must now contact your operator to unlock your device."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">Incorrect SIM PIN code. You have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
diff --git a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
index b8a6f10..975b1f6 100644
--- a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‎‎‎‏‎‏‏‏‎‏‎‏‎‎‎‏‏‎‏‎‏‏‎‏‏‎‎‎‏‏‎‎‎‏‎‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎Press Menu to unlock.‎‏‎‎‏‎"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‏‎‏‎‎‏‏‎‎‏‎‎‏‎‏‏‏‏‏‎‏‎‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‏‎‏‏‎‎‏‎‏‎‎‎‎‎‎‎‎‎‎‎Network locked‎‏‎‎‏‎"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‏‎‎‎‏‎‏‏‎‏‎‏‏‎‏‎‏‎‏‎‎‎‎‏‎‎‎‏‎‎‏‎‎‎‎‏‎‎‏‏‎‎‏‎‎‎‎‎‎‏‎‏‎‏‏‎No SIM card‎‏‎‎‏‎"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‏‏‏‎‏‏‎‎‏‎‏‎‎‎‎‏‎‏‏‏‎‏‎‎‎‏‎‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎‏‎‏‎‏‎‎‎‏‏‎No SIM card in tablet.‎‏‎‎‏‎"</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‏‏‏‎‎‎‏‎‎‎‏‏‏‏‎‏‎‎‎‎‏‏‏‏‎‎‏‎‎‎‎‎‎‏‎‏‎‏‎‏‎‏‎‏‏‎‏‏‎‎‏‏‏‎No SIM card in phone.‎‏‎‎‏‎"</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‎‏‎‎‎‎‎‏‎‏‎‏‏‏‎‏‏‎‏‎‎‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‎‏‏‏‏‎‎‏‎‎‏‎‏‏‎‏‏‏‎‎Insert a SIM card.‎‏‎‎‏‎"</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎‏‏‎‎‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‏‎‏‏‎‎‎‎‏‏‎‏‏‏‏‏‎‎‎‎‎‏‎‏‎‎The SIM card is missing or not readable. Insert a SIM card.‎‏‎‎‏‎"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‏‎‏‎‏‏‎‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‎‏‎‏‏‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‎‏‎‏‎‏‏‎‎‏‎‎Unusable SIM card.‎‏‎‎‏‎"</string>
@@ -83,25 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‏‎‏‎‏‎‏‎‏‎‎‎‎‏‎‏‎‏‏‎‎‎‎‏‏‎‎‎‏‎‎‎‏‎‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‎‎‏‎‎Type a PIN that is 4 to 8 numbers.‎‏‎‎‏‎"</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‎‏‎‏‎‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‎‎‏‏‏‏‎‎PUK code should be 8 numbers or more.‎‏‎‎‏‎"</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‏‎‏‎‎‎‎‏‎‏‏‎‎‎‏‏‏‎‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM.‎‏‎‎‏‎"</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‏‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‎‎‎‎‎‏‏‎‎‎‎‎‏‏‎‎‏‏‎‏‏‏‎‏‎‏‏‎‎PIN codes does not match‎‏‎‎‏‎"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‏‏‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‏‎‏‏‎‏‎‏‎‎‎‏‎‎‏‎‎‏‏‏‎‏‏‏‏‏‎‎‎‎‎‎‎‎‏‎‎Too many pattern attempts‎‏‎‎‏‎"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‏‎‎‎‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‏‏‎‏‎‏‏‏‏‏‏‎‎‎‎‏‎‎‏‎‏‎‎‏‏‏‎‏‏‎You have incorrectly typed your PIN ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Try again in ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ seconds.‎‏‎‎‏‎"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‏‎‏‎‎‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‏‏‏‎‏‎‎‏‏‎‎‎‏‎‏‎‏‎‏‎‏‎‏‏‎‎You have incorrectly typed your password ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Try again in ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ seconds.‎‏‎‎‏‎"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‎‎‎‎‎‏‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‏‏‏‏‎‏‎‏‏‎‏‎‏‎‏‏‏‏‎‏‏‏‏‎‎‏‎‏‎‏‎‎‎‎‎You have incorrectly drawn your unlock pattern ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Try again in ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ seconds.‎‏‎‎‏‎"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‎‎‎‏‏‎‎‎‏‎‎‏‏‏‏‎‎‏‏‎‎‏‏‏‏‏‎‎‏‏‎‎‏‎‏‏‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‎You have incorrectly attempted to unlock the tablet ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. After ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ more unsuccessful attempts, this tablet will be reset, which will delete all its data.‎‏‎‎‏‎"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‎‎‎‎‎‏‏‏‏‎‎‎‏‏‎‏‏‎‏‎‏‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‏‏‎‏‏‏‏‏‎‏‎‏‏‎‎‎‎‎‎You have incorrectly attempted to unlock the phone ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. After ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ more unsuccessful attempts, this phone will be reset, which will delete all its data.‎‏‎‎‏‎"</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‏‎‎‎‏‏‎‏‏‎‏‏‏‏‏‎‎‎‏‎‎‏‎‎‎‏‏‎‏‏‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‎‎You have incorrectly attempted to unlock the tablet ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%d</xliff:g>‎‏‎‎‏‏‏‎ times. This tablet will be reset, which will delete all its data.‎‏‎‎‏‎"</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‎‎‏‎‎‏‎‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‎‎‏‎‏‎‎‎You have incorrectly attempted to unlock the phone ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%d</xliff:g>‎‏‎‎‏‏‏‎ times. This phone will be reset, which will delete all its data.‎‏‎‎‏‎"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‏‎‏‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‎‏‏‏‎‏‏‏‏‎‎‎‏‎‏‏‎‏‏‎‎‎‎‏‏‎‎‏‏‏‎‏‎‎‎‎‎You have incorrectly attempted to unlock the tablet ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. After ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ more unsuccessful attempts, this user will be removed, which will delete all user data.‎‏‎‎‏‎"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‏‎‏‎‎‎‏‎‏‎‏‎‏‏‎‏‎‎‏‎‎‎‎‎‎‏‏‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‏‎‏‏‏‎‎‎‎You have incorrectly attempted to unlock the phone ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. After ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ more unsuccessful attempts, this user will be removed, which will delete all user data.‎‏‎‎‏‎"</string>
-    <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="9046628517316763961">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‎‎‎‎‏‎‏‎‎‏‎‏‏‎‏‎‎‏‎‎‏‎‏‎‏‏‎‎‏‎‏‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‎‎‏‎You have incorrectly attempted to unlock the tablet ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%d</xliff:g>‎‏‎‎‏‏‏‎ times. This user will be removed, which will delete all user data.‎‏‎‎‏‎"</string>
-    <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="3588779327358321092">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‎‎‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‎‏‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‏‎‏‎‎‎‎‎‏‏‏‎‎‎‏‎‎‎You have incorrectly attempted to unlock the phone ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%d</xliff:g>‎‏‎‎‏‏‏‎ times. This user will be removed, which will delete all user data.‎‏‎‎‏‎"</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="6114158710353725041">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‎‏‏‏‎‏‏‎‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‎‎‏‏‏‎‎‎‏‎You have incorrectly attempted to unlock the tablet ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. After ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ more unsuccessful attempts, the work profile will be removed, which will delete all profile data.‎‏‎‎‏‎"</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="8345451368768804892">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‎‏‎‏‏‏‎‎‎‎‏‏‎‎‎‏‏‎‎‎‎‎‎‏‏‏‎‎‎You have incorrectly attempted to unlock the phone ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. After ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ more unsuccessful attempts, the work profile will be removed, which will delete all profile data.‎‏‎‎‏‎"</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‏‏‎‎‏‎‎‎‏‏‏‎‎‏‏‎‎‏‏‎‏‏‏‏‎‏‎‏‎‏‏‎‎‏‎‏‏‏‏‎‎‏‎‎‎‏‎‏‎You have incorrectly attempted to unlock the tablet ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%d</xliff:g>‎‏‎‎‏‏‏‎ times. The work profile will be removed, which will delete all profile data.‎‏‎‎‏‎"</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‎‏‏‏‎‏‏‎‏‎‏‎‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‎‎‎‎‎‏‏‏‏‎‎‏‎‏‎‏‎‏‎‎‎You have incorrectly attempted to unlock the phone ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%d</xliff:g>‎‏‎‎‏‏‏‎ times. The work profile will be removed, which will delete all profile data.‎‏‎‎‏‎"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‏‏‎‏‏‎‏‎‏‏‏‏‎‎‎‎‎‎‏‎‏‎‏‎‎‎‎‎‏‏‏‎‎‏‎‏‎‎‎‏‏‎‎‎‎‎‏‎‏‏‏‎‎‎You have incorrectly drawn your unlock pattern ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. After ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ more unsuccessful attempts, you will be asked to unlock your tablet using an email account.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎ Try again in ‎‏‎‎‏‏‎<xliff:g id="NUMBER_2">%3$d</xliff:g>‎‏‎‎‏‏‏‎ seconds.‎‏‎‎‏‎"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‏‏‏‎‏‏‏‎‎‏‏‎‎‎‏‏‎‎‎‎‏‏‏‎‎‎‏‎‎‏‎‏‎‎‎‏‎You have incorrectly drawn your unlock pattern ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. After ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ more unsuccessful attempts, you will be asked to unlock your phone using an email account.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎ Try again in ‎‏‎‎‏‏‎<xliff:g id="NUMBER_2">%3$d</xliff:g>‎‏‎‎‏‏‏‎ seconds.‎‏‎‎‏‎"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‏‎‏‏‏‏‎‏‏‏‎‏‏‎‎‏‎‏‎‎‎‏‏‎‏‏‏‎‏‎‎‎‏‎‏‎‏‎‏‏‎‎‏‎‏‎‎‎‏‎‏‎Incorrect SIM PIN code you must now contact your carrier to unlock your device.‎‏‎‎‏‎"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‏‎‎‎‏‏‎‏‎‎‏‏‏‎‎‏‏‎‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‎‎‏‏‎‎‏‎‎‎‏‎‏‏‎‎‎‏‎‎Incorrect SIM PIN code, you have ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%d</xliff:g>‎‏‎‎‏‏‏‎ remaining attempts.‎‏‎‎‏‎</item>
diff --git a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
index 411f855..80df3be 100644
--- a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Presiona Menú para desbloquear."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Bloqueada para la red"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Sin tarjeta SIM"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No hay tarjeta SIM en la tablet."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No hay tarjeta SIM en el teléfono."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Inserta una tarjeta SIM."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Falta la tarjeta SIM o no se puede leer. Introduce una tarjeta SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Tarjeta SIM inutilizable"</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Escribe un PIN que tenga entre 4 y 8 números."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"El código PUK debe tener al menos 8 números."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Vuelve a ingresar el código PUK correcto. Si ingresas un código incorrecto varias veces, se inhabilitará la tarjeta SIM."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Los códigos PIN no coinciden"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Demasiados intentos incorrectos para el ingreso del patrón"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Escribiste tu PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Escribiste tu contraseña <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Dibujaste tu patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Intentaste desbloquear la tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se restablecerá la tablet, lo que borrará todos los datos."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se restablecerá el teléfono, lo que borrará todos los datos."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Intentaste desbloquear la tablet <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se restablecerá la tablet, lo que borrará todos los datos."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se restablecerá el teléfono, lo que borrará todos los datos."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Intentaste desbloquear la tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se quitará este usuario, lo que borrará todos los datos asociados."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se quitará este usuario, lo que borrará todos los datos asociados."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Intentaste desbloquear la tablet <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se quitará el perfil de trabajo, lo que borrará todos los datos asociados."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se quitará el perfil de trabajo, lo que borrará todos los datos asociados."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu tablet mediante una cuenta de correo electrónico.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu dispositivo mediante una cuenta de correo electrónico.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"El código PIN de la tarjeta SIM es incorrecto. Debes comunicarte con tu proveedor para desbloquear el dispositivo."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">El código PIN de la tarjeta SIM es incorrecto. Te quedan <xliff:g id="NUMBER_1">%d</xliff:g> intentos más.</item>
diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml
index 4430046..abfaf3a 100644
--- a/packages/SystemUI/res-keyguard/values-es/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Pulsa el menú para desbloquear la pantalla."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Bloqueada para la red"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Falta la tarjeta SIM"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No se ha insertado ninguna tarjeta SIM en el tablet."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No se ha insertado ninguna tarjeta SIM en el teléfono."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Inserta una tarjeta SIM."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Falta la tarjeta SIM o no se puede leer. Inserta una tarjeta SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"La tarjeta SIM se ha inhabilitado."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Escribe un código PIN que tenga entre 4 y 8 dígitos."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"El código PUK debe tener 8 números como mínimo."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Vuelve a introducir el código PUK correcto. Si introduces un código incorrecto varias veces, se inhabilitará la tarjeta SIM de forma permanente."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Los códigos PIN no coinciden"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Has fallado demasiadas veces al introducir el patrón"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al escribir el PIN. \n\nVuelve a intentarlo dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al introducir la contraseña. \n\nVuelve a intentarlo dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al dibujar el patrón de desbloqueo. \n\nVuelve a intentarlo dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al desbloquear el tablet. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, se recuperarán los ajustes de fábrica de este tablet y se eliminarán todos sus datos."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al desbloquear el teléfono. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, se recuperarán los ajustes de fábrica de este teléfono y se eliminarán todos sus datos."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Has fallado <xliff:g id="NUMBER">%d</xliff:g> veces al desbloquear el tablet. Se recuperarán los ajustes de fábrica de este tablet y se eliminarán todos sus datos."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Has fallado <xliff:g id="NUMBER">%d</xliff:g> veces al desbloquear el teléfono. Se recuperarán los ajustes de fábrica de este teléfono y se eliminarán todos sus datos."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al desbloquear el tablet. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, se quitará a este usuario y se eliminarán todos sus datos."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al desbloquear el teléfono. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, se quitará a este usuario y se eliminarán todos sus datos."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Has fallado <xliff:g id="NUMBER">%d</xliff:g> veces al desbloquear el tablet. Se quitará este perfil de trabajo se quitará y se eliminarán todos sus datos."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Has fallado <xliff:g id="NUMBER">%d</xliff:g> veces al desbloquear el teléfono. Se quitará este perfil de trabajo y se eliminarán todos sus datos."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, tendrás que usar una cuenta de correo electrónico para desbloquear el tablet.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, tendrás que usar una cuenta de correo electrónico para desbloquear el teléfono.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"El código PIN de la tarjeta SIM es incorrecto. Debes ponerte en contacto con tu operador para desbloquear el dispositivo."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">El código PIN de la tarjeta SIM es incorrecto. Quedan <xliff:g id="NUMBER_1">%d</xliff:g> intentos.</item>
diff --git a/packages/SystemUI/res-keyguard/values-et/strings.xml b/packages/SystemUI/res-keyguard/values-et/strings.xml
index 888a57f..bf8d067 100644
--- a/packages/SystemUI/res-keyguard/values-et/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-et/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Vajutage avamiseks menüüklahvi."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Võrk on lukus"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM-kaarti pole"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Tahvelarvutis pole SIM-kaarti."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefonis pole SIM-kaarti."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Sisestage SIM-kaart."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM-kaart puudub või on loetamatu. Sisestage SIM-kaart."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Kasutamiskõlbmatu SIM-kaart."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Sisestage 4–8-numbriline PIN-kood."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-koodi pikkus peab olema vähemalt kaheksa numbrit."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Sisestage uuesti õige PUK-kood. Korduvkatsete korral keelatakse SIM-kaart jäädavalt."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-koodid ei ole vastavuses"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Liiga palju mustrikatseid"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Olete PIN-koodi <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti sisestanud. \n\nProovige <xliff:g id="NUMBER_1">%2$d</xliff:g> sekundi pärast uuesti."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Olete parooli <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti sisestanud. \n\nProovige <xliff:g id="NUMBER_1">%2$d</xliff:g> sekundi pärast uuesti."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Olete oma avamismustrit <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti joonistanud. \n\nProovige <xliff:g id="NUMBER_1">%2$d</xliff:g> sekundi pärast uuesti."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda tahvelarvutit valesti avada. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset tahvelarvuti lähtestatakse ja kõik selle andmed kustutatakse."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda telefoni valesti avada. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset telefon lähtestatakse ja kõik selle andmed kustutatakse."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda tahvelarvutit valesti avada. Tahvelarvuti lähtestatakse ja kõik selle andmed kustutatakse."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda telefoni valesti avada. Telefon lähtestatakse ja kõik selle andmed kustutatakse."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda tahvelarvutit valesti avada. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset kasutaja eemaldatakse ja kõik kasutajaandmed kustutatakse."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda telefoni valesti avada. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset kasutaja eemaldatakse ja kõik kasutajaandmed kustutatakse."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda tahvelarvutit valesti avada. Tööprofiil eemaldatakse ja kõik profiiliandmed kustutatakse."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda telefoni valesti avada. Tööprofiil eemaldatakse ja kõik profiiliandmed kustutatakse."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset palutakse teil tahvelarvuti avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundi pärast."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset palutakse teil telefon avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundi pärast."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM-kaardi vale PIN-kood. Seadme avamiseks peate nüüd ühendust võtma oma operaatoriga."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">SIM-kaardi vale PIN-kood. Teil on jäänud veel <xliff:g id="NUMBER_1">%d</xliff:g> katset.</item>
diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml
index 117305f..6cf00d8 100644
--- a/packages/SystemUI/res-keyguard/values-eu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Desblokeatzeko, sakatu Menua."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Sarea blokeatuta dago"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Ez dago SIM txartelik"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Ez dago SIM txartelik tabletan."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Ez dago SIM txartelik telefonoan."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Sartu SIM txartela."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM txartela falta da edo ezin da irakurri. Sartu SIM txartel bat."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM txartela erabilgaitza da."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Idatzi 4 eta 8 zenbaki bitarteko PIN bat."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK kodeak 8 zenbaki izan behar ditu gutxienez."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Idatzi berriro PUK kode zuzena. Hainbat saiakera oker eginez gero, betiko desgaituko da SIM txartela."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodeak ez datoz bat"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Eredua marrazteko saiakera gehiegi egin dira"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz idatzi duzu PIN kodea, baina huts egin duzu denetan. \n\nSaiatu berriro <xliff:g id="NUMBER_1">%2$d</xliff:g> segundo barru."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz idatzi duzu pasahitza, baina huts egin duzu denetan. \n\nSaiatu berriro <xliff:g id="NUMBER_1">%2$d</xliff:g> segundo barru."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz marraztu duzu desblokeatzeko eredua, baina huts egin duzu denetan. \n\nSaiatu berriro <xliff:g id="NUMBER_1">%2$d</xliff:g> segundo barru."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, berrezarri egingo da tableta eta, ondorioz, bertako datu guztiak ezabatuko dira."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, berrezarri egingo da telefonoa eta, ondorioz, bertako datu guztiak ezabatuko dira."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Tableta berrezarri egingo da eta, ondorioz, bertako datu guztiak ezabatuko dira."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Telefonoa berrezarri egingo da eta, ondorioz, bertako datu guztiak ezabatuko dira."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, kendu egingo da erabiltzailea eta, ondorioz, haren datu guztiak ezabatuko dira."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, kendu egingo da erabiltzailea eta, ondorioz, haren datu guztiak ezabatuko dira."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Laneko profila kendu egingo da eta, ondorioz, profileko datu guztiak ezabatuko dira."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Laneko profila kendu egingo da eta, ondorioz, profileko datu guztiak ezabatuko dira."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz marraztu duzu desblokeatzeko eredua, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, tableta posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%3$d</xliff:g> segundo barru."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz marraztu duzu desblokeatzeko eredua, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, telefonoa posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%3$d</xliff:g> segundo barru."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM txartelaren PIN kodea ez da zuzena. Gailua desblokeatzeko, operadorearekin jarri beharko duzu harremanetan."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">Ez da zuzena SIM txartelaren PIN kodea. <xliff:g id="NUMBER_1">%d</xliff:g> saiakera geratzen zaizkizu gailua desblokeatzeko.</item>
diff --git a/packages/SystemUI/res-keyguard/values-fa/strings.xml b/packages/SystemUI/res-keyguard/values-fa/strings.xml
index da5ec73..6fbe804 100644
--- a/packages/SystemUI/res-keyguard/values-fa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fa/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"برای باز کردن قفل روی «منو» فشار دهید."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"شبکه قفل شد"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"سیم‌کارت موجود نیست"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"سیم‌کارت درون رایانهٔ لوحی نیست."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"سیم‌کارت درون تلفن نیست."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"سیم‌کارت را وارد کنید."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"سیم‌کارت موجود نیست یا قابل خواندن نیست. یک سیم‌کارت وارد کنید."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"سیم‌کارت غیرقابل استفاده است."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"یک پین ۴ تا ۸ رقمی را تایپ کنید."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"کد پین باید ۸ عدد یا بیشتر باشد."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"کد پین صحیح را دوباره وارد کنید. تلاش‌های مکرر به‌طور دائم سیم‌کارت را غیرفعال خواهد کرد."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"کدهای پین منطبق نیستند"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"‏تلاش‎های زیادی برای کشیدن الگو صورت گرفته است"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"پین خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه تایپ کردید. \n\nپس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"گذرواژه خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه تایپ کردید. \n\nپس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"الگوی باز کردن قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدید. \n\nلطفاً پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"<xliff:g id="NUMBER_0">%1$d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشته‌اید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، این رایانه لوحی بازنشانی می‌شود که با آن همه داده‌هایش حذف می‌شود."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"<xliff:g id="NUMBER_0">%1$d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشته‌اید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، تلفن بازنشانی می‌شود که با آن همه داده‌هایش حذف می‌شود."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشته‌اید. این رایانه لوحی بازنشانی می‌شود که با آن همه داده‌هایش حذف می‌شود."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشته‌اید. این تلفن بازنشانی می‌شود که با آن همه داده‌هایش حذف می‌شود."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"<xliff:g id="NUMBER_0">%1$d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشته‌اید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، این کاربر پاک می‌شود که با آن همه داده‌های کاربر حذف می‌شود."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"<xliff:g id="NUMBER_0">%1$d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشته‌اید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، این کاربر پاک می‌شود که با آن همه داده‌های کاربر حذف می‌شود."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشته‌اید. نمایه کاری پاک می‌شود که با آن همه داده‌های نمایه حذف می‌شود."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشته‌اید. نمایه کاری پاک می‌شود که با آن همه داده‌های نمایه حذف می‌شود."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"‏شما الگوی باز کردن قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‎اید. بعد از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته می‎شود که با استفاده از یک حساب ایمیل قفل رایانه لوحی خود را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"‏شما الگوی باز کردن قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‌اید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته می‎شود که با استفاده از یک حساب ایمیل قفل تلفن را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"کد پین سیم‌کارت اشتباه است، اکنون برای باز کردن قفل دستگاهتان باید با شرکت مخابراتی تماس بگیرید."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">کد پین سیم‌کارت اشتباه است، <xliff:g id="NUMBER_1">%d</xliff:g> بار دیگر می‌توانید تلاش کنید.</item>
diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml
index eec3d12..6d26e36 100644
--- a/packages/SystemUI/res-keyguard/values-fi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Poista lukitus painamalla Valikkoa."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Verkko lukittu"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Ei SIM-korttia"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Tabletissa ei ole SIM-korttia."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Puhelimessa ei ole SIM-korttia."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Aseta SIM-kortti."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM-korttia ei löydy tai ei voi lukea. Aseta SIM-kortti."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM-kortti ei käytettävissä"</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Anna 4–8-numeroinen PIN-koodi."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-koodissa tulee olla vähintään 8 numeroa."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Anna uudelleen oikea PUK-koodi. Jos teet liian monta yritystä, SIM-kortti poistetaan käytöstä pysyvästi."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-koodit eivät täsmää"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Liikaa kuvionpiirtoyrityksiä"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Olet kirjoittanut PIN-koodin väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunnin kuluttua."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Olet kirjoittanut salasanan väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunnin kuluttua."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Olet piirtänyt lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunnin kuluttua."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos <xliff:g id="NUMBER_1">%2$d</xliff:g> seuraavaa yritystä epäonnistuu, tämä puhelin nollataan ja kaikki sen tiedot poistetaan."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos <xliff:g id="NUMBER_1">%2$d</xliff:g> seuraavaa yritystä epäonnistuu, tämä puhelin nollataan ja kaikki sen tiedot poistetaan."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Tämä tabletti nollataan ja kaikki sen tiedot poistetaan."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Tämä puhelin nollataan ja kaikki sen tiedot poistetaan."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos <xliff:g id="NUMBER_1">%2$d</xliff:g> seuraavaa yritystä epäonnistuu, tämä käyttäjä ja kaikki sen käyttäjätiedot poistetaan."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos <xliff:g id="NUMBER_1">%2$d</xliff:g> seuraavaa yritystä epäonnistuu, tämä käyttäjä ja kaikki käyttäjän tiedot poistetaan."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Työprofiili ja kaikki sen tiedot poistetaan."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Työprofiili ja kaikki sen tiedot poistetaan."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> kertaa, sinua pyydetään avaamaan tabletin lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunnin kuluttua."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> kertaa, sinua pyydetään avaamaan puhelimesi lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunnin kuluttua."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Virheellinen SIM-kortin PIN-koodi. Sinun on nyt otettava yhteys operaattoriin laitteen lukituksen avaamiseksi."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">Virheellinen SIM-kortin PIN-koodi. Sinulla on <xliff:g id="NUMBER_1">%d</xliff:g> yritystä jäljellä.</item>
diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
index c13ec43..53255af 100644
--- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Appuyez sur la touche Menu pour déverrouiller l\'appareil."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Réseau verrouillé"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Aucune carte SIM"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Aucune carte SIM n\'est insérée dans la tablette."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Aucune carte SIM n\'est insérée dans le téléphone."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Insérez une carte SIM."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Carte SIM absente ou illisible. Veuillez insérer une carte SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Carte SIM inutilisable."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Veuillez entrer un NIP comprenant entre quatre et huit chiffres."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Le code PUK doit contenir au moins 8 chiffres."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Veuillez entrer de nouveau le code PUK correct. Trop de tentatives répétées désactiveront définitivement la carte SIM."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Les NIP ne correspondent pas."</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Trop de tentatives."</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Vous avez entré un NIP incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Vous avez entré un mot de passe incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%2$d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), cette tablette sera réinitialisée, ce qui entraînera la suppression de toutes les données qu\'elle contient."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%2$d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), le téléphone sera réinitialisé, ce qui entraînera la suppression de toutes les données qu\'il contient."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Cette tablette sera réinitialisée, ce qui entraîne la suppression de toutes les données qu\'elle contient."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Ce téléphone sera réinitialisé, ce qui entraîne la suppression de toutes les données qu\'il contient."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%2$d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), cet utilisateur sera supprimé, ce qui entraînera la suppression de toutes ses données."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%2$d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), cet utilisateur sera supprimé, ce qui entraînera la suppression de toutes ses données."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel sera supprimé, ce qui entraîne la suppression de toutes ses données."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel sera supprimé, ce qui entraîne la suppression de toutes ses données."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de courriel.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de courriel.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"NIP de carte SIM incorrect. Vous devez maintenant communiquer avec votre fournisseur de services pour déverrouiller votre appareil."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">Le NIP de la carte SIM incorrect. Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentative.</item>
diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml
index 62d2456..ff3ed53 100644
--- a/packages/SystemUI/res-keyguard/values-fr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Appuyez sur \"Menu\" pour déverrouiller le clavier."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Réseau verrouillé"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Pas de carte SIM"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Aucune carte SIM n\'est insérée dans la tablette."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Aucune carte SIM n\'est insérée dans le téléphone."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Insérez une carte SIM."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Carte SIM absente ou illisible. Insérez une carte SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"La carte SIM est inutilisable."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Saisissez un code PIN comprenant 4 à 8 chiffres."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"La clé PUK doit contenir au moins 8 chiffres."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Veuillez saisir de nouveau la clé PUK. Après plusieurs tentatives, la carte SIM sera définitivement désactivée."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Les codes PIN ne correspondent pas"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Trop de tentatives"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Vous avez saisi un code incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises.\n\nRéessayez dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Vous avez saisi un mot de passe incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises.\n\nRéessayez dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises.\n\nRéessayez dans <xliff:g id="NUMBER_1">%2$d</xliff:g> secondes."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, elle sera réinitialisée et toutes les données qu\'elle contient seront supprimées."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, il sera réinitialisé et toutes les données qu\'il contient seront supprimées."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Elle va être réinitialisée et toutes les données qu\'elle contient seront supprimées."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Il va être réinitialisé et toutes les données qu\'il contient seront supprimées."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, ce compte utilisateur et toutes les données associées seront supprimés."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, ce compte utilisateur et toutes les données associées seront supprimés."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel et toutes les données associées vont être supprimés."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel et toutes les données associées vont être supprimés."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de messagerie électronique.\n\nRéessayez dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique.\n\nRéessayez dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Code PIN de la carte SIM incorrect. Vous devez désormais contacter votre opérateur pour déverrouiller votre appareil."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">Code PIN de la carte SIM incorrect. Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentative.</item>
diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml
index aeef9aa..d7f6b6a 100644
--- a/packages/SystemUI/res-keyguard/values-gl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Preme Menú para desbloquear."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Bloqueada pola rede"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Sen tarxeta SIM"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Non hai ningunha tarxeta SIM na tableta."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Non hai ningunha tarxeta SIM no teléfono."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Insire unha tarxeta SIM."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Falta a tarxeta SIM ou non se pode ler. Insire unha tarxeta SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Tarxeta SIM inutilizable"</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Escribe un PIN que teña entre 4 e 8 números."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"O código PUK debe ter 8 números como mínimo."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Volve introducir o código PUK correcto. Se realizas intentos repetidos é posible que se desactive a tarxeta SIM permanentemente."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Os códigos PIN non coinciden"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Tentaches debuxar o padrón moitas veces"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Introduciches o PIN incorrectamente <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \n\nTéntao de novo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Introduciches o contrasinal incorrectamente <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \n\nTéntao de novo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Debuxaches incorrectamente o padrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \n\nTéntao de novo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Tentaches desbloquear a tableta <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, restablecerase a tableta e, por conseguinte, eliminaranse todos os seus datos."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, restablecerase o teléfono e, por conseguinte, eliminaranse todos os seus datos."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Tentaches desbloquear a tableta <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Restablecerase a tableta e, por conseguinte, eliminaranse todos os seus datos."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Restablecerase o teléfono e, por conseguinte, eliminaranse todos os seus datos."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Tentaches desbloquear a tableta <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, quitarase este usuario e, por conseguinte, todos os datos do usuario."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, quitarase este usuario e, por conseguinte, todos os datos do usuario."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Tentaches desbloquear a tableta <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Quitarase o perfil de traballo e, por conseguinte, todos os datos do perfil."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Quitarase o perfil de traballo e, por conseguinte, todos os datos do perfil."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Debuxaches o padrón de desbloqueo incorrectamente <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, terás que desbloquear a tableta a través dunha conta de correo electrónico.\n\n Téntao de novo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Debuxaches o padrón de desbloqueo incorrectamente <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, terás que desbloquear o teléfono a través dunha conta de correo electrónico.\n\n Téntao de novo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"O código PIN da SIM non é correcto. Agora debes contactar co operador para desbloquear o dispositivo."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">O código PIN da SIM é incorrecto. Quédanche <xliff:g id="NUMBER_1">%d</xliff:g> intentos.</item>
diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml
index 3f5cab5..c3b7602 100644
--- a/packages/SystemUI/res-keyguard/values-gu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"અનલૉક કરવા માટે મેનૂ દબાવો."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"નેટવર્ક લૉક થયું"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"કોઈ સિમ કાર્ડ નથી"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ટૅબ્લેટમાં સિમ કાર્ડ નથી."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ફોનમાં સિમ કાર્ડ નથી."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"એક સિમ કાર્ડ દાખલ કરો."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"સિમ કાર્ડ ખૂટે છે અથવા વાંચન યોગ્ય નથી. સિમ કાર્ડ દાખલ કરો."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"બિનઉપયોગી સિમ કાર્ડ."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4 થી 8 સંખ્યાનો હોય તેવો એક પિન લખો."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK કોડ 8 કે તેનાથી વધુ સંખ્યાનો હોવો જોઈએ."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"સાચો PUK કોડ ફરીથી દાખલ કરો. પુનરાવર્તિત પ્રયાસો સિમ ને કાયમી રીતે અક્ષમ કરશે."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"પિન કોડ મેળ ખાતા નથી"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"ઘણા બધા પૅટર્ન પ્રયાસો"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"તમારો પિન તમે <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે લખ્યો છે. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> સેકન્ડમાં ફરીથી પ્રયાસ કરો."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"તમારો પાસવર્ડ તમે <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે લખ્યો છે. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> સેકંડમાં ફરીથી પ્રયાસ કરો."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"તમારી અનલૉક પૅટર્ન તમે <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે દોરી છે. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> સેકન્ડમાં ફરીથી પ્રયાસ કરો."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"તમે ટૅબ્લેટને <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, આ ટૅબ્લેટ ફરીથી સેટ કરવામાં આવશે, જે તેનો તમામ ડેટા કાઢી નાખશે."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"તમે ફોનને <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, આ ફોન ફરીથી સેટ કરવામાં આવશે, જે તેનો તમામ ડેટા કાઢી નાખશે."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"તમે ટૅબ્લેટને <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. આ ટૅબ્લેટ ફરીથી સેટ થશે, જે તેનો તમામ ડેટા કાઢી નાખશે."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"તમે ફોનને <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. આ ફોન ફરીથી સેટ કરાશે, જે તેનો તમામ ડેટા કાઢી નાખશે."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"તમે ટૅબ્લેટને <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. <xliff:g id="NUMBER_1">%2$d</xliff:g> વધુ અસફળ પ્રયાસો પછી, આ વપરાશકર્તાને દૂર કરવામાં આવશે, જે તમામ વપરાશકર્તા ડેટાને કાઢી નાખશે."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"તમે ફોનને <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, આ વપરાશકર્તાને દૂર કરવામાં આવશે, જે તમામ વપરાશકર્તા ડેટા કાઢી નાખશે."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"તમે ટૅબ્લેટને <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. આ કાર્યાલયની પ્રોફાઇલ દૂર કરવામાં આવશે, જે તમામ પ્રોફાઇલ ડેટાને કાઢી નાખશે."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"તમે ફોનને <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. આ કાર્યાલયની પ્રોફાઇલ દૂર કરવામાં આવશે, જે તમામ પ્રોફાઇલ ડેટાને કાઢી નાખશે."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"તમે તમારી અનલૉક પૅટર્ન <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે દોરી છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, તમને એક ઇમેઇલ એકાઉન્ટનો ઉપયોગ કરીને તમારા ટૅબ્લેટને અનલૉક કરવાનું કહેવામાં આવશે.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> સેકન્ડમાં ફરી પ્રયાસ કરો."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"તમે તમારી અનલૉક પૅટર્ન <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે દોરી છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, તમને ઇમેઇલ એકાઉન્ટનો ઉપયોગ કરીને ફોન અનલૉક કરવાનું કહેવામાં આવશે.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> સેકન્ડમાં ફરીથી પ્રયાસ કરો."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"ખોટો સિમ પિન કોડ, તમારે હવે તમારું ઉપકરણ અનલૉક કરવા માટે તમારા કૅરીઅરનો સંપર્ક કરવો આવશ્યક છે."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">ખોટો સિમ પિન કોડ, તમારી પાસે <xliff:g id="NUMBER_1">%d</xliff:g> પ્રયાસ બાકી છે.</item>
diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml
index cc8af31..1c5cead 100644
--- a/packages/SystemUI/res-keyguard/values-hi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"लॉक खोलने के लिए मेन्यू दबाएं."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"नेटवर्क लॉक किया हुआ है"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"कोई SIM कार्ड नहीं है"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"टैबलेट में कोई SIM कार्ड नहीं है."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"फ़ोन में कोई SIM कार्ड नहीं है."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM कार्ड लगाएं."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM कार्ड मौजूद नहीं है या उसे पढ़ा नहीं जा सकता है. कोई SIM कार्ड लगाएं."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"बेकार SIM कार्ड."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"कोई ऐसा पिन लिखें, जिसमें 4 से 8 अंक हों."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK कोड 8 या ज़्यादा संख्या वाला होना चाहिए."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"सही PUK कोड दोबारा डालें. बार-बार कोशिश करने से SIM हमेशा के लिए अक्षम हो जाएगा."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"पिन कोड का मिलान नहीं हो रहा है"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"पैटर्न के लिए बहुत ज़्यादा बार कोशिश की गई है"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"आप अपना पिन <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से लिख चुके हैं. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंड में फिर से कोशिश करें."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"आप अपना पासवर्ड <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से लिख चुके हैं. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंड में फिर से कोशिश करें."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"आपने अपने लॉक खोलने के पैटर्न को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से ड्रॉ किया है. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंड में फिर से कोशिश करें."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"आपने टैबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से कोशिश की है. <xliff:g id="NUMBER_1">%2$d</xliff:g> और असफल कोशिशों के बाद, इस टैबलेट को रीसेट कर दिया जाएगा, जिससे इसका सारा डेटा हट जाएगा."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"आपने फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से कोशिश की है. <xliff:g id="NUMBER_1">%2$d</xliff:g> और असफल कोशिशों के बाद, इस फ़ोन को रीसेट कर दिया जाएगा, जिससे इसका सारा डेटा हट जाएगा."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"आपने टैबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से कोशिश की है. इस टैबलेट को रीसेट कर दिया जाएगा, जिससे इसका सारा डेटा हट जाएगा."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"आपने फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से कोशिश की है. इस फ़ोन को रीसेट कर दिया जाएगा, जिससे इसका सारा डेटा हट जाएगा."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"आपने टैबलेट का लॉक खोलने के लिए <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से कोशिश की है. <xliff:g id="NUMBER_1">%2$d</xliff:g> बार और गलत कोशिश करने पर, इस उपयोगकर्ता को निकाल दिया जाएगा, जिससे सभी उपयोगकर्ता डेटा मिट जाएगा."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"आपने फ़ोन का लॉक खोलने के लिए <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से कोशिश की है. <xliff:g id="NUMBER_1">%2$d</xliff:g> बार और गलत कोशिश करने पर, इस उपयोगकर्ता को निकाल दिया जाएगा, जिससे सभी उपयोगकर्ता डेटा मिट जाएगा."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"आपने टैबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से कोशिश की है. वर्क प्रोफ़ाइल को निकाल दिया जाएगा, जिससे सभी प्रोफ़ाइल डेटा हट जाएगा."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"आपने फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से कोशिश की है. वर्क प्रोफ़ाइल को निकाल दिया जाएगा, जिससे सभी प्रोफ़ाइल डेटा हट जाएगा."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"आपने अपने लॉक खोलने के पैटर्न को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से ड्रॉ किया है. अगर आपने <xliff:g id="NUMBER_1">%2$d</xliff:g> बार और गलत ड्रॉ किया, तो आपसे अपने टैबलेट को किसी ईमेल खाते का इस्तेमाल करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड बाद फिर से कोशिश करें."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"आपने अपने लॉक खोलने के पैटर्न को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से ड्रॉ किया है. अगर आपने <xliff:g id="NUMBER_1">%2$d</xliff:g> बार और गलत ड्रॉ किया, तो आपसे अपने फ़ोन को किसी ईमेल खाते का इस्तेमाल करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड बाद फिर से कोशिश करें."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"गलत SIM पिन कोड, अपने डिवाइस को अनलॉक करने के लिए अब आपको अपनी मोबाइल और इंटरनेट सेवा देने वाली कंपनी से संपर्क करना होगा."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">गलत सिम पिन कोड, आप <xliff:g id="NUMBER_1">%d</xliff:g> बार और कोशिश कर सकते हैं.</item>
diff --git a/packages/SystemUI/res-keyguard/values-hr/strings.xml b/packages/SystemUI/res-keyguard/values-hr/strings.xml
index 17153e4..ee7a403 100644
--- a/packages/SystemUI/res-keyguard/values-hr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hr/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Pritisnite Izbornik da biste otključali."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Mreža je zaključana"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Nema SIM kartice"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"U tabletu nema SIM kartice."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"U telefonu nema SIM kartice."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Umetnite SIM karticu."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM kartica nedostaje ili nije čitljiva. Umetnite SIM karticu."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM kartica nije upotrebljiva."</string>
@@ -84,17 +82,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Unesite PIN koji ima od 4 do 8 brojeva."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK kôd treba imati 8 brojeva ili više."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Ponovo unesite ispravan PUK kôd. Ponovljeni pokušaji trajno će onemogućiti SIM."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodovi nisu jednaki"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Previše pokušaja iscrtavanja uzorka"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Netočno ste unijeli PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Netočno ste unijeli zaporku <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Neuspješno ste pokušali otključati tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja tablet će se vratiti na zadano, a time će se izbrisati i svi podaci na njemu."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Neuspješno ste pokušali otključati telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja telefon će se vratiti na zadano, a time će se izbrisati i svi podaci na njemu."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Neuspješno ste pokušali otključati tablet <xliff:g id="NUMBER">%d</xliff:g> put/a. Tablet će se vratiti na zadano, a time će se izbrisati i svi podaci na njemu."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Neuspješno ste pokušali otključati telefon <xliff:g id="NUMBER">%d</xliff:g> put/a. Telefon će se vratiti na zadano, a time će se izbrisati i svi podaci na njemu."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Neuspješno ste pokušali otključati tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja taj će se korisnik ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Neuspješno ste pokušali otključati telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja taj će se korisnik ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -103,10 +94,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Neuspješno ste pokušali otključati tablet <xliff:g id="NUMBER">%d</xliff:g> put/a. Radni će se profil ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Neuspješno ste pokušali otključati telefon <xliff:g id="NUMBER">%d</xliff:g> put/a. Radni će se profil ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja morat ćete otključati tablet pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja morat ćete otključati telefon pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Netočan PIN kôd SIM kartice; sada morate kontaktirati svog mobilnog operatera da bi otključao vaš uređaj."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">PIN kôd SIM-a nije točan. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj.</item>
diff --git a/packages/SystemUI/res-keyguard/values-hu/strings.xml b/packages/SystemUI/res-keyguard/values-hu/strings.xml
index 4eb32e9..2f358a0 100644
--- a/packages/SystemUI/res-keyguard/values-hu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hu/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"A feloldáshoz nyomja meg a Menü gombot."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Hálózat zárolva"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Nincs SIM-kártya"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nincs SIM-kártya a táblagépben."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Nincs SIM-kártya a telefonban."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Helyezzen be SIM-kártyát."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"A SIM-kártya hiányzik vagy nem olvasható. Helyezzen be SIM-kártyát."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"A SIM-kártya nem használható."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Írjon be egy 4-8 számjegyű PIN-kódot."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"A PUK-kódnak legalább nyolc számjegyből kell állnia."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Adja meg újra a helyes PUK-kódot. Az ismételt próbálkozásokkal véglegesen letiltja a SIM-kártyát."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"A PIN-kódok nem egyeznek"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Túl sok mintarajzolási próbálkozás"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül adta meg a PIN-kódot.\n\nPróbálja újra <xliff:g id="NUMBER_1">%2$d</xliff:g> másodperc múlva."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül adta meg a jelszót.\n\nPróbálja újra <xliff:g id="NUMBER_1">%2$d</xliff:g> másodperc múlva."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal rosszul rajzolta le a feloldási mintát.\n\nPróbálja újra <xliff:g id="NUMBER_1">%2$d</xliff:g> másodperc múlva."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után a rendszer visszaállítja a táblagépet, és ezzel az összes adat törlődik róla."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után a rendszer visszaállítja a telefont, és ezzel az összes adat törlődik róla."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. A rendszer visszaállítja a táblagépet, és ezzel a rajta lévő összes adat törlődik."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. A rendszer visszaállítja a telefont, és ezzel a rajta lévő összes adat törlődik."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után a rendszer eltávolítja a felhasználót, és ezzel a felhasználó összes adata törlődik majd."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után a rendszer eltávolítja a felhasználót, és ezzel a felhasználó összes adata törlődik majd."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. A rendszer eltávolítja a munkaprofilt, és ezzel a profil összes adata törlődik."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. A rendszer eltávolítja a munkaprofilt, és ezzel a profil összes adata törlődik."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után e-mail-fiók használatával kell feloldania táblagépét.\n\nPróbálja újra <xliff:g id="NUMBER_2">%3$d</xliff:g> másodperc múlva."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után e-mail-fiók használatával kell feloldania telefonját.\n\nPróbálja újra <xliff:g id="NUMBER_2">%3$d</xliff:g> másodperc múlva."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Helytelen PIN-kód a SIM-kártyához. Az eszköz feloldása érdekében, kérjük, vegye fel a kapcsolatot szolgáltatójával."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">Helytelen PIN-kód a SIM-kártyához. Még <xliff:g id="NUMBER_1">%d</xliff:g> próbálkozása maradt.</item>
diff --git a/packages/SystemUI/res-keyguard/values-hy/strings.xml b/packages/SystemUI/res-keyguard/values-hy/strings.xml
index c0d1c93..7da8ed4 100644
--- a/packages/SystemUI/res-keyguard/values-hy/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hy/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Ապակողպելու համար սեղմեք Ընտրացանկը:"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Ցանցը կողպված է"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM քարտ չկա"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Պլանշետում SIM քարտ չկա:"</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Հեռախոսում SIM քարտ չկա:"</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Տեղադրեք SIM քարտ:"</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM քարտը բացակայում է կամ ընթեռնելի չէ: Տեղադրեք SIM քարտ:"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Անպիտան SIM քարտ:"</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Մուտքագրեք 4-8 թվանշան պարունակող PIN կոդ։"</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK կոդը պետք է առնվազն 8 թվանշան պարունակի։"</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Վերամուտքագրեք ճիշտ PUK կոդը: Կրկնվող փորձերը ընդմիշտ կարգելափակեն SIM քարտը:"</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN կոդերը չեն համընկնում"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Նախշը մուտքագրելու չափազանց շատ փորձեր են կատարվել"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Դուք սխալ եք մուտքագրել ձեր PIN կոդը <xliff:g id="NUMBER_0">%1$d</xliff:g> անգամ: \n\nՓորձեք կրկին <xliff:g id="NUMBER_1">%2$d</xliff:g> վայրկյանից։"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Դուք սխալ եք մուտքագրել ձեր գաղտնաբառը <xliff:g id="NUMBER_0">%1$d</xliff:g> անգամ: \n\nՓորձեք կրկին <xliff:g id="NUMBER_1">%2$d</xliff:g> վայրկյանից:"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Դուք սխալ եք մուտքագրել ձեր ապակողպման նախշը <xliff:g id="NUMBER_0">%1$d</xliff:g> անգամ: \n\nՓորձեք կրկին <xliff:g id="NUMBER_1">%2$d</xliff:g> վայրկյանից։"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Դուք կատարել եք պլանշետն ապակողպելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո այս պլանշետը կվերակայվի և բոլոր տվյալները կջնջվեն:"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո այս հեռախոսը կվերակայվի և բոլոր տվյալները կջնջվեն:"</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Դուք կատարել եք պլանշետն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Այս պլանշետը կվերակայվի և բոլոր տվյալները կջնջվեն:"</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Այս հեռախոսը կվերակայվի և բոլոր տվյալները կջնջվեն:"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Դուք կատարել եք պլանշետն ապակողպելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո այս օգտվողը կհեռացվի և օգտվողի բոլոր տվյալները կջնջվեն:"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո այս օգտվողը կհեռացվի և օգտվողի բոլոր տվյալները կջնջվեն:"</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Դուք կատարել եք պլանշետն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Աշխատանքային պրոֆիլը կհեռացվի և պրոֆիլի բոլոր տվյալները կջնջվեն:"</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Աշխատանքային պրոֆիլը կհեռացվի և պրոֆիլի բոլոր տվյալները կջնջվեն:"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Դուք կատարել եք ապակողպման նախշը մուտքագրելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո ձեզանից կպահանջվի ապակողպել պլանշետը էլփոստի հաշվի միջոցով։\n\n Խնդրում ենք փորձել կրկին <xliff:g id="NUMBER_2">%3$d</xliff:g> վայրկյանից:"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Դուք կատարել եք ապակողպման նախշը մուտքագրելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո ձեզանից կպահանջվի ապակողպել հեռախոսը էլփոստի հաշվի միջոցով։\n\n Խնդրում ենք փորձել կրկին <xliff:g id="NUMBER_2">%3$d</xliff:g> վայրկյանից:"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM PIN կոդը սխալ է։ Այժմ պետք է դիմեք ձեր օպերատորին՝ սարքն արգելահանելու համար:"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">Incorrect SIM PIN code, you have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml
index 8772d89..406b00e 100644
--- a/packages/SystemUI/res-keyguard/values-in/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-in/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Tekan Menu untuk membuka kunci."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Jaringan terkunci"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Tidak ada kartu SIM"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Tidak ada kartu SIM dalam tablet."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Tidak ada Kartu SIM di dalam ponsel."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Masukkan kartu SIM."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Kartu SIM tidak ada atau tidak dapat dibaca. Masukkan kartu SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Kartu SIM tidak dapat digunakan."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Ketikkan PIN berupa 4 sampai 8 angka."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Kode PUK harus terdiri dari 8 angka atau lebih."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Masukkan kembali kode PUK yang benar. Jika berulang kali gagal, SIM akan dinonaktifkan secara permanen."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kode PIN tidak cocok"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Terlalu banyak upaya pola"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah mengetik PIN. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%2$d</xliff:g> detik."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah mengetik sandi. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%2$d</xliff:g> detik."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka kunci. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%2$d</xliff:g> detik."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Sudah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, tablet ini akan disetel ulang, sehingga semua datanya akan dihapus."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Sudah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, ponsel ini akan disetel ulang, sehingga semua datanya akan dihapus."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Tablet ini akan disetel ulang, sehingga menghapus semua datanya."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Ponsel ini akan disetel ulang, sehingga menghapus semua datanya."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Sudah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, pengguna ini akan dihapus, sehingga semua data pengguna akan dihapus."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Sudah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, pengguna ini akan dihapus, sehingga semua data pengguna akan dihapus."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Profil kerja akan dihapus, sehingga menghapus semua data profil."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Profil kerja akan dihapus, sehingga menghapus semua data profil."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka. Setelah gagal <xliff:g id="NUMBER_1">%2$d</xliff:g> kali lagi, Anda akan diminta membuka kunci tablet menggunakan akun email.\n\n Coba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka. Setelah gagal <xliff:g id="NUMBER_1">%2$d</xliff:g> kali lagi, Anda akan diminta membuka kunci ponsel menggunakan akun email.\n\n Coba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Kode PIN SIM salah. Hubungi operator untuk membuka kunci perangkat."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">Kode PIN SIM salah, sisa, sisa <xliff:g id="NUMBER_1">%d</xliff:g> percobaan.</item>
diff --git a/packages/SystemUI/res-keyguard/values-is/strings.xml b/packages/SystemUI/res-keyguard/values-is/strings.xml
index bece625..4f87df6 100644
--- a/packages/SystemUI/res-keyguard/values-is/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-is/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Ýttu á valmyndarhnappinn til að taka úr lás."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Net læst"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Ekkert SIM-kort"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Ekkert SIM-kort í spjaldtölvunni."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Ekkert SIM-kort í símanum."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Settu SIM-kort í."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM-kort vantar eða það er ekki læsilegt. Settu SIM-kort í."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Ónothæft SIM-kort."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Sláðu in PIN-númer sem er 4 til 8 tölustafir."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-númerið verður að vera 8 tölustafir eða lengra."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Prófaðu aftur að setja inn rétt PUK-númer. Endurteknar tilraunir gera SIM-kortið varanlega óvirkt."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-númerin stemma ekki"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Of margar tilraunir til að teikna mynstur"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Þú hefur slegið inn rangt PIN-númer <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. \n\nReyndu aftur eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> sekúndur."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Þú hefur slegið inn rangt aðgangsorð <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. \n\nReyndu aftur eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> sekúndur."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. \n\nReyndu aftur eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> sekúndur."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Þú hefur gert <xliff:g id="NUMBER_0">%1$d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður spjaldtölvan endurstillt, með þeim afleiðingum að öllum gögnum hennar verður eytt."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Þú hefur gert <xliff:g id="NUMBER_0">%1$d</xliff:g> árangurslausar tilraunir til að opna símann. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður síminn endurstilltur, með þeim afleiðingum að öllum gögnum hans verður eytt."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Spjaldtölvan verður endurstillt, með þeim afleiðingum að öllum gögnum hennar verður eytt."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna símann. Síminn verður endurstilltur, með þeim afleiðingum að öllum gögnum hans verður eytt."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Þú hefur gert <xliff:g id="NUMBER_0">%1$d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður notandinn fjarlægður með þeim afleiðingum að öllum notandagögnum verður eytt."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Þú hefur gert <xliff:g id="NUMBER_0">%1$d</xliff:g> árangurslausar tilraunir til að opna símann. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður notandinn fjarlægður með þeim afleiðingum að öllum notandagögnum verður eytt."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Vinnusniðið verður fjarlægt, með þeim afleiðingum að öllum gögnum þess verður eytt."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna símann. Vinnusniðið verður fjarlægt, með þeim afleiðingum að öllum gögnum þess verður eytt."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður þú beðin(n) um að opna spjaldtölvuna með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%3$d</xliff:g> sekúndur."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verðurðu beðin(n) um að opna símann með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%3$d</xliff:g> sekúndur."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Rangt PIN-númer SIM-korts. Nú þarftu að hafa samband við símafyrirtækið til að opna fyrir tækið."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">Rangt PIN-númer SIM-korts. Þú átt <xliff:g id="NUMBER_1">%d</xliff:g> tilraun eftir.</item>
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index cd27ba4..f714bf7 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Premi Menu per sbloccare."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rete bloccata"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Nessuna SIM"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nessuna scheda SIM presente nel tablet."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Nessuna scheda SIM presente nel telefono."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Inserisci una scheda SIM."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Scheda SIM mancante o non leggibile. Inserisci una scheda SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Scheda SIM inutilizzabile."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Il PIN deve essere di 4-8 numeri."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Il codice PUK dovrebbe avere almeno otto numeri."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Inserisci di nuovo il codice PUK corretto. Ripetuti tentativi comportano la disattivazione definitiva della scheda SIM."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"I codici PIN non corrispondono"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Troppi tentativi di inserimento della sequenza"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Hai digitato il tuo PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> volte in modo errato. \n\nRiprova tra <xliff:g id="NUMBER_1">%2$d</xliff:g> secondi."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Hai digitato la tua password <xliff:g id="NUMBER_0">%1$d</xliff:g> volte in modo errato. \n\nRiprova tra <xliff:g id="NUMBER_1">%2$d</xliff:g> secondi."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. \n\nRiprova tra <xliff:g id="NUMBER_1">%2$d</xliff:g> secondi."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER_0">%1$d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, il tablet verrà ripristinato e verranno quindi eliminati tutti i relativi dati."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER_0">%1$d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, il telefono verrà ripristinato e verranno quindi eliminati tutti i relativi dati."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il tablet verrà ripristinato e verranno quindi eliminati tutti i relativi dati."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il telefono verrà ripristinato e verranno quindi eliminati tutti i relativi dati."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER_0">%1$d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, questo utente verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER_0">%1$d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, questo utente verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il profilo di lavoro verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il profilo di lavoro verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il tablet con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%3$d</xliff:g> secondi."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%3$d</xliff:g> secondi."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Codice PIN della SIM errato. Devi contattare l\'operatore per sbloccare il dispositivo."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">Codice PIN della SIM errato. Hai ancora <xliff:g id="NUMBER_1">%d</xliff:g> tentativi a disposizione.</item>
diff --git a/packages/SystemUI/res-keyguard/values-iw/strings.xml b/packages/SystemUI/res-keyguard/values-iw/strings.xml
index d7156370..2af5192 100644
--- a/packages/SystemUI/res-keyguard/values-iw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-iw/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"לחץ על \'תפריט\' כדי לבטל את הנעילה."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"הרשת נעולה"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"‏אין כרטיס SIM"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"‏אין כרטיס SIM בטאבלט."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"‏אין כרטיס SIM בטלפון."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"‏הכנס כרטיס SIM."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"‏כרטיס ה-SIM חסר או שלא ניתן לקרוא אותו. הכנס כרטיס SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"‏לא ניתן להשתמש בכרטיס SIM זה."</string>
@@ -85,17 +83,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"הקלד קוד גישה שאורכו 4 עד 8 ספרות."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"‏קוד PUK צריך להיות בן 8 ספרות או יותר."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"‏הזן את קוד ה-PUK הנכון. ניסיונות חוזרים ישביתו את כרטיס ה-SIM לצמיתות."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"קודי הגישה אינם תואמים"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"ניסית לשרטט את קו ביטול הנעילה יותר מדי פעמים"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"הקלדת קוד גישה שגוי <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. \n\nנסה שוב בעוד <xliff:g id="NUMBER_1">%2$d</xliff:g> שניות."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"הקלדת סיסמה שגויה <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים.\n\nנסה שוב בעוד <xliff:g id="NUMBER_1">%2$d</xliff:g> שניות."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"שרטטת קו ביטול נעילה שגוי <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. \n\nנסה שוב בעוד <xliff:g id="NUMBER_1">%2$d</xliff:g> שניות."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ניסית לבטל את נעילת הטאבלט <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, טאבלט זה יאופס וכל הנתונים שבו יימחקו."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, טלפון זה יאופס וכל הנתונים שבו יימחקו."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ניסית לבטל את נעילת הטאבלט <xliff:g id="NUMBER">%d</xliff:g> פעמים. הטאבלט יאופס וכל הנתונים שלו יימחקו."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER">%d</xliff:g> פעמים. הטלפון יאופס וכל הנתונים שבו יימחקו."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ניסית לבטל את נעילת הטאבלט <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, משתמש זה יוסר וכל נתוני המשתמש יימחקו."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, משתמש זה יוסר וכל נתוני המשתמש יימחקו."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -104,10 +95,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ניסית לבטל את נעילת הטאבלט <xliff:g id="NUMBER">%d</xliff:g> פעמים. פרופיל העבודה יוסר וכל נתוני הפרופיל יימחקו."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER">%d</xliff:g> פעמים. פרופיל העבודה יוסר וכל נתוני הפרופיל יימחקו."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"שרטטת קו ביטול נעילה שגוי <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילת הטאבלט באמצעות חשבון אימייל‏.\n\nנסה שוב בעוד <xliff:g id="NUMBER_2">%3$d</xliff:g> שניות."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"שרטטת קו ביטול נעילה שגוי <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילת הטלפון באמצעות חשבון אימייל‏.\n\n נסה שוב בעוד <xliff:g id="NUMBER_2">%3$d</xliff:g> שניות."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"‏קוד הגישה של כרטיס ה-SIM שגוי. צור קשר עם הספק כדי לבטל את נעילת המכשיר."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="two">‏קוד הגישה של כרטיס ה-SIM שגוי. נותרו לך עוד <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות.</item>
diff --git a/packages/SystemUI/res-keyguard/values-ja/strings.xml b/packages/SystemUI/res-keyguard/values-ja/strings.xml
index 3ed6fec..5f0d83f 100644
--- a/packages/SystemUI/res-keyguard/values-ja/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ja/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"メニューからロックを解除できます。"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"ネットワークがロックされました"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM カードなし"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"タブレットに SIM カードが挿入されていません。"</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"スマートフォンに SIM カードが挿入されていません。"</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM カードを挿入してください。"</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM カードが見つからないか読み取れません。SIM カードを挿入してください。"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM カードは使用できません。"</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"PIN は 4~8 桁の数字で入力してください。"</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK コードは 8 桁以下の数字で入力してください。"</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"正しい PUK コードを再入力してください。誤入力を繰り返すと、SIM が完全に無効になる恐れがあります。"</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN コードが一致しません"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"パターンの入力を所定の回数以上間違えました"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"PIN の入力を <xliff:g id="NUMBER_0">%1$d</xliff:g> 回間違えました。\n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後にもう一度お試しください。"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"パスワードの入力を <xliff:g id="NUMBER_0">%1$d</xliff:g> 回間違えました。\n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後にもう一度お試しください。"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"ロック解除パターンの入力を <xliff:g id="NUMBER_0">%1$d</xliff:g> 回間違えました。\n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後にもう一度お試しください。"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"タブレットのロック解除に <xliff:g id="NUMBER_0">%1$d</xliff:g> 回失敗しました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回失敗すると、このタブレットはリセットされ、データはすべて消去されます。"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"スマートフォンのロック解除に <xliff:g id="NUMBER_0">%1$d</xliff:g> 回失敗しました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回失敗すると、このスマートフォンはリセットされ、データはすべて消去されます。"</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"タブレットのロック解除に <xliff:g id="NUMBER">%d</xliff:g> 回失敗しました。このタブレットはリセットされ、データはすべて消去されます。"</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"スマートフォンのロック解除に <xliff:g id="NUMBER">%d</xliff:g> 回失敗しました。このスマートフォンはリセットされ、データはすべて消去されます。"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"タブレットのロック解除に <xliff:g id="NUMBER_0">%1$d</xliff:g> 回失敗しました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回失敗すると、このユーザーは削除され、ユーザー データはすべて消去されます。"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"スマートフォンのロック解除に <xliff:g id="NUMBER_0">%1$d</xliff:g> 回失敗しました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回失敗すると、このユーザーは削除され、ユーザー データはすべて消去されます。"</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"タブレットのロック解除に <xliff:g id="NUMBER">%d</xliff:g> 回失敗しました。仕事用プロファイルは削除され、プロファイルのデータはすべて消去されます。"</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"スマートフォンのロック解除に <xliff:g id="NUMBER">%d</xliff:g> 回失敗しました。仕事用プロファイルは削除され、プロファイルのデータはすべて消去されます。"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ロック解除パターンの入力を <xliff:g id="NUMBER_0">%1$d</xliff:g> 回間違えました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回間違えると、タブレットのロック解除にメール アカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後にもう一度お試しください。"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ロック解除パターンの入力を <xliff:g id="NUMBER_0">%1$d</xliff:g> 回間違えました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回間違えると、スマートフォンのロック解除にメール アカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後にもう一度お試しください。"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM PIN コードが無効です。お使いのデバイスをロック解除するには携帯通信会社にお問い合わせいただく必要があります。"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">SIM PIN コードが無効です。入力できるのはあと <xliff:g id="NUMBER_1">%d</xliff:g> 回です。</item>
diff --git a/packages/SystemUI/res-keyguard/values-ka/strings.xml b/packages/SystemUI/res-keyguard/values-ka/strings.xml
index cf170e4..cd1719b 100644
--- a/packages/SystemUI/res-keyguard/values-ka/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ka/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"განსაბლოკად დააჭირეთ მენიუს."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"ქსელი ჩაკეტილია"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM ბარათი არ არის"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ტაბლეტში არ არის SIM ბარათი."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ტელეფონში არ არის SIM ბარათი."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"ჩადეთ SIM ბარათი."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM ბარათი არ არის ან არ იკითხება. ჩადეთ SIM ბარათი."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM ბარათი გამოუსადეგარია."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"აკრიფეთ 4-8 ციფრისგან შემდგარი PIN-კოდი."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-კოდი 8 ან მეტი ციფრისგან უნდა შედგებოდეს."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"ხელახლა შეიყვანეთ სწორი PUK-კოდი. რამდენიმე წარუმატებელი მცდელობის შემთხვევაში, SIM ბარათი სამუდამოდ გამოუსადეგარი გახდება."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-კოდები არ ემთხვევა"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"ნიმუში დახატულია არასწორად მეტისმეტად ბევრჯერ"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"თქვენ არასწორად შეიყვანეთ PIN-კოდი <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. \n\nცადეთ ხელახლა <xliff:g id="NUMBER_1">%2$d</xliff:g> წამში."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"თქვენ არასწორად აკრიფეთ პაროლი <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. \n\nცადეთ ხელახლა <xliff:g id="NUMBER_1">%2$d</xliff:g> წამში."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"თქვენ არასწორად დახატეთ განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. \n\nცადეთ ხელახლა <xliff:g id="NUMBER_1">%2$d</xliff:g> წამში."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"თქვენ არასწორად ცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ამ ტაბლეტის გადაყენება განხორციელდება, რაც მისი მონაცემების მთლიანად წაშლას გამოიწვევს."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"თქვენ არასწორად ცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ამ ტელეფონის გადაყენება განხორციელდება, რაც მისი მონაცემების მთლიანად წაშლას გამოიწვევს."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"თქვენ არასწორად ცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g>-ჯერ. ამის გამო, ამ ტაბლეტის გადაყენება განხორციელდება, რაც მისი მონაცემების მთლიანად წაშლას გამოიწვევს."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"თქვენ არასწორად ცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g>-ჯერ. ამის გამო, ამ ტელეფონის გადაყენება განხორციელდება, რაც მისი მონაცემების მთლიანად წაშლას გამოიწვევს."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"თქვენ არასწორად ცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ეს მომხმარებელი ამოიშლება, რაც მომხმარებლის ყველა მონაცემის წაშლას გამოიწვევს."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"თქვენ არასწორად ცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ეს მომხმარებელი ამოიშლება, რაც მომხმარებლის ყველა მონაცემის წაშლას გამოიწვევს."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"თქვენ არასწორად ცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g>-ჯერ. ამის გამო, სამსახურის პროფილი ამოიშლება, რაც პროფილის ყველა მონაცემის წაშლას გამოიწვევს."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"თქვენ არასწორად ცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g>-ჯერ. ამის გამო, სამსახურის პროფილი ამოიშლება, რაც პროფილის ყველა მონაცემის წაშლას გამოიწვევს."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ტაბლეტის განბლოკვა თქვენი ელფოსტის ანგარიშის მეშვეობით მოგიწევთ.\n\n ცადეთ ხელახლა <xliff:g id="NUMBER_2">%3$d</xliff:g> წამში."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ტელეფონის განბლოკვა თქვენი ელფოსტის ანგარიშის მეშვეობით მოგიწევთ.\n\n ცადეთ ხელახლა <xliff:g id="NUMBER_2">%3$d</xliff:g> წამში."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM ბარათის PIN-კოდი არასწორია. ახლა თქვენი მოწყობილობის განსაბლოკად თქვენს ოპერატორთან დაკავშირება მოგიწევთ."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">SIM ბარათის PIN-კოდი არასწორია. თქვენ დაგრჩათ <xliff:g id="NUMBER_1">%d</xliff:g> მცდელობა.</item>
diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml
index 53c1138..0b78b57 100644
--- a/packages/SystemUI/res-keyguard/values-kk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Ашу үшін \"Мәзір\" пернесін басыңыз."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Желі құлыптаулы"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM картасы салынбаған"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Планшетте SIM картасы жоқ."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Телефонда SIM картасы жоқ."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM картасын енгізіңіз."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM картасы жоқ немесе оқылмайды. SIM картасын салыңыз."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM картасы қолданыстан шыққан."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4-8 саннан тұратын PIN кодын енгізіңіз."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK коды 8 не одан көп саннан тұруы қажет."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Дұрыс PUK кодын қайта енгізіңіз. Әрекетті қайталай берсеңіз, SIM картасы өшіріледі."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN коды сәйкес келмейді"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Тым көп өрнек енгізу әрекеті жасалды"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"PIN коды <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате енгізілді. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секундтан кейін әркетті қайталаңыз."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Құпия сөз <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате енгізілді. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секундтан кейін әрекетті қайталаңыз."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Құлыпты ашу өрнегі <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате енгізілді. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секундтан кейін әрекетті қайталаңыз."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Планшет құлпын ашуға <xliff:g id="NUMBER_0">%1$d</xliff:g> рет сәтсіз әрекет жасалды. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін осы планшет бастапқы күйіне қайтарылып, оның бүкіл деректері жойылады."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Телефон құлпын ашуға <xliff:g id="NUMBER_0">%1$d</xliff:g> рет сәтсіз әрекет жасалды. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін осы телефон бастапқы күйіне қайтарылып, оның бүкіл деректері жойылады."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Планшет құлпын ашуға <xliff:g id="NUMBER">%d</xliff:g> рет сәтсіз әрекет жасалды. Осы планшет бастапқы күйіне қайтарылып, оның бүкіл деректері жойылады."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Телефон құлпын ашуға <xliff:g id="NUMBER">%d</xliff:g> рет сәтсіз әрекет жасалды. Осы телефон бастапқы күйіне қайтарылып, оның бүкіл деректері жойылады."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Планшет құлпын ашуға <xliff:g id="NUMBER_0">%1$d</xliff:g> рет сәтсіз әрекет жасалды. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін пайдаланушы өшіріліп, оның бүкіл деректері жойылады."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Телефон құлпын ашуға <xliff:g id="NUMBER_0">%1$d</xliff:g> рет сәтсіз әрекет жасалды. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін пайдаланушы өшіріліп, оның бүкіл деректері жойылады."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Планшет құлпын ашуға <xliff:g id="NUMBER">%d</xliff:g> рет сәтсіз әрекет жасалды. Жұмыс профилі өшіріліп, оның бүкіл деректері жойылады."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Телефон құлпын ашуға <xliff:g id="NUMBER">%d</xliff:g> рет сәтсіз әрекет жасалды. Жұмыс профилі өшіріліп, оның бүкіл деректері жойылады."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Құлыпты ашу өрнегі <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате енгізілді. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін планшетті есептік жазба арқылы ашу сұралады. \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін әрекетті қайталаңыз."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Құлыпты ашу өрнегі <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате енгізілді. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін телефонды есептік жазба арқылы ашу сұралады. \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін әрекетті қайталаңыз."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM PIN коды дұрыс емес, операторға хабарласып, құрылғының құлпын ашуды сұраңыз."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">SIM PIN коды дұрыс емес. <xliff:g id="NUMBER_1">%d</xliff:g> әрекет қалды.</item>
diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml
index 0e4b418..a07c299 100644
--- a/packages/SystemUI/res-keyguard/values-km/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-km/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"ចុចម៉ឺនុយ ​ដើម្បី​ដោះ​សោ។"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"បណ្ដាញ​ជាប់​សោ"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"គ្មាន​ស៊ីម​កាត​ទេ"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"គ្មាន​ស៊ីម​កាត​នៅ​ក្នុង​ថេប្លេត​ទេ។"</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"គ្មាន​ស៊ីមកាត​នៅ​ក្នុង​ទូរសព្ទ​ទេ។"</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"ស៊ក​បញ្ចូល​ស៊ីម​កាត​។"</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"ស៊ីមកាត​បាន​បាត់ ឬ​មិន​អាច​អាន​បាន។ សូម​ស៊ក​បញ្ចូល​ស៊ីម​កាត។"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"ស៊ី​ម​កាត​មិន​អាច​ប្រើ​បាន​ទេ។"</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"វាយ​បញ្ចូល​កូដ PIN ​ចន្លោះពី 4 ទៅ 8 ខ្ទង់"</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"កូដ PUK គួរ​តែ​មាន​លេខ 8 ខ្ទង់ ឬ​ច្រើន​ជាង​នេះ។"</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"សូម​បញ្ចូល​កូដ PUK ម្ដង​ទៀត។ ការ​ព្យាយាម​ដដែល​ច្រើន​ដង​នឹង​បិទ​ដំណើរការ​ស៊ីម​នេះ​ជា​អចិន្ត្រៃយ៍។"</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"កូដ PIN មិន​ត្រូវ​គ្នា​ទេ"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"ការព្យាយាម​បញ្ចូល​លំនាំ​ច្រើន​ដង​ពេកហើយ"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"អ្នក​បាន​វាយ​បញ្ចូល​កូដ PIN របស់​អ្នក​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដង​ហើយ។ \n\nសូម​ព្យាយាម​ម្ដង​ទៀត​ក្នុង​រយៈ​ពេល <xliff:g id="NUMBER_1">%2$d</xliff:g> វិនាទី​ទៀត។"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"អ្នក​បាន​វាយ​បញ្ចូល​ពាក្យ​សម្ងាត់​របស់​អ្នក​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដង​ហើយ។ \n\nសូម​ព្យាយាម​ម្ដង​ទៀត​ក្នុង​រយៈ​ពេល <xliff:g id="NUMBER_1">%2$d</xliff:g> វិនាទី​ទៀត។"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"អ្នក​បាន​គូរ​លំនាំ​ដោះ​សោ​របស់​អ្នក​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដង​ហើយ។ \n\nសូមព្យាយាម​ម្ដង​ទៀត​ក្នុង​រយៈ​ពេល <xliff:g id="NUMBER_1">%2$d</xliff:g> វិនាទី​ទៀត។"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"អ្នក​បាន​ព្យាយាម​ដោះសោ​ថេប្លេត​នេះ​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដង​ហើយ។ ប្រសិន​បើ​ការ​ព្យាយាម​ដោះ​សោ​ចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀត​មិន​ទទួល​បាន​ជោគជ័យទេ ថេប្លេត​នេះ​នឹង​ត្រូវ​បាន​កំណត់​ឡើងវិញ ហើយ​វា​នឹង​លុប​ទិន្នន័យ​របស់វា​ទាំងអស់។"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"អ្នក​បាន​ព្យាយាម​ដោះសោ​ទូរសព្ទ​នេះ​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដង​ហើយ។ ប្រសិន​បើ​ការ​ព្យាយាម​ដោះ​សោ​ចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀត​មិន​ទទួល​បាន​ជោគជ័យទេ ទូរសព្ទ​នេះ​នឹង​ត្រូវ​បាន​កំណត់​ឡើងវិញ ហើយ​វា​នឹង​លុប​ទិន្នន័យ​របស់វា​ទាំងអស់។"</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"អ្នក​បាន​ព្យាយាម​ដោះសោ​ថេប្លេត​នេះ​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER">%d</xliff:g> ដង។ ថេប្លេត​នេះ​នឹង​ត្រូវ​បាន​កំណត់​ឡើងវិញ ហើយ​វា​នឹង​លុប​ទិន្នន័យ​ទាំងអស់​របស់​វា។"</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"អ្នក​បាន​ព្យាយាម​ដោះសោ​ទូរសព្ទ​នេះ​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER">%d</xliff:g> ដង​ហើយ។ ទូរសព្ទ​នេះ​នឹង​ត្រូវ​បាន​កំណត់​ឡើងវិញ ហើយ​វា​នឹង​លុប​ទិន្នន័យ​ទាំងអស់​របស់​វា។"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"អ្នក​បាន​ព្យាយាម​ដោះ​សោ​ថេប្លេត​នេះ​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដង​ហើយ។ ប្រសិន​បើ​ការ​ព្យាយាម​ដោះ​សោ​ចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀត​មិន​ទទួល​បាន​ជោគជ័យទេ អ្នក​ប្រើប្រាស់​នេះនឹង​ត្រូវ​បាន​លុប ហើយ​វា​នឹង​លុប​ទិន្នន័យ​របស់​អ្នក​ប្រើប្រាស់​ទាំងអស់។"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"អ្នក​បាន​ព្យាយាម​ដោះ​សោ​ទូរសព្ទ​នេះ​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដង​ហើយ។ ប្រសិន​បើ​ការ​ព្យាយាមដោះសោ​ចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀត​មិន​ទទួល​បាន​ជោគជ័យទេ អ្នក​ប្រើប្រាស់​នេះនឹង​ត្រូវ​បាន​លុប ហើយ​វា​នឹង​លុប​ទិន្នន័យ​របស់​អ្នក​ប្រើប្រាស់​ទាំងអស់។"</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"អ្នក​បាន​ព្យាយាម​ដោះសោ​ថេប្លេត​នេះ​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER">%d</xliff:g> ដង​ហើយ។ កម្រង​ព័ត៌មាន​ការងារ​នេះ​នឹង​ត្រូវ​បាន​លុប ហើយ​វា​នឹង​លុប​ទិន្នន័យ​កម្រង​ព័ត៌មាន​ទាំងអស់។"</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"អ្នក​បាន​ព្យាយាម​ដោះសោ​ទូរសព្ទ​នេះ​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER">%d</xliff:g> ដង​ហើយ។ កម្រង​ព័ត៌មាន​ការងារ​នេះ​នឹង​ត្រូវ​បាន​លុប ហើយ​វា​នឹង​លុប​ទិន្នន័យ​កម្រង​ព័ត៌មាន​ទាំងអស់។"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"អ្នក​បាន​គូរ​លំនាំ​ដោះ​សោ​របស់​អ្នក​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដង​ហើយ។ ប្រសិន​បើ​ការ​ព្យាយាម​ដោះ​សោ​ចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀត​មិន​ទទួល​បាន​ជោគជ័យទេ អ្នក​នឹង​ត្រូវ​បាន​ស្នើ​ឲ្យ​ដោះ​សោ​ថេប្លេត​របស់​អ្នក​ ដោយ​ប្រើ​គណនី​អ៊ីមែល។\n\n សូមព្យាយាម​ម្ដង​ទៀត​ក្នុង​រយៈ​ពេល <xliff:g id="NUMBER_2">%3$d</xliff:g> វិនាទី​ទៀត។"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"អ្នក​បាន​គូរ​លំនាំ​ដោះ​សោ​របស់​អ្នក​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដង​ហើយ។ ប្រសិន​បើ​ការ​ព្យាយាម​ដោះ​សោ​ចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀត​មិន​ទទួល​បាន​ជោគជ័យទេ អ្នក​នឹង​ត្រូវ​បាន​ស្នើ​ឲ្យ​ដោះ​សោ​ទូរសព្ទ​របស់​អ្នក​ ដោយ​ប្រើ​គណនី​អ៊ីមែល។\n\n សូម​ព្យាយាម​ម្ដង​ទៀត​ក្នុង​រយៈ​ពេល <xliff:g id="NUMBER_2">%3$d</xliff:g> វិនាទី​ទៀត។"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"កូដ PIN របស់​ស៊ីម​មិន​ត្រឹមត្រូវ​ទេ អ្នក​ត្រូវ​ទាក់ទង​ទៅក្រុមហ៊ុន​បម្រើ​សេវា​ទូរសព្ទ​របស់​អ្នក​ឥឡូវ​នេះ ដើម្បី​ដោះ​សោ​ឧបករណ៍​របស់​អ្នក។"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">កូដ PIN របស់​ស៊ីម​មិន​ត្រឹមត្រូវ​ទេ អ្នក​អាច​ព្យាយាម​បាន <xliff:g id="NUMBER_1">%d</xliff:g> ដងទៀត។</item>
diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml
index 1d162e8..2c88419 100644
--- a/packages/SystemUI/res-keyguard/values-kn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"ಅನ್‌ಲಾಕ್ ಮಾಡಲು ಮೆನು ಒತ್ತಿರಿ."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"ನೆಟ್‌ವರ್ಕ್ ಲಾಕ್ ಆಗಿದೆ"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"ಸಿಮ್‌ ಕಾರ್ಡ್ ಇಲ್ಲ"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ಟ್ಯಾಬ್ಲೆಟ್‌ನಲ್ಲಿ ಸಿಮ್‌ ಕಾರ್ಡ್ ಇಲ್ಲ."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ಪೋನ್‌ನಲ್ಲಿ ಯಾವುದೇ ಸಿಮ್‌ ಕಾರ್ಡ್ ಇಲ್ಲ."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"ಸಿಮ್‌ ಕಾರ್ಡ್ ಸೇರಿಸಿ."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"ಸಿಮ್‌ ಕಾರ್ಡ್ ಇಲ್ಲ ಅಥವಾ ಗುರುತಿಸಲು ಅಸಾಧ್ಯ. ಒಂದು ಸಿಮ್‌ ಕಾರ್ಡ್ ಸೇರಿಸಿ."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"ನಿಷ್ಪ್ರಯೋಜಕ ಸಿಮ್‌ ಕಾರ್ಡ್."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4 ರಿಂದ 8 ಸಂಖ್ಯೆಗಳಿರುವ ಪಿನ್‌ ಟೈಪ್ ಮಾಡಿ."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK ಕೋಡ್ 8 ಅಥವಾ ಹೆಚ್ಚು ಸಂಖ್ಯೆಗಳನ್ನು ಹೊಂದಿರಬೇಕು."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"ಸರಿಯಾದ PUK ಕೋಡ್ ಮರು-ನಮೂದಿಸಿ. ಸತತ ಪ್ರಯತ್ನಗಳು ಸಿಮ್‌ ಅನ್ನು ಶಾಶ್ವತವಾಗಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ಪಿನ್‌ ಕೋಡ್‍ಗಳು ಹೊಂದಾಣಿಕೆಯಾಗುತ್ತಿಲ್ಲ"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"ಪ್ಯಾಟರ್ನ್ ಪ್ರಯತ್ನಗಳ ಮಿತಿ ಮುಗಿದಿದೆ"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"ನಿಮ್ಮ ಪಿನ್‌ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಟೈಪ್ ಮಾಡಿದ್ದೀರಿ. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"ನಿಮ್ಮ ಪಾಸ್‍‍ವರ್ಡ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ನಮೂದಿಸಿದ್ದೀರಿ. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"ನಿಮ್ಮ ಅನ್‍‍ಲಾಕ್ ಪ್ಯಾಟರ್ನ್‌ ಅನ್ನು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಎಳೆದಿದ್ದೀರಿ. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ಫೋನ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಫೋನ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಈ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲಾಗುತ್ತದೆ, ಇದು ಅದರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ಫೋನ್  ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಈ ಫೋನ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲಾಗುತ್ತದೆ, ಇದು ಅದರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಬಳಕೆದಾರರನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಬಳಕೆದಾರರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ಫೋನ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಬಳಕೆದಾರರನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಬಳಕೆದಾರರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಪ್ರೊಫೈಲ್ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ಫೋನ್ ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಪ್ರೊಫೈಲ್ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ನಿಮ್ಮ ಅನ್‍‍ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಎಳೆದಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ನಿಮ್ಮ ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್‌ಲಾಕ್ ಮಾಡುವಂತೆ ನಿಮ್ಮಲ್ಲಿ ಕೇಳಿಕೊಳ್ಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ನಿಮ್ಮ ಅನ್‍‍ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಎಳೆದಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ನಿಮ್ಮ ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿ ಫೋನ್ ಅನ್‌ಲಾಕ್ ಮಾಡುವಂತೆ ನಿಮ್ಮಲ್ಲಿ ಕೇಳಿಕೊಳ್ಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"ಸಿಮ್‌ ಪಿನ್‌ ಕೋಡ್‌ ತಪ್ಪಾಗಿದೆ, ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅನ್‌ಲಾಕ್‌ ಮಾಡಲು ನೀವು ಈ ಕೂಡಲೇ ನಿಮ್ಮ ವಾಹಕವನ್ನು ಸಂಪರ್ಕಿಸಬೇಕು."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">ಸಿಮ್‌ ಪಿನ್ ಕೋಡ್‌ ತಪ್ಪಾಗಿದೆ, ನಿಮಗೆ <xliff:g id="NUMBER_1">%d</xliff:g> ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ.</item>
diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml
index c0fb716..bdbd3d9 100644
--- a/packages/SystemUI/res-keyguard/values-ko/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"잠금 해제하려면 메뉴를 누르세요."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"네트워크 잠김"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM 카드 없음"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"태블릿에 SIM 카드가 없습니다."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"휴대전화에 SIM 카드가 없습니다."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM 카드를 삽입하세요."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM 카드가 없거나 읽을 수 없는 상태입니다. SIM 카드를 삽입하세요."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"사용할 수 없는 SIM 카드입니다."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4~8자리 숫자로 된 PIN을 입력하세요."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK 코드는 8자리 이상의 숫자여야 합니다."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"올바른 PUK 코드를 다시 입력하세요. 입력을 반복해서 시도하면 SIM이 영구적으로 사용 중지됩니다."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN 코드가 일치하지 않음"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"패턴 그리기를 너무 많이 시도함"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"PIN을 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 잘못 입력했습니다. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g>초 후에 다시 시도하세요."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"비밀번호를 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 잘못 입력했습니다. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g>초 후에 다시 시도하세요."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 잘못 그렸습니다. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g>초 후에 다시 시도하세요."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"태블릿 잠금 해제에 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 태블릿이 재설정되며 모든 데이터가 삭제됩니다."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"휴대전화 잠금 해제에 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 휴대전화가 재설정되며 모든 데이터가 삭제됩니다."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"태블릿 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 태블릿이 재설정되며 모든 데이터가 삭제됩니다."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"휴대전화 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 휴대전화가 재설정되며 모든 데이터가 삭제됩니다."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"태블릿 잠금 해제에 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 이 사용자와 모든 사용자 데이터가 삭제됩니다."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"휴대전화 잠금 해제에 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 이 사용자와 모든 사용자 데이터가 삭제됩니다."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"태블릿 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 직장 프로필과 모든 프로필 데이터가 삭제됩니다."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"휴대전화 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 직장 프로필과 모든 프로필 데이터가 삭제됩니다."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 잘못 그렸습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 이메일 계정을 사용하여 태블릿을 잠금 해제해야 합니다.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g>초 후에 다시 시도해 주세요."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 잘못 그렸습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 이메일 계정을 사용하여 휴대전화를 잠금 해제해야 합니다.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g>초 후에 다시 시도해 주세요."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"잘못된 SIM PIN코드입니다. 이동통신사에 문의하여 기기를 잠금 해제해야 합니다."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">잘못된 SIM PIN 코드입니다. 입력을 <xliff:g id="NUMBER_1">%d</xliff:g>번 더 시도할 수 있습니다.</item>
diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml
index 32a3346..8e9c794 100644
--- a/packages/SystemUI/res-keyguard/values-ky/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Кулпуну ачуу үчүн Менюну басыңыз."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Тармак кулпуланган"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM карта жок"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Планшетте SIM-карта жок."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Телефондо SIM-карта жок."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM-карта салыңыз."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM-карта жок же ал окулбай калган. SIM-карта салыңыз."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Жараксыз SIM-карта."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4–8 сандан турган PIN-кодду териңиз."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-код 8 же андан көп сандан турушу керек."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"PUK-кодду кайрадан туура киргизиңиз. Кайталанган аракеттер SIM-картаны биротоло жараксыз кылат."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-коддор дал келген жок"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Өтө көп графикалык ачкычты тартуу аракети болду"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"PIN-кодуңузду <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тердиңиз. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секунддан кийин дагы аракет кылып көрүңүз."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Сырсөзүңүздү <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тердиңиз. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секунддан кийин дагы аракет кылып көрүңүз."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Кулпуну ачуучу графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секунддан кийин дагы аракет кылып көрүңүз."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Планшеттин кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, бул планшет баштапкы абалга келтирилип, андагы бардык дайындар жок болот."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Телефондун кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, бул телефон баштапкы абалга келтирилип, андагы бардык дайындар жок болот."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Планшеттин кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Бул планшет баштапкы абалга келтирилип, андагы бардык дайындар жок болот."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Телефондун кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес аракет жасадыңыз. Бул телефон баштапкы абалга келтирилип, андагы бардык дайындар жок болот."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Планшеттин кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, бул колдонуучу чыгарылып салынып, колдонуучунун бардык дайындары жок болот."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Телефондун кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, бул колдонуучу чыгарылып салынып, колдонуучунун бардык дайындары жок болот."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Планшеттин кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Жумуш профили чыгарылып салынып, андагы бардык дайындар жок болот."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Телефондун кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Жумуш профили чыгарылып салынып, андагы бардык дайындар жок болот."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Сиз графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин планшетиңизди бөгөттөн электрондук почтаңыз аркылуу чыгарышыңыз талап кылынат.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секунддан кийин кайра аракеттениңиз."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Сиз графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин телефонуңузду бөгөттөн электрондук почтаңыз аркылуу чыгаруу талап кылынат.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секунддан кийин кайра аракеттениңиз."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM-картанын PIN-коду туура эмес. Эми түзмөктү бөгөттөн чыгаруу үчүн байланыш операторуңузга кайрылышыңыз керек."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">SIM-картанын PIN-коду туура эмес, сизде <xliff:g id="NUMBER_1">%d</xliff:g> аракет калды.</item>
diff --git a/packages/SystemUI/res-keyguard/values-lo/strings.xml b/packages/SystemUI/res-keyguard/values-lo/strings.xml
index 3683002..3ae088b 100644
--- a/packages/SystemUI/res-keyguard/values-lo/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lo/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"ກົດ \"ເມນູ\" ເພື່ອປົດລັອກ."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"ເຄືອຂ່າຍຖືກລັອກ"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"ບໍ່ມີຊິມກາດ"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ບໍ່ມີຊິມກາດໃນແທັບເລັດ."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ບໍ່ມີ SIM card ໃນໂທລະສັບ."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"ໃສ່ຊິມກາດ."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"ບໍ່ພົບເຫັນຊິມກາດ ຫຼືບໍ່ສາມາດອ່ານຊິມກາດໄດ້. ກະລຸນາໃສ່ຊິມກາດໃໝ່."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM card ບໍ່ສາມາດໃຊ້ໄດ້."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"ພິມລະຫັດ PIN ທີ່ມີ 4 ຫາ 8 ໂຕເລກ."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"ລະຫັດ PUK ຄວນມີຢ່າງໜ້ອຍ 8 ໂຕເລກ."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"ປ້ອນລະຫັດ PUK ທີ່ຖືກຕ້ອງຄືນໃໝ່. ການພະຍາຍາມໃສ່ຫຼາຍເທື່ອຈະເຮັດໃຫ້ຊິມກາດໃຊ້ບໍ່ໄດ້ຖາວອນ."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ລະຫັດ PIN ບໍ່ກົງກັນ"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"ແຕ້ມຮູບແບບປົດລັອກຫຼາຍເກີນໄປ"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"ທ່ານພິມລະຫັດ PIN ຂອງທ່ານຜິດ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. \n\nກະລຸນາລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ວິນາທີ."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"ທ່ານພິມລະຫັດຜ່ານຜິດ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. \n\nໃຫ້ລອງໃໝ່ອີກຄັ້ງໃນອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ວິນາທີ."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"ທ່ານແຕ້ມຮູບແບບປົດລັອກບໍ່ຖືກ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. \n\nລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ວິນາທີ."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER_0">%1$d</xliff:g> ຄັ້ງ. ຫຼັງຈາກລອງບໍ່ສຳເລັດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ຄັ້ງ, ແທັບເລັດນີ້ຈະຖືກຕັ້ງຄ່າໃໝ່, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຂອງມັນ."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER_0">%1$d</xliff:g> ຄັ້ງ. ຫຼັງຈາກລອງບໍ່ສຳເລັດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ຄັ້ງ, ໂທລະສັບນີ້ຈະຖືກຕັ້ງຄ່າໃໝ່, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຂອງມັນ."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ແທັບເລັດນີ້ຈະຖືກຕັ້ງຄ່າໃໝ່, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຂອງມັນ."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ໂທລະສັບນີ້ຈະຖືກຕັ້ງຄ່າໃໝ່, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຂອງມັນ."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER_0">%1$d</xliff:g> ຄັ້ງ. ຫຼັງຈາກລອງບໍ່ສຳເລັດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g>ຄັ້ງ, ຜູ້ໃຊ້ນີ້ຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຜູ້ໃຊ້."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER_0">%1$d</xliff:g> ຄັ້ງ. ຫຼັງຈາກລອງບໍ່ສຳເລັດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ຄັ້ງ, ຜູ້ໃຊ້ນີ້ຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຜູ້ໃຊ້."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນໂປຣໄຟລ໌."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນໂປຣໄຟລ໌."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຜິດ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກແຕ້ມຜິດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ເທື່ອ, ທ່ານຈະຖືກຖາມໃຫ້ປົດລັອກແທັບເລັດຂອງທ່ານ ດ້ວຍການເຂົ້າສູ່ລະບົບໂດຍໃຊ້ອີເມວຂອງທ່ານ.\n\n ກະລຸນາລອງໃໝ່ອີກຄັ້ງໃນອີກ <xliff:g id="NUMBER_2">%3$d</xliff:g> ວິນາທີ."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຂອງທ່ານຜິດ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກຄວາມພະຍາຍາມອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ເທື່ອ ທ່ານຈະຖືກຖາມໃຫ້ປົດລັອກໂທລະສັບຂອງທ່ານດ້ວຍບັນຊີອີເມວ.\n\n ລອງໃໝ່ອີກຄັ້ງໃນ <xliff:g id="NUMBER_2">%3$d</xliff:g> ວິນາທີ."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"ລະຫັດ PIN ຂອງ SIM ບໍ່ຖືກຕ້ອງທ່ານຕ້ອງຕິດຕໍ່ຫາຜູ່ໃຫ້ບໍລິການ ເພື່ອປົດລັອກອຸປະກອນຂອງທ່ານ."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">ລະຫັດ SIM PIN ບໍ່ຖືກຕ້ອງ, ທ່ານຍັງພະຍາຍາມໄດ້ອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ຄັ້ງ.</item>
diff --git a/packages/SystemUI/res-keyguard/values-lt/strings.xml b/packages/SystemUI/res-keyguard/values-lt/strings.xml
index 49812ce..3d637f0 100644
--- a/packages/SystemUI/res-keyguard/values-lt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lt/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Paspauskite meniu, jei norite atrakinti."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Tinklas užrakintas"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Nėra SIM kortelės"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Planšetiniame kompiuteryje nėra SIM kortelės."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefone nėra SIM kortelės."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Įdėkite SIM kortelę."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Nėra SIM kortelės arba ji neskaitoma. Įdėkite SIM kortelę."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Negalima naudoti SIM kortelės."</string>
@@ -85,17 +83,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Įveskite PIN kodą, sudarytą iš 4–8 skaičių."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK kodas turėtų būti sudarytas iš 8 ar daugiau skaitmenų."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Pakartotinai įveskite tinkamą PUK kodą. Pakartotinai bandant SIM kortelė bus išjungta visam laikui."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodai nesutampa"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Per daug atrakinimo piešinių bandymų"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. netinkamai įvedėte PIN kodą. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%2$d</xliff:g> sek."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. netinkamai įvedėte slaptažodį. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%2$d</xliff:g> sek."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. netinkamai nupiešėte atrakinimo piešinį. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%2$d</xliff:g> sek."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. šis planšetinis kompiuteris bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. šis telefonas bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Šis planšetinis kompiuteris bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Šis telefonas bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. šis naudotojas bus pašalintas ir visi naudotojo duomenys bus ištrinti."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. šis naudotojas bus pašalintas ir visi naudotojo duomenys bus ištrinti."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -104,10 +95,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Darbo profilis bus pašalintas ir visi profilio duomenys bus ištrinti."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Darbo profilis bus pašalintas ir visi profilio duomenys bus ištrinti."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. netinkamai nupiešėte atrakinimo piešinį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. būsite paprašyti atrakinti planšetinį kompiuterį naudodami el. pašto paskyrą.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. netinkamai nupiešėte atrakinimo piešinį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. būsite paprašyti atrakinti telefoną naudodami el. pašto paskyrą.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Netinkamas SIM kortelės PIN kodas. Reikės susisiekti su operatoriumi, kad atrakintų įrenginį."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">Netinkamas SIM kortelės PIN kodas. Liko <xliff:g id="NUMBER_1">%d</xliff:g> bandymas.</item>
diff --git a/packages/SystemUI/res-keyguard/values-lv/strings.xml b/packages/SystemUI/res-keyguard/values-lv/strings.xml
index 94244ac..2c24f4a 100644
--- a/packages/SystemUI/res-keyguard/values-lv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lv/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Lai atbloķētu, nospiediet izvēlnes ikonu."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Tīkls ir bloķēts."</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Nav SIM kartes."</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Planšetdatorā nav SIM kartes."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Tālrunī nav SIM kartes."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Ievietojiet SIM karti."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Nav SIM kartes, vai arī to nevar nolasīt. Ievietojiet SIM karti."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Nelietojama SIM karte."</string>
@@ -84,17 +82,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Ievadiet PIN kodu, kas sastāv no 4 līdz 8 cipariem."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK kodam ir jābūt vismaz 8 ciparus garam."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Atkārtoti ievadiet pareizo PUK kodu. Ja vairākas reizes ievadīsiet to nepareizi, SIM karte tiks neatgriezeniski atspējota."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodi neatbilst."</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Pārāk daudz kombinācijas mēģinājumu"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) esat ievadījis nepareizu PIN kodu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%2$d</xliff:g> sekundes(-ēm)."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) esat ievadījis nepareizu paroli.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%2$d</xliff:g> sekundes(-ēm)."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) esat nepareizi uzzīmējis atbloķēšanas kombināciju.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%2$d</xliff:g> sekundes(-ēm)."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt planšetdatoru. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) šis planšetdators tiks atiestatīts, kā arī visi planšetdatora dati tiks dzēsti."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt tālruni. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) šis tālrunis tiks atiestatīts, kā arī visi tālruņa dati tiks dzēsti."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt planšetdatoru. Šis planšetdators tiks atiestatīts, kā arī visi planšetdatora dati tiks dzēsti."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt tālruni. Šis tālrunis tiks atiestatīts, kā arī visi tālruņa dati tiks dzēsti."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt planšetdatoru. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) šis lietotājs tiks noņemts, kā arī visi lietotāja dati tiks dzēsti."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt tālruni. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) šis lietotājs tiks noņemts, kā arī visi lietotāja dati tiks dzēsti."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -103,10 +94,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt planšetdatoru. Darba profils tiks noņemts, kā arī visi profila dati tiks dzēsti."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt tālruni. Darba profils tiks noņemts, kā arī visi profila dati tiks dzēsti."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nepareizi norādījāt atbloķēšanas kombināciju. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) planšetdators būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundes(-ēm)."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nepareizi norādījāt atbloķēšanas kombināciju. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) tālrunis būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundes(-ēm)."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Nepareizs SIM kartes PIN kods. Lai atbloķētu ierīci, sazinieties ar mobilo sakaru operatoru."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="zero">Nepareizs SIM kartes PIN kods. Varat mēģināt vēl <xliff:g id="NUMBER_1">%d</xliff:g> reizes.</item>
diff --git a/packages/SystemUI/res-keyguard/values-mk/strings.xml b/packages/SystemUI/res-keyguard/values-mk/strings.xml
index 52528f7..d434bc4 100644
--- a/packages/SystemUI/res-keyguard/values-mk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mk/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Притиснете „Мени“ за отклучување."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Мрежата е заклучена"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Нема SIM-картичка"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Во таблетот нема SIM-картичка."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Во телефонот нема SIM-картичка."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Вметнете SIM-картичка."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Нема SIM-картичка или не може да се прочита. Вметнете SIM-картичка."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Неупотреблива SIM-картичка."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Внесете PIN што содржи 4 - 8 броеви."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-кодот треба да содржи 8 или повеќе броеви."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Повторно внесете го точниот PUK-код. Повторните обиди трајно ќе ја оневозможат SIM-картичката."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-кодовите не се совпаѓаат"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Премногу обиди со шема"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Погрешно сте го напишале вашиот PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. \n\nОбидете се повторно за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунди."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Погрешно сте ја напишале вашата лозинка <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. \n\nОбидете се повторно за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунди."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Погрешно сте ја нацртале вашата шема за отклучување <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. \n\nОбидете се повторно за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунди."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Неправилно се обидовте да го отклучите таблетот <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, таблетот ќе се ресетира, со што ќе се избришат сите негови податоци."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, телефонот ќе се ресетира, со што ќе се избришат сите негови податоци."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Неправилно се обидовте да го отклучите таблетот <xliff:g id="NUMBER">%d</xliff:g> пати. Овој таблет ќе се ресетира, со што ќе се избришат сите негови податоци."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER">%d</xliff:g> пати. Овој телефон ќе се ресетира, со што ќе се избришат сите негови податоци."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Неправилно се обидовте да го отклучите таблетот <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, корисникот ќе се отстрани, со што ќе се избришат сите негови податоци."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, корисникот ќе се отстрани, со што ќе се избришат сите податоци на корисникот."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Неправилно се обидовте да го отклучите таблетот <xliff:g id="NUMBER">%d</xliff:g> пати. Работниот профил ќе се отстрани, со што ќе се избришат сите податоци на профилот."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER">%d</xliff:g> пати. Работниот профил ќе се отстрани, со што ќе се избришат сите податоци на профилот."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Погрешно сте ја употребиле вашата шема на отклучување <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, ќе побараме да го отклучите таблетот со сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Погрешно сте ја употребиле вашата шема на отклучување <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, ќе побараме да го отклучите телефонот со сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Погрешен PIN-код за SIM, сега мора да контактирате со вашиот оператор за да го отклучите уредот."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">Погрешен PIN-код за SIM, ви преостанува уште <xliff:g id="NUMBER_1">%d</xliff:g> обид.</item>
diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml
index 5f3a8ca..3992e17 100644
--- a/packages/SystemUI/res-keyguard/values-ml/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"അൺലോക്കുചെയ്യാൻ മെനു അമർത്തുക."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"നെറ്റ്‌വർക്ക് ലോക്കുചെയ്‌തു"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"സിം കാർഡില്ല"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ടാബ്‌ലെറ്റിൽ സിം കാർഡൊന്നുമില്ല."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ഫോണിൽ സിം കാർഡൊന്നുമില്ല."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"ഒരു ‌സിം കാർഡ് ഇടുക."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"സിം കാർഡ് കാണുന്നില്ല, അല്ലെങ്കിൽ റീഡുചെയ്യാനായില്ല. ഒരു സിം കാർഡ് ഇടുക."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"ഉപയോഗയോഗ്യമല്ലാത്ത സിം കാർഡ്."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4 മുതൽ 8 വരെ അക്കങ്ങളുള്ള ഒരു പിൻ ടൈപ്പുചെയ്യുക."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK കോഡിൽ 8 അല്ലെങ്കിൽ അതിലധികം സംഖ്യകൾ ഉണ്ടായിരിക്കണം."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"ശരിയായ PUK കോഡ് വീണ്ടും നൽകുക. ആവർത്തിച്ചുള്ള ശ്രമങ്ങൾ സിം ശാശ്വതമായി പ്രവർത്തനരഹിതമാക്കും."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"പിൻ കോഡുകൾ പൊരുത്തപ്പെടുന്നില്ല"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"വളരെയധികം പാറ്റേൺ ശ്രമങ്ങൾ"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ പിൻ ‌തെറ്റായി ‌ടൈപ്പുചെയ്തു. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> സെക്കന്റിനു‌ശേഷം വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ നിങ്ങളുടെ പാസ്‌വേഡ് ‌തെറ്റായി ‌ടൈപ്പുചെയ്തു. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> സെക്കന്റിനു‌ശേഷം വീണ്ടും ശ്രമിക്കുക."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ അൺലോക്ക് പാറ്റേൺ ‌തെറ്റായി ‌വരച്ചു. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> സെക്കന്റിനു‌ശേഷം വീണ്ടും ശ്രമിക്കുക."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി ടാബ്‌ലെറ്റ് അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ, ഈ ടാബ്‌ലെറ്റ് ‌റീസെറ്റുചെയ്യപ്പെടുകയും, അതുവഴി അതിലെ എല്ലാ ‌ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി ഫോൺ അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ ഈ ഫോൺ റീസെറ്റുചെയ്യപ്പെടുകയും, അതുവഴി അതിലെ എല്ലാ ‌ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"നിങ്ങൾ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി ടാബ്‌ലെറ്റ് അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഈ ഫോൺ റീസെറ്റുചെയ്യപ്പെടുകയും, അതുവഴി അതിലെ എല്ലാ ‌ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"നിങ്ങൾ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി ഫോൺ അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഈ ഫോൺ റീസെറ്റുചെയ്യപ്പെടുകയും, അതുവഴി അതിലെ എല്ലാ ‌ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി ടാബ്‌ലെറ്റ് അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ ഈ ഉപയോക്താവിനെ ‌നീക്കം ചെയ്യുകയും, അതുവഴി ‌ഉപയോക്താവിന്റെ എല്ലാ ‌ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി ഫോൺ അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ ഈ ഉപയോക്താവിനെ ‌നീക്കം ചെയ്യുകയും, അതുവഴി ‌ഉപയോക്താവിന്റെ എല്ലാ ‌ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"നിങ്ങൾ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി ടാബ്‌ലെറ്റ് അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഔദ്യോഗിക പ്രൊഫൈൽ നീക്കംചെയ്യപ്പെടുകയും, അതുവഴി എല്ലാ പ്രൊഫൈൽ ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"നിങ്ങൾ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി ഫോൺ അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഔദ്യോഗിക പ്രൊഫൈൽ നീക്കംചെയ്യപ്പെടുകയും, അതുവഴി എല്ലാ പ്രൊഫൈൽ ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി അൺലോക്ക് പാറ്റേൺ വരച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ, ഒരു ഇമെയിൽ അക്കൗണ്ടുപയോഗിച്ച് ടാബ്‌ലെറ്റ് അൺലോക്കുചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> സെക്കന്റ് കഴിഞ്ഞ് വീണ്ടും ‌ശ്രമിക്കുക."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി അൺലോക്ക് പാറ്റേൺ വരച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ, ഒരു ഇമെയിൽ അക്കൗണ്ടുപയോഗിച്ച് ഫോൺ അൺലോക്കുചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> സെക്കന്റ് കഴിഞ്ഞ് വീണ്ടും ‌ശ്രമിക്കുക."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"സിം പിൻ കോഡ് തെറ്റാണ്, നിങ്ങളുടെ ഉപകരണം അൺലോക്കുചെയ്യാൻ ഇനി നിങ്ങളുടെ കാരിയറുമായി ബന്ധപ്പെടണം."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">സിം പിൻ കോഡ് തെറ്റാണ്, നിങ്ങൾക്ക് <xliff:g id="NUMBER_1">%d</xliff:g> ശ്രമങ്ങൾ കൂടി ശേഷിക്കുന്നു.</item>
diff --git a/packages/SystemUI/res-keyguard/values-mn/strings.xml b/packages/SystemUI/res-keyguard/values-mn/strings.xml
index 6eda5d8..ba80daf 100644
--- a/packages/SystemUI/res-keyguard/values-mn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mn/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Түгжээг тайлах бол цэсийг дарна уу."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Сүлжээ түгжигдсэн"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM карт алга"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Таблетад SIM карт алга."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Утсанд SIM карт алга."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM картыг оруулна уу."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM карт байхгүй, эсвэл унших боломжгүй байна. SIM карт оруулна уу."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Ашиглах боломжгүй SIM карт байна."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4-8 тооноос бүтэх ПИН-г оруулна уу."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK код 8-с цөөнгүй тооноос бүтнэ."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Зөв PUK кодыг дахин оруулна уу. Олон удаагийн оролдлого нь SIM-г хүчингүй болгоно."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ПИН код тохирохгүй байна"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Загварыг хэт олон удаа буруу оруулсан байна"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Та ПИН кодоо <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу орууллаа. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Та нууц үгээ <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу орууллаа. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Та тайлах хээг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу орууллаа. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Та таблетын түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу хийлээ. Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд энэ таблетыг шинэчлэх бөгөөд бүх өгөгдөл нь устах болно."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу хийлээ.Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд энэ утсыг шинэчлэх бөгөөд бүх өгөгдөл нь устах болно."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Та таблетын түгжээг тайлах оролдлогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу хийлээ. Энэ таблетыг шинэчлэх бөгөөд ингэснээр бүх өгөгдөл нь устах болно."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу хийлээ. Энэ утсыг шинэчлэх бөгөөд ингэснээр бүх өгөгдөл нь устах болно."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Та таблетын түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу хийсэн байна. Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд энэ хэрэглэгчийг устгах бөгөөд ингэснээр хэрэглэгчийн бүх өгөгдөл устах болно."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу хийсэн байна. Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд энэ хэрэглэгчийг устгах бөгөөд ингэснээр хэрэглэгчийн бүх өгөгдөл устах болно."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Та таблетын түгжээг тайлах оролдогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу хийсэн байна. Ажлын профайлыг устгах бөгөөд ингэснээр профайлын бүх өгөгдөл устах болно."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу хийлээ. Ажлын профайлыг устгах бөгөөд ингэснээр профайлын бүх өгөгдлийг устгах болно."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Та түгжээ тайлах загварыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу орууллаа. Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд таблетынхаа түгжээг имэйл бүртгэлээрээ тайлах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Та түгжээ тайлах загварыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу орууллаа. Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд утасныхаа түгжээг имэйл бүртгэлээрээ тайлах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM-н ПИН кодыг буруу оруулсан тул та төхөөрөмжийнхөө түгжээг тайлахын тулд оператор компанитайгаа холбогдоно уу."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">SIM-н ПИН код буруу байна. Танд <xliff:g id="NUMBER_1">%d</xliff:g> оролдлого үлдлээ.</item>
diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml
index 1c9ef54..9d46fb9 100644
--- a/packages/SystemUI/res-keyguard/values-mr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"अनलॉक करण्यासाठी मेनू दाबा."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"नेटवर्क लॉक केले"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"सिम कार्ड नाही"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"टॅबलेटमध्ये सिम कार्ड नाही."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"फोनमध्ये सिम कार्ड नाही."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"सिम कार्ड घाला."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"सिम कार्ड गहाळ झाले आहे किंवा ते वाचनीय नाही. सिम कार्ड घाला."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"निरुपयोगी सिम कार्ड."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4 ते 8 अंकांचा पिन टाईप करा."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK कोड 8 अंकी किंवा त्यापेक्षा अधिकचा असावा."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"योग्य PUK कोड पुन्हा एंटर करा. पुनःपुन्हा प्रयत्न करणे सिम कायमचे अक्षम करेल."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"पिन कोड जुळत नाहीत"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"खूप जास्त पॅटर्न प्रयत्न"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"तुम्ही तुमचा PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने टाइप केला आहे. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"तुम्ही तुमचा पासवर्ड <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने टाइप केला आहे. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"तुम्ही तुमचा अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यरितीने काढला. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"तुम्ही टॅबलेट अनलॉक करण्याचा <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, हे टॅबलेट रीसेट केला जाईल, जे त्याचा सर्व डेटा हटवेल."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"तुम्ही फोन अनलॉक करण्याचा <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, हा फोन रीसेट केला जाईल, जे त्याचा सर्व डेटा हटवेल."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"तुम्ही टॅबलेट अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. हे टॅबलेट रीसेट केले जाईल, जे त्याचा सर्व डेटा हटवेल."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"तुम्ही फोन अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. हा फोन रीसेट केला जाईल, जे त्याचा सर्व डेटा हटवेल."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"तुम्ही टॅबलेट अनलॉक करण्याचा <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, या वापरकर्त्याला काढले जाईल, जे सर्व वापरकर्ता डेटा हटवेल."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"तुम्ही फोन अनलॉक करण्याचा <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, या वापरकर्त्याला काढले जाईल, जे सर्व वापरकर्ता डेटा हटवेल."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"तुम्ही टॅबलेट अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. कार्य प्रोफाइल काढली जाईल, जे सर्व प्रोफाइल डेटा हटवेल."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"तुम्ही फोन अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. कार्य प्रोफाइल काढली जाईल, जे सर्व प्रोफाइल डेटा हटवेल."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"तुम्ही तुमचा अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यपणे काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, तुम्हाला ईमेल खाते वापरून तुमचा टॅब्लेट अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"तुम्ही तुमचा अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यपणे काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, तुम्हाला ईमेल खाते वापरून तुमचा फोन अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"सिम पिन कोड चुकीचा आहे तुम्ही आता तुमचे डिव्हाइस अनलॉक करण्‍यासाठी तुमच्या वाहकाशी संपर्क साधावा."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">चुकीचा सिम पिन कोड, तुमच्याकडे <xliff:g id="NUMBER_1">%d</xliff:g> प्रयत्न शिल्लक आहेत.</item>
diff --git a/packages/SystemUI/res-keyguard/values-ms/strings.xml b/packages/SystemUI/res-keyguard/values-ms/strings.xml
index d8b63da..7c8e1b8 100644
--- a/packages/SystemUI/res-keyguard/values-ms/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ms/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Tekan Menu untuk membuka kunci."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rangkaian dikunci"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Tiada kad SIM"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Tiada kad SIM dalam tablet."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Tiada kad SIM dalam telefon."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Masukkan kad SIM."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Kad SIM tiada atau tidak dapat dibaca. Sila masukkan kad SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Kad SIM tidak boleh digunakan."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Taipkan PIN yang mengandungi 4 hingga 8 nombor."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Kod PUK seharusnya 8 nombor atau lebih."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Masukkan semula kod PUK yang betul. Percubaan berulang akan melumpuhkan SIM secara kekal."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kod PIN tidak sepadan"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Terlalu banyak percubaan melukis corak"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Anda telah tersilap taip PIN sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%2$d</xliff:g> saat."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Anda telah tersilap taip kata laluan sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%2$d</xliff:g> saat."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%2$d</xliff:g> saat."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, tablet ini akan ditetapkan semula sekali gus memadamkan semua data."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, telefon ini akan ditetapkan semula sekali gus memadamkan semua data."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Tablet ini akan ditetapkan semula sekali gus memadamkan semua data."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Telefon ini akan ditetapkan semula sekali gus memadamkan semua data."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, pengguna ini akan dialih keluar sekali gus memadamkan semua data pengguna."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, pengguna ini akan dialih keluar sekali gus memadamkan semua data pengguna."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Profil kerja ini akan dialih keluar sekali gus memadamkan semua data profil."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Profil kerja ini akan dialih keluar sekali gus memadamkan semua data profil."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Anda telah tersilap melukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, anda akan diminta membuka kunci tablet anda menggunakan akaun e-mel.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> saat."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, anda akan diminta membuka kunci telefon anda menggunakan akaun e-mel.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> saat."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Kod PIN SIM salah. Anda mesti menghubungi pembawa anda untuk membuka kunci peranti."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">Kod PIN SIM salah, tinggal <xliff:g id="NUMBER_1">%d</xliff:g> percubaan.</item>
diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml
index 83f9b7e..19a5c25 100644
--- a/packages/SystemUI/res-keyguard/values-my/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-my/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"မီနူးကို နှိပ်၍ လော့ခ်ဖွင့်ပါ။"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"ကွန်ရက်ကို လော့ခ်ချထားသည်"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"ဆင်းမ်ကဒ် မရှိပါ"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"တက်ဘလက်ထဲတွင် ဆင်းမ်ကဒ် မရှိပါ။"</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ဖုန်းထဲတွင် ဆင်းမ်ကဒ် မရှိပါ။"</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"ဆင်းမ်ကဒ် ထည့်ပါ။"</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"ဆင်းမ်ကဒ်မရှိပါ သို့မဟုတ် အသုံးပြု၍မရပါ။ ဆင်းမ်ကဒ်တစ်ခု ထည့်ပါ။"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"အသုံးပြု၍ မရတော့သော ဆင်းမ်ကဒ်။"</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"ဂဏန်း ၄ လုံးမှ ၈ လုံးအထိ ရှိသော ပင်နံပါတ်ကို ထည့်ပါ။"</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"ပင်နံပါတ် ပြန်ဖွင့်သည့်ကုဒ်သည် ဂဏန်း ၈ လုံးနှင့် အထက် ဖြစ်ရပါမည်။"</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"မှန်ကန်သည့် ပင်နံပါတ် ပြန်ဖွင့်သည့်ကုဒ်ကို ပြန်ထည့်ပါ။ ထပ်ခါထပ်ခါမှားယွင်းနေလျှင် ဆင်းမ်ကဒ်ကို အပြီးအပိုင် ပိတ်လိုက်ပါမည်။"</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ပင်နံပါတ် ကိုက်ညီမှုမရှိပါ"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"ပုံစံထည့်သွင်းရန် ကြိုးစားသည့် အကြိမ်အရေအတွက် အလွန်များနေပါပြီ"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"သင်သည် ပင်နံပါတ်ကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ်မှားယွင်းစွာ ထည့်ခဲ့ပါသည်။ \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> စက္ကန့်အကြာတွင် ထပ်စမ်းကြည့်ပါ။"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"သင်သည် စကားဝှက်ကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ်မှားယွင်းစွာ ထည့်ခဲ့ပါသည်။ \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> စက္ကန့်အကြာတွင် ထပ်စမ်းကြည့်ပါ။"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"သင်သည် ပုံစံကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ်မှားယွင်းစွာ ဆွဲခဲ့ပါသည်။ \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> စက္ကန့်အကြာတွင် ထပ်စမ်းကြည့်ပါ။"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"တက်ဘလက်ကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းခဲ့လျှင် ဤတက်ဘလက်ကို ပြင်ဆင်သတ်မှတ်လိုက်မည် ဖြစ်ပြီး ၎င်းအတွင်းရှိ ဒေတာများအားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ဖုန်းကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းခဲ့လျှင် ဤဖုန်းကို ပြင်ဆင်သတ်မှတ်လိုက်မည် ဖြစ်ပြီး ၎င်းအတွင်းရှိ ဒေတာများအားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"တက်ဘလက်ကို <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ ဤတက်ဘလက်ကို ပြင်ဆင်သတ်မှတ်လိုက်မည် ဖြစ်ပြီး ၎င်းအတွင်းရှိ ဒေတာများအားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ဖုန်းကို <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ ဤဖုန်းကို ပြင်ဆင်သတ်မှတ်လိုက်မည် ဖြစ်ပြီး ၎င်းအတွင်းရှိ ဒေတာများအားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"တက်ဘလက်ကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းခဲ့လျှင် ဤအသုံးပြုသူကို ဖယ်ရှားလိုက်မည်ဖြစ်ပြီး အသုံးပြုသူဒေတာများ အားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ဖုန်းကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းသွားလျှင် ဤအသုံးပြုသူကို ဖယ်ရှားလိုက်မည်ဖြစ်ပြီး အသုံးပြုသူဒေတာများ အားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"တက်ဘလက်ကို <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ အလုပ်ပရိုဖိုင်ကို ဖယ်ရှားလိုက်မည်ဖြစ်ပြီး ပရိုဖိုင်ဒေတာများ အားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ဖုန်းကို <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ အလုပ်ပရိုဖိုင်ကို ဖယ်ရှားလိုက်မည်ဖြစ်ပြီး ပရိုဖိုင်ဒေတာများ အားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"သင်သည် သင်၏ လော့ခ်ဖွင့်ခြင်းပုံစံကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ ဆွဲခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းပြီးသည့်နောက်တွင် သင့်အီးမေးလ်အကောင့်အား အသုံးပြု၍ တက်ဘလက်ကို လော့ခ်ဖွင့်ရန် တောင်းဆိုသွားပါမည်။\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> စက္ကန့်အကြာတွင် ထပ်စမ်းကြည့်ပါ။"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"သင်သည် သင်၏ လော့ခ်ဖွင့်ခြင်းပုံစံကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ ဆွဲခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းပြီးသည့်နောက်တွင် သင့်အီးမေးလ်အကောင့်အား အသုံးပြု၍ ဖုန်းကို လော့ခ်ဖွင့်ရန် တောင်းဆိုသွားပါမည်။\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> စက္ကန့်အကြာတွင် ထပ်စမ်းကြည့်ပါ။"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"ဆင်းမ်ကဒ်ပင်နံပါတ် မှားယွင်းနေသောကြောင့် ယခုအခါ သင့်စက်ပစ္စည်းအား လော့ခ်ဖွင့်ရန် ဝန်ဆောင်မှုပေးသူကို ဆက်သွယ်ရပါမည်။"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">ဆင်းမ်ပင်နံပါတ် မှန်ကန်မှုမရှိပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် စမ်းသပ်ခွင့်ရှိပါသေးသည်။</item>
diff --git a/packages/SystemUI/res-keyguard/values-nb/strings.xml b/packages/SystemUI/res-keyguard/values-nb/strings.xml
index e766d59..d5aa0e1 100644
--- a/packages/SystemUI/res-keyguard/values-nb/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nb/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Trykk på menyknappen for å låse opp."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Nettverket er låst"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM-kort mangler"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nettbrettet mangler SIM-kort."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefonen mangler SIM-kort."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Sett inn et SIM-kort."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM-kort mangler eller er uleselig. Sett inn et SIM-kort."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Ubrukelig SIM-kort."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Skriv inn en PIN-kode på fire til åtte sifre."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-koden skal være på åtte eller flere sifre."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Skriv inn den riktige PUK-koden på nytt. Gjentatte forsøk deaktiverer SIM-kortet permanent."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-kodene stemmer ikke overens"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"For mange forsøk på tegning av mønster"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Du har oppgitt feil PIN-kode <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Du har tastet inn passordet ditt feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Du har tegnet opplåsningsmønsteret ditt feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Nettbrettet tilbakestilles etter <xliff:g id="NUMBER_1">%2$d</xliff:g> nye mislykkede forsøk, noe som sletter alle dataene på nettbrettet."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Telefonen tilbakestilles etter <xliff:g id="NUMBER_1">%2$d</xliff:g> nye mislykkede forsøk, noe som sletter alle dataene på telefonen."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER">%d</xliff:g> ganger. Dette nettbrettet blir tilbakestilt, og alle dataene blir slettet."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER">%d</xliff:g> ganger. Denne telefonen blir tilbakestilt, og alle dataene blir slettet."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Brukeren fjernes etter <xliff:g id="NUMBER_1">%2$d</xliff:g> nye mislykkede forsøk, noe som sletter alle brukerdataene."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Brukeren fjernes etter <xliff:g id="NUMBER_1">%2$d</xliff:g> nye mislykkede forsøk, noe som sletter alle brukerdataene."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER">%d</xliff:g> ganger. Jobbprofilen blir fjernet, og alle profildataene blir slettet."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER">%d</xliff:g> ganger. Jobbprofilen blir fjernet, og alle profildataene blir slettet."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Du har tegnet opplåsingsmønsteret feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%2$d</xliff:g> feil forsøk blir du bedt om å låse opp nettbrettet via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Du har tegnet opplåsingsmønsteret feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%2$d</xliff:g> feil forsøk blir du bedt om å låse opp telefonen via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Feil PIN-kode for SIM-kortet. Du må nå kontakte operatøren din for å låse opp enheten."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">Feil PIN-kode for SIM-kortet. Du har <xliff:g id="NUMBER_1">%d</xliff:g> forsøk igjen.</item>
diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml
index 4f1ea2a..763dc03 100644
--- a/packages/SystemUI/res-keyguard/values-ne/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"अनलक गर्न मेनु थिच्नुहोस्।"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"नेटवर्क लक भएको छ"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM कार्ड छैन"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ट्याब्लेटमा SIM कार्ड छैन।"</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"फोनमा SIM कार्ड छैन।"</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM कार्ड हाल्नुहोस्"</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM कार्ड हालिएको छैन वा पढ्न योग्य छैन। SIM कार्ड हाल्नुहोस्।"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM कार्ड काम नलाग्ने भएको छ।"</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"४ देखि ८ वटा नम्बर भएको एउटा PIN टाइप गर्नुहोस्।"</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK कोड ८ वा सो भन्दा बढी नम्बरको हुनु पर्छ।"</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"PUK कोड पुन: प्रविष्टि गर्नुहोस्। पटक-पटकको प्रयासले SIM सदाका लागि असक्षम हुनेछ।"</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN कोडहरू मिलेनन्"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"अत्यन्त धेरै ढाँचा कोर्ने प्रयासहरू"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले आफ्नो PIN प्रविष्ट गर्नुभएको छ। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक आफ्नो गलत पासवर्ड  प्रविष्ट गर्नुभएको छ। \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले आफ्नो अनलक ढाँचा कोर्नुभएको छ। \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकेन्डमा फेरि कोसिस गर्नुहोस्।"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, यो ट्याब्लेट यसमा भएका सबै डेटा मेटिने गरी रिसेट हुनेछ।"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, यो फोन यसमा भएका सबै डेटा मेटिने गरी रिसेट हुनेछ।"</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"तपाईंले <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नुभएको छ। यो ट्याब्लेट यसमा भएका सबै डेटा मेटिने गरी रिसेट हुनेछ।"</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"तपाईंले <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नुभएको छ। यो फोन यसमा भएका सबै डेटा मेटिने गरी रिसेट हुनेछ।"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले  ट्याब्लेट अनलक गर्ने प्रयास गर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, यस प्रयोगकर्तालाई यसका सबै डेटा मेटिने गरी हटाइने छ।"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, यस प्रयोगकर्तालाई यसका सबै डेटा मेटिने गरी हटाइने छ।"</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"तपाईं <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नुभएको छ। कार्य प्रोफाइललाई यसका सबै डेटा मेटिने गरी हटाइने छ।"</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"तपाईंले <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नुभएको छ। कार्य प्रोफाइललाई यसका सबै डेटा मेटिने गरी हटाइने छ।"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक आफ्नो अनलक गर्ने ढाँचा गलत रूपमा कोर्नुभयो। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, तपाईंलाई एउटा इमेल खाता प्रयोग गरेर आफ्नो ट्याब्लेट अनलक गर्न आग्रह गरिनेछ।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक आफ्नो अनलक गर्ने ढाँचा गलत रूपमा कोर्नुभयो। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, तपाईंलाई एउटा इमेल खाता प्रयोग गरेर आफ्नो फोन अनलक गर्न आग्रह गरिनेछ।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM को PIN कोड गलत छ। तपाईंले अब आफ्नो यन्त्र खोल्न आफ्नो सेवा प्रदायकलाई सम्पर्क गर्नै पर्ने हुन्छ।"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">SIM को PIN कोड गलत छ, तपाईं अझै <xliff:g id="NUMBER_1">%d</xliff:g> पटक प्रयास गर्न सक्नुहुन्छ।</item>
diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml
index 16b3425..953e32d 100644
--- a/packages/SystemUI/res-keyguard/values-nl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Druk op Menu om te ontgrendelen."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Netwerk vergrendeld"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Geen simkaart"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Geen simkaart in tablet."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Geen simkaart in telefoon."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Plaats een simkaart."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"De simkaart ontbreekt of kan niet worden gelezen. Plaats een simkaart."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Onbruikbare simkaart."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Geef een pincode van vier tot acht cijfers op."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"De pukcode is minimaal acht cijfers lang."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Geef de juiste pukcode opnieuw op. Bij herhaalde pogingen wordt de simkaart definitief uitgeschakeld."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Pincodes komen niet overeen"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Te veel patroonpogingen"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Je hebt je pincode <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getypt. \n\nProbeer het over <xliff:g id="NUMBER_1">%2$d</xliff:g> seconden opnieuw."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Je hebt je wachtwoord <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getypt. \n\nProbeer het over <xliff:g id="NUMBER_1">%2$d</xliff:g> seconden opnieuw."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getekend. \n\nProbeer het over <xliff:g id="NUMBER_1">%2$d</xliff:g> seconden opnieuw."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Je hebt <xliff:g id="NUMBER_0">%1$d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt deze tablet gereset, waardoor alle gegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Je hebt <xliff:g id="NUMBER_0">%1$d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt deze telefoon gereset, waardoor alle gegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Deze tablet wordt gereset, waardoor alle gegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Deze telefoon wordt gereset, waardoor alle gegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Je hebt <xliff:g id="NUMBER_0">%1$d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt deze gebruiker verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Je hebt <xliff:g id="NUMBER_0">%1$d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt deze gebruiker verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Het werkprofiel wordt verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Het werkprofiel wordt verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt je gevraagd je tablet te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%3$d</xliff:g> seconden opnieuw."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt je gevraagd je telefoon te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%3$d</xliff:g> seconden opnieuw."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Onjuiste pincode voor simkaart. Je moet nu contact opnemen met je provider om je apparaat te ontgrendelen."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">Onjuiste pincode voor simkaart. Je hebt nog <xliff:g id="NUMBER_1">%d</xliff:g> pogingen over.</item>
diff --git a/packages/SystemUI/res-keyguard/values-or/strings.xml b/packages/SystemUI/res-keyguard/values-or/strings.xml
index b2e8957..32738d8c 100644
--- a/packages/SystemUI/res-keyguard/values-or/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-or/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"ଅନଲକ୍‌ କରିବା ପାଇଁ ମେନୁକୁ ଦବାନ୍ତୁ।"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"ନେଟୱର୍କକୁ ଲକ୍‌ କରାଯାଇଛି"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"କୌଣସି SIM କାର୍ଡ ନାହିଁ"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ଟାବଲେଟ୍‌ରେ କୌଣସି SIM‍ କାର୍ଡ ନାହିଁ।"</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ଫୋନରେ କୌଣସି SIM କାର୍ଡ ନାହିଁ।"</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"ଗୋଟିଏ SIM କାର୍ଡ ଭର୍ତ୍ତି କରନ୍ତୁ।"</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM କାର୍ଡ ନାହିଁ କିମ୍ବା ଖରାପ ଅଛି। SIM କାର୍ଡ ଭର୍ତ୍ତି କରନ୍ତୁ।"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM କାର୍ଡଟିକୁ ବ୍ୟବହାର କରାଯାଇପାରିବ ନାହିଁ।"</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4 ରୁ 8 ନମ୍ବର ବିଶିଷ୍ଟ ଏକ PIN ଟାଇପ୍ କରନ୍ତୁ।"</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK କୋଡ୍‍‍ରେ 8ଟି କିମ୍ବା ଅଧିକ ନମ୍ବର ରହିଥାଏ।"</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"ଠିକ୍‍ PUK କୋଡ୍‍ ପୁଣି ଲେଖନ୍ତୁ। ବାରମ୍ବାର ପ୍ରୟାସ କଲେ SIM କାର୍ଡ ସ୍ଥାୟୀ ରୂପେ ଅକ୍ଷମ ହୋଇଯିବ।"</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN କୋଡ୍‍ ମେଳ ହେଉନାହିଁ"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"ଅନେକ ପାଟର୍ନ ପ୍ରୟାସ"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"ଆପଣଙ୍କ PIN ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g>ଥର ଭୁଲ ଭାବେ ଟାଇପ୍‍ କରିଛନ୍ତି। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"ଆପଣଙ୍କ ପାସ୍‌ୱର୍ଡକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ଭାବେ ଟାଇପ୍ କରିଛନ୍ତି। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"ଆପଣଙ୍କ ଲକ୍‍ ଖୋଲିବା ପାଟର୍ନକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g>ଥର ଭୁଲ ଭାବେ ଅଙ୍କନ କରିଛନ୍ତି। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ଆପଣ ଟାବଲେଟକୁ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଭୁଲ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ୍‍ ପ୍ରୟାସ ପରେ, ଏହି ଟାବଲେଟଟି ରିସେଟ୍‍ ହୋଇଯିବ, ଯାହାଦ୍ୱାରା ଏହାର ସମସ୍ତ ଡାଟା ଲିଟ୍‍ ହୋଇଯିବ।"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ଆପଣ ଫୋନକୁ ଅନଲକ୍‍ କରିବାକୁ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଭୁଲ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ୍‍ ପ୍ରୟାସ ପରେ, ଏହି ଫୋନଟି ରିସେଟ୍‍ ହୋଇଯିବ, ଯାହାଦ୍ୱାରା ଏହାର ସମସ୍ତ ଡାଟା ଲିଟ୍‍ ହୋଇଯିବ।"</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ଆପଣ ଟାବଲେଟକୁ ଅନଲକ୍‍ କରିବାକୁ <xliff:g id="NUMBER">%d</xliff:g> ଥର ଭୁଲ୍‍ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ଏହି ଟାବଲେଟକୁ ରିସେଟ୍‍ କରାଯିବ, ଯାହାଦ୍ୱାରା ଏହାର ସମସ୍ତ ଡାଟା ଡିଲିଟ୍‍ ହୋଇଯିବ।"</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ଆପଣ ଫୋନଟି ଅନଲକ୍‍ କରିବାକୁ <xliff:g id="NUMBER">%d</xliff:g>ଥର ଭୁଲ୍‍ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ଏହି ଫୋନ୍‍ ରିସେଟ୍‍ କରାଯିବ, ଯାହା ଦ୍ୱାରା ଏହାର ସମସ୍ତ ଡାଟା ଡିଲିଟ୍‍ ହୋଇଯିବ।"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ଆପଣ ଟାବଲେଟ୍‌ଟିକୁ ଅନଲକ୍‍ କରିବା ପାଇଁ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ଭାବେ ଚେଷ୍ଟା କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g> ଟି ଭୁଲ୍‍ ପ୍ରୟାସ ପରେ, ୱାର୍କ ପ୍ରୋଫାଇଲ୍‍କୁ ବାହାର କରିଦିଆଯିବ ଏବଂ ଏହା ଦ୍ୱାରା ସମସ୍ତ ପ୍ରୋଫାଇଲ୍‍ ଡାଟା ଡିଲିଟ୍‍ ହୋଇଯିବ।"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ଆପଣ ଫୋନଟି ଅନଲକ୍‍ କରିବାକୁ <xliff:g id="NUMBER_0">%1$d</xliff:g>ଥର ଭୁଲ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ୍‍ ପ୍ରୟାସ ପରେ, ଏହି ୟୁଜରଙ୍କୁ ବାହାର କରିଦିଆଯିବ ଏବଂ ଏହାଦ୍ୱାରା ସମସ୍ତ ୟୁଜର୍‍ ଡାଟା ଡିଲିଟ୍‍ ହୋଇଯିବ।"</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ଆପଣ ଟାବଲେଟକୁ ଅନଲକ୍‍ କରିବାକୁ <xliff:g id="NUMBER">%d</xliff:g> ଭୁଲ୍‍ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। କାର୍ଯ୍ୟ ପ୍ରୋଫାଇଲ୍‍ ବାହାର କରିଦିଆଯିବ, ଯାହାଦ୍ୱାରା ସମସ୍ତ ପ୍ରୋଫାଇଲ୍‍ ଡାଟା ଡିଲିଟ୍‍ ହୋଇଯିବ।"</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ଆପଣ ଫୋନଟି ଅନଲକ୍‍ କରିବାକୁ <xliff:g id="NUMBER">%d</xliff:g>ଥର ଭୁଲ୍‍ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ୱର୍କ ପ୍ରୋଫାଇଲ୍‍ ବାହାର କରିଦିଆଯିବ, ଯାହା ଦ୍ୱାରା ସମସ୍ତ ପ୍ରୋଫାଇଲ୍‍ ଡାଟା ଡିଲିଟ୍‍ ହୋଇଯିବ।"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ଆପଣଙ୍କ ଅନଲକ୍‍ ପାଟର୍ନକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ଭାବେ ଅଙ୍କନ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g> ଟି ଭୁଲ ପ୍ରୟାସ ପରେ ଏକ ଇମେଲ୍‍ ଆକାଉଣ୍ଟ ବ୍ୟବହାର କରି ନିଜ ଟାବଲେଟକୁ ଅନଲକ୍‌ କରିବା ପାଇଁ କୁହାଯିବ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ଆପଣଙ୍କ ଅନଲକ୍‍ ପାଟର୍ନକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ଭାବେ ଅଙ୍କନ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g> ଟି ଭୁଲ ପ୍ରୟାସ ପରେ ଏକ ଇମେଲ୍‍ ଆକାଉଣ୍ଟ ବ୍ୟବହାର କରି ନିଜ ଫୋନକୁ ଅନଲକ୍‌ କରିବା ପାଇଁ କୁହାଯିବ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"ଭୁଲ SIM PIN କୋଡ୍‌, ଆପଣଙ୍କ ଡିଭାଇସକୁ ଅନଲକ୍‌ କରିବା ପାଇଁ ଏବେ ହିଁ ନିଜ କେରିଅର୍‌ଙ୍କ ସହ ସମ୍ପର୍କ କରନ୍ତୁ।"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">ଭୁଲ SIM PIN କୋଡ୍, ଆପଣଙ୍କର ଆଉ <xliff:g id="NUMBER_1">%d</xliff:g>ଟି ପ୍ରୟାସ ବାକି ରହିଛି।</item>
diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml
index 5e68530..c53f42f 100644
--- a/packages/SystemUI/res-keyguard/values-pa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"ਅਣਲਾਕ ਕਰਨ ਲਈ \"ਮੀਨੂ\" ਦਬਾਓ।"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"ਨੈੱਟਵਰਕ  ਲਾਕ  ਕੀਤਾ ਗਿਆ"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"ਕੋਈ ਸਿਮ ਕਾਰਡ ਨਹੀਂ"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ਟੈਬਲੈੱਟ ਵਿੱਚ ਕੋਈ ਸਿਮ ਕਾਰਡ ਮੌਜੂਦ ਨਹੀਂ।"</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ਫ਼ੋਨ ਵਿੱਚ ਕੋਈ ਸਿਮ ਕਾਰਡ ਮੌਜੂਦ ਨਹੀਂ।"</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"ਇੱਕ SIM ਕਾਰਡ ਪਾਓ।"</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM ਕਾਰਡ ਮੌਜੂਦ ਨਹੀਂ ਜਾਂ ਪੜ੍ਹਨਯੋਗ ਨਹੀਂ ਹੈ। ਇੱਕ SIM ਕਾਰਡ ਪਾਓ।"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"ਨਾ-ਵਰਤਣਯੋਗ SIM ਕਾਰਡ।"</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"ਕੋਈ ਪਿੰਨ ਟਾਈਪ ਕਰੋ ਜੋ 4 ਤੋਂ 8 ਨੰਬਰਾਂ ਦਾ ਹੋਵੇ।"</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK ਕੋਡ 8 ਜਾਂ ਵੱਧ ਨੰਬਰਾਂ ਦਾ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ।"</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"ਸਹੀ PUK ਕੋਡ ਮੁੜ-ਦਾਖਲ ਕਰੋ। ਬਾਰ-ਬਾਰ ਕੀਤੀਆਂ ਕੋਸ਼ਿਸ਼ਾਂ ਸਿਮ ਨੂੰ ਸਥਾਈ ਤੌਰ \'ਤੇ ਬੰਦ ਕਰ ਦੇਣਗੀਆਂ।"</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ਪਿੰਨ ਕੋਡ ਮੇਲ ਨਹੀਂ ਖਾਂਦੇ"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"ਬਹੁਤ ਜ਼ਿਆਦਾ ਪੈਟਰਨ ਕੋਸ਼ਿਸ਼ਾਂ"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"ਤੁਸੀਂ ਆਪਣਾ ਪਿੰਨ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਟਾਈਪ ਕੀਤਾ ਹੈ। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਆਪਣਾ ਪਾਸਵਰਡ ਗਲਤ ਢੰਗ ਨਾਲ ਟਾਈਪ ਕੀਤਾ ਹੈ।\n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਣਲਾਕ ਪੈਟਰਨ ਗਲਤ ਢੰਗ ਨਾਲ ਉਲੀਕਿਆ ਹੈ। \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਹ ਟੈਬਲੈੱਟ ਰੀਸੈੱਟ ਕੀਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਇਸਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਫ਼ੋਨ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਹ ਫ਼ੋਨ ਰੀਸੈੱਟ ਕੀਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਇਸਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। ਇਹ ਟੈਬਲੈੱਟ ਰੀਸੈੱਟ ਕੀਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਇਸਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਫ਼ੋਨ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। ਇਹ ਫ਼ੋਨ ਰੀਸੈੱਟ ਕੀਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਇਸਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਸ ਵਰਤੋਂਕਾਰ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਸਾਰਾ ਵਰਤੋਂਕਾਰ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਫ਼ੋਨ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਸ ਵਰਤੋਂਕਾਰ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਸਾਰਾ ਵਰਤੋਂਕਾਰ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਸਾਰਾ ਪ੍ਰੋਫਾਈਲ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਫ਼ੋਨ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਸਾਰਾ ਪ੍ਰੋਫਾਈਲ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਣਲਾਕ ਪੈਟਰਨ ਗਲਤ ਢੰਗ ਨਾਲ ਉਲੀਕਿਆ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਨੂੰ ਇੱਕ ਈਮੇਲ ਖਾਤਾ ਵਰਤਦੇ ਹੋਏ ਆਪਣੇ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਲਈ ਕਿਹਾ ਜਾਵੇਗਾ।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਣਲਾਕ ਪੈਟਰਨ ਗਲਤ ਢੰਗ ਨਾਲ ਡ੍ਰਾ ਕੀਤਾ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਨੂੰ ਇੱਕ ਈਮੇਲ ਖਾਤਾ ਵਰਤਦੇ ਹੋਏ ਆਪਣਾ ਫ਼ੋਨ ਅਣਲਾਕ ਕਰਨ ਲਈ ਕਿਹਾ ਜਾਏਗਾ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"ਗਲਤ ਸਿਮ ਪਿੰਨ ਕੋਡ, ਆਪਣੇ ਡੀਵਾਈਸ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਲਈ ਹੁਣ ਤੁਹਾਨੂੰ ਲਾਜ਼ਮੀ ਤੌਰ \'ਤੇ ਆਪਣੇ ਕੈਰੀਅਰ ਨਾਲ ਸੰਪਰਕ ਕਰਨਾ ਚਾਹੀਦਾ ਹੈ।"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">ਗਲਤ ਸਿਮ ਪਿੰਨ ਕੋਡ, ਤੁਹਾਡੇ ਕੋਲ <xliff:g id="NUMBER_1">%d</xliff:g> ਕੋਸ਼ਿਸ਼ ਬਾਕੀ ਹੈ।</item>
diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml
index c9752b9..e3d7878 100644
--- a/packages/SystemUI/res-keyguard/values-pl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Naciśnij Menu, aby odblokować."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Sieć zablokowana"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Brak karty SIM"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Brak karty SIM w tablecie."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Brak karty SIM w telefonie."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Włóż kartę SIM."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Brak karty SIM lub nie można jej odczytać. Włóż kartę SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Karta SIM jest zablokowana."</string>
@@ -85,17 +83,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Wpisz kod PIN o długości od 4 do 8 cyfr."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Kod PUK musi mieć co najmniej 8 cyfr."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Wpisz poprawny kod PUK. Kolejne próby spowodują trwałe wyłączenie karty SIM."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kody PIN nie pasują"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Zbyt wiele prób narysowania wzoru"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> wpisałeś nieprawidłowy kod PIN. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> wpisałeś nieprawidłowe hasło. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> próbowałeś nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach tablet zostanie zresetowany, co spowoduje skasowanie wszystkich jego danych."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> próbowałeś nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach telefon zostanie zresetowany, co spowoduje skasowanie wszystkich jego danych."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowałeś nieprawidłowo odblokować tablet. Tablet zostanie zresetowany, co spowoduje skasowanie wszystkich jego danych."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowałeś nieprawidłowo odblokować telefon. Telefon zostanie zresetowany, co spowoduje skasowanie wszystkich jego danych."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> próbowałeś nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach użytkownik zostanie usunięty, co spowoduje skasowanie wszystkich danych użytkownika."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> próbowałeś nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach użytkownik zostanie usunięty, co spowoduje skasowanie wszystkich danych użytkownika."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -104,10 +95,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowałeś nieprawidłowo odblokować tablet. Profil służbowy zostanie usunięty, co spowoduje skasowanie wszystkich danych tego profilu."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowałeś nieprawidłowo odblokować telefon. Profil służbowy zostanie usunięty, co spowoduje skasowanie wszystkich danych tego profilu."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach konieczne będzie odblokowanie tabletu przy użyciu konta e-mail.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach konieczne będzie odblokowanie telefonu przy użyciu konta e-mail.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Nieprawidłowy kod PIN karty SIM. Musisz teraz skontaktować się z operatorem, by odblokował Twoje urządzenie."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="few">Nieprawidłowy kod PIN karty SIM. Masz jeszcze <xliff:g id="NUMBER_1">%d</xliff:g> próby.</item>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
index 19645c0..b74aea9 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Pressione Menu para desbloquear."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rede bloqueada"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Sem chip"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Não há um chip no tablet."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Não há um chip no smartphone."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Insira um chip."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"O chip não foi inserido ou não é possível lê-lo. Insira um chip."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Chip inutilizável."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Digite um PIN com 4 a 8 números."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"O código PUK deve ter oito números ou mais."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Introduza novamente o código PUK correto. Muitas tentativas malsucedidas desativarão permanentemente o chip."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Os códigos PIN não coincidem"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Muitas tentativas de padrão"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Você digitou seu PIN incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este smartphone será redefinido, o que excluirá todos os dados dele."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este smartphone será redefinido, o que excluirá todos os dados dele."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este tablet será redefinido, o que excluirá todos os dados dele."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este smartphone será redefinido, o que excluirá todos os dados dele."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este usuário será removido, o que excluirá todos os dados do usuário."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este usuário será removido, o que excluirá todos os dados do usuário."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Código PIN do chip incorreto. Entre em contato com a operadora para desbloquear o dispositivo."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">Código PIN do chip incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>.</item>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
index be3ca3e..e8600c8 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Prima Menu para desbloquear."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rede bloqueada"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Nenhum cartão SIM"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nenhum cartão SIM no tablet."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Nenhum cartão SIM no telemóvel."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Insira um cartão SIM."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"O cartão SIM está em falta ou não é legível. Insira um cartão SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Cartão SIM inutilizável."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Introduza um PIN com 4 a 8 números."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"O código PUK deve ter 8 ou mais números."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Volte a introduzir o código PUK correto. Demasiadas tentativas consecutivas irão desativar permanentemente o cartão SIM."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Os códigos PIN não coincidem"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Demasiadas tentativas para desenhar o padrão"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Introduziu o PIN incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Introduziu a palavra-passe incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Desenhou a sua padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, este tablet será reposto, o que eliminará todos os dados do mesmo."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, este telemóvel será reposto, o que eliminará todos os dados do mesmo."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER">%d</xliff:g> vezes. Este tablet será reposto, o que eliminará todos os dados do mesmo."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER">%d</xliff:g> vezes. Este telemóvel será reposto, o que eliminará todos os dados do mesmo."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, este utilizador será removido, o que eliminará todos os dados do mesmo."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, este utilizador será removido, o que eliminará todos os dados do mesmo."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que eliminará todos os dados do mesmo."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que eliminará todos os dados do mesmo."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Desenhou o padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, ser-lhe-á pedido para desbloquear o tablet através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Desenhou o padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, ser-lhe-á pedido para desbloquear o telemóvel através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Código PIN do cartão SIM incorreto. Tem de contactar o seu operador para desbloquear o dispositivo."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">Código PIN do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas.</item>
diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml
index 19645c0..b74aea9 100644
--- a/packages/SystemUI/res-keyguard/values-pt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Pressione Menu para desbloquear."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rede bloqueada"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Sem chip"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Não há um chip no tablet."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Não há um chip no smartphone."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Insira um chip."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"O chip não foi inserido ou não é possível lê-lo. Insira um chip."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Chip inutilizável."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Digite um PIN com 4 a 8 números."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"O código PUK deve ter oito números ou mais."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Introduza novamente o código PUK correto. Muitas tentativas malsucedidas desativarão permanentemente o chip."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Os códigos PIN não coincidem"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Muitas tentativas de padrão"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Você digitou seu PIN incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este smartphone será redefinido, o que excluirá todos os dados dele."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este smartphone será redefinido, o que excluirá todos os dados dele."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este tablet será redefinido, o que excluirá todos os dados dele."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este smartphone será redefinido, o que excluirá todos os dados dele."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este usuário será removido, o que excluirá todos os dados do usuário."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este usuário será removido, o que excluirá todos os dados do usuário."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Código PIN do chip incorreto. Entre em contato com a operadora para desbloquear o dispositivo."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">Código PIN do chip incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>.</item>
diff --git a/packages/SystemUI/res-keyguard/values-ro/strings.xml b/packages/SystemUI/res-keyguard/values-ro/strings.xml
index 05d1048..f8a39f0 100644
--- a/packages/SystemUI/res-keyguard/values-ro/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ro/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Apăsați pe Meniu pentru a debloca."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rețea blocată"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Niciun card SIM"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nu există card SIM în tabletă."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Nu există card SIM în telefon."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Introduceți un card SIM."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Cardul SIM lipsește sau nu poate fi citit. Introduceți un card SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Card SIM inutilizabil."</string>
@@ -84,17 +82,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Introduceți un cod PIN alcătuit din 4 până la 8 cifre."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Codul PUK trebuie să aibă minimum 8 cifre."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Reintroduceți codul PUK corect. Încercările repetate vor dezactiva definitiv cardul SIM."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Codurile PIN nu coincid"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Prea multe încercări de desenare a modelului"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Ați introdus incorect codul PIN de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori.\n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> secunde."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Ați introdus incorect parola de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> secunde."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> secunde."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, această tabletă va fi resetată, iar toate datele acesteia vor fi șterse."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acest telefon va fi resetat, iar toate datele acestuia vor fi șterse."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Această tabletă va fi resetată, iar toate datele acesteia vor fi șterse."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Acest telefon va fi resetat, iar toate datele acestuia vor fi șterse."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acest utilizator va fi eliminat, iar toate datele utilizatorului vor fi șterse."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acest utilizator va fi eliminat, iar toate datele utilizatorului vor fi șterse."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -103,10 +94,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați tableta cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați telefonul cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Codul PIN pentru cardul SIM este incorect. Contactați operatorul pentru a vă debloca dispozitivul."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="few">Codul PIN pentru cardul SIM este incorect. V-au mai rămas <xliff:g id="NUMBER_1">%d</xliff:g> încercări.</item>
diff --git a/packages/SystemUI/res-keyguard/values-ru/strings.xml b/packages/SystemUI/res-keyguard/values-ru/strings.xml
index 53ad97f..4b38fdc 100644
--- a/packages/SystemUI/res-keyguard/values-ru/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ru/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Для разблокировки нажмите \"Меню\"."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Сеть заблокирована"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Нет SIM-карты."</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Нет SIM-карты."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Нет SIM-карты."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Вставьте SIM-карту."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM-карта отсутствует или недоступна. Вставьте SIM-карту."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM-карта непригодна к использованию."</string>
@@ -85,17 +83,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Введите PIN-код (от 4 до 8 цифр)."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-код должен содержать не менее 8 цифр."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Введите правильный PUK-код. После нескольких неудачных попыток SIM-карта будет заблокирована."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-коды не совпадают."</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Слишком много попыток ввести графический ключ."</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Вы ввели неверный PIN-код несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>).\n\nПовторите попытку через <xliff:g id="NUMBER_1">%2$d</xliff:g> сек."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Вы ввели неверный пароль несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>).\n\nПовторите попытку через <xliff:g id="NUMBER_1">%2$d</xliff:g> сек."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Вы начертили неверный графический ключ несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>).\n\nПовторите попытку через <xliff:g id="NUMBER_1">%2$d</xliff:g> сек."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Вы пытались разблокировать планшет несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи произойдет сброс настроек и все данные на устройстве будут удалены."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Вы пытались разблокировать телефон несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи произойдет сброс настроек и все данные на устройстве будут удалены."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Достигнуто максимальное количество неудачных попыток разблокировать планшет (<xliff:g id="NUMBER">%d</xliff:g>). Настройки устройства будут сброшены, а все его данные – удалены."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Достигнуто максимальное количество неудачных попыток разблокировать телефон (<xliff:g id="NUMBER">%d</xliff:g>). Настройки устройства будут сброшены, а все его данные – удалены."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Вы пытались разблокировать планшет несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи профиль пользователя и все его данные будут удалены."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Вы пытались разблокировать телефон несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи профиль пользователя и все его данные будут удалены."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -104,10 +95,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Достигнуто максимальное количество неудачных попыток разблокировать планшет (<xliff:g id="NUMBER">%d</xliff:g>). Рабочий профиль и все его данные будут удалены."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Достигнуто максимальное количество неудачных попыток разблокировать телефон (<xliff:g id="NUMBER">%d</xliff:g>). Рабочий профиль и все его данные будут удалены."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Вы ввели неверный графический ключ несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи вам будет предложено разблокировать планшет с помощью аккаунта электронной почты.\n\nПовторите попытку через <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Вы ввели неверный графический ключ несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи вам будет предложено разблокировать телефон с помощью аккаунта электронной почты.\n\nПовторите попытку через <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Неверный PIN-код. Обратитесь к оператору связи, чтобы разблокировать SIM-карту."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">Неверный PIN-код. Осталась <xliff:g id="NUMBER_1">%d</xliff:g> попытка.</item>
diff --git a/packages/SystemUI/res-keyguard/values-si/strings.xml b/packages/SystemUI/res-keyguard/values-si/strings.xml
index fe1b7e9..d646018 100644
--- a/packages/SystemUI/res-keyguard/values-si/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-si/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"අගුලු හැරීමට මෙනුව ඔබන්න."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"ජාලය අගුළු දමා ඇත"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM පත නැත"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ටැබ්ලටයේ SIM පත නොමැත."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"දුරකථනය තුල SIM පතක් නැත."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM කාඩ්පතක් ඇතුළු කරන්න."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM පත නොමැත හෝ කියවිය නොහැක. SIM පතක් ඇතුලත් කරන්න."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"භාවිතා කළ නොහැකි SIM පත."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4 සිට 8 දක්වා අංක සහිත PIN එකක් ටයිප් කරන්න."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK කේතය සංඛ්‍යා 8 ක් හෝ වැඩි විය යුතුය."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"නිවැරදි PUK කේතය නැවත ඇතුලත් කරන්න. නැවත නැවත උත්සාහ කිරීමෙන් SIM එක ස්ථිරවම අබල කරයි."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN කේත නොගැළපේ."</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"රටා උත්සාහ කිරීම් වැඩිය"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"ඔබ PIN අංකය <xliff:g id="NUMBER_0">%1$d</xliff:g> වාරයක් වැරදියට ටයිප් කොට ඇත.\n\n තත්පර <xliff:g id="NUMBER_1">%2$d</xliff:g> ක් ඇතුළත නැවත උත්සාහ කරන්න."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"ඔබ මුරපදය වාර <xliff:g id="NUMBER_0">%1$d</xliff:g> ක් වැරදියට ටයිප්කොට ඇත. \n\nතත්පර <xliff:g id="NUMBER_1">%2$d</xliff:g> කින් නැවත උත්සහ කරන්න."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"ඔබ <xliff:g id="NUMBER_0">%1$d</xliff:g> වාරයක් අගුළු ඇරීමේ රටාව වැරදියට ඇඳ ඇත. \n\nතත්පර <xliff:g id="NUMBER_1">%2$d</xliff:g> ක් ඇතුළත නැවත උත්සාහ කරන්න."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ඔබ ටැබ්ලට් පරිගණකය අගුළු හැරීමට <xliff:g id="NUMBER_0">%1$d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. තවත් අසාර්ථක උත්සාහයන් <xliff:g id="NUMBER_1">%2$d</xliff:g>කින් පසුව, මෙම ටැබ්ලට් පරිගණකය යළි සකසනු ඇති අතර, එය එහි සියලු දත්ත මකනු ඇත."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ඔබ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER_0">%1$d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. තවත් අසාර්ථක උත්සාහයන් <xliff:g id="NUMBER_1">%2$d</xliff:g>කින් පසුව, මෙම දුරකථනය යළි සකසනු ඇති අතර, එය එහි සියලු දත්ත මකනු ඇත."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ඔබ ටැබ්ලට් පරිගණකය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. මෙම ටැබ්ලට් පරිගණකය යළි සකසනු ඇති අතර, එය එහි සියලු පදත්ත මකනු ඇත."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ඔබ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. මෙම දුරකථනය යළි සකසනු ඇති අතර, එය එහි සියලු පදත්ත මකනු ඇත."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ඔබ ටැබ්ලට් පරිගණකය අගුළු හැරීමට <xliff:g id="NUMBER_0">%1$d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. තවත් අසාර්ථක උත්සාහයන් <xliff:g id="NUMBER_1">%2$d</xliff:g>කින් පසුව, මෙම පරිශීලකයා ඉවත් කරනු ඇති අතර, එය සියලු පරිශීලක දත්ත මකනු ඇත."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ඔබ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER_0">%1$d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. තවත් අසාර්ථක උත්සාහයන් <xliff:g id="NUMBER_1">%2$d</xliff:g>කින් පසුව, මෙම පරිශීලකයා ඉවත් කරනු ඇති අතර, එය සියලු පරිශීලක දත්ත මකනු ඇත."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ඔබ ටැබ්ලට් පරිගණකය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. කාර්යාල පැතිකඩ ඉවත් කරනු ඇති අතර, එය සියලු පැතිකඩ දත්ත මකනු ඇත."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ඔබ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. කාර්යාල පැතිකඩ ඉවත් කරනු ඇති අතර, එය සියලු පැතිකඩ දත්ත මකනු ඇත."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ඔබ අගුළු ඇරිමේ රටාව <xliff:g id="NUMBER_0">%1$d</xliff:g> වතාවක් වැරදියට ඇඳ ඇත. තවත් අසාර්ථක උත්සාහ <xliff:g id="NUMBER_1">%2$d</xliff:g> කින් පසුව, ඊ-තැපැල් ගිණුම භාවිතා කරමින් ඔබගේ ටැබ්ලටයේ අගුළු ඇරීමට ඔබට පවසනු ඇත.\n\n නැවත තත්පර <xliff:g id="NUMBER_2">%3$d</xliff:g> කින් උත්සාහ කරන්න."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ඔබ වැරදියට <xliff:g id="NUMBER_0">%1$d</xliff:g> වතාවක් ඔබගේ අගුළු හැරීමේ රටාව ඇඳ ඇත. අසාර්ථක උත්සහ කිරීම් <xliff:g id="NUMBER_1">%2$d</xliff:g> න් පසුව, ඔබගේ ඊ-තැපැල් ලිපිනය භාවිතයෙන් ඔබගේ දුරකථනය අගුළු හැරීමට ඔබගෙන් අසයි.\n\n තත්පර <xliff:g id="NUMBER_2">%3$d</xliff:g> න් පසුව නැවත උත්සහ කරන්න."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"වැරදී SIM PIN කේතයකි, ඔබගේ දුරකතනයේ අඟුල හැරීමට ඔබගේ වාහකයා ඔබ දැන් සම්බන්ධ කරගත යුතුය."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">වැරදී SIM PIN කේතයකි, ඔබගේ දුරකථනයේ අඟුල හැරීමට ඔබගේ වාහකයා සම්බන්ධ කරගැනීමට පෙර ඔබ සතුව තවත් උත්සාහයන් <xliff:g id="NUMBER_1">%d</xliff:g>ක් ඉතිරිව ඇත.</item>
diff --git a/packages/SystemUI/res-keyguard/values-sk/strings.xml b/packages/SystemUI/res-keyguard/values-sk/strings.xml
index 27b0e8e..7be6ed2 100644
--- a/packages/SystemUI/res-keyguard/values-sk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sk/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Odomknete stlačením tlačidla ponuky."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Sieť je zablokovaná"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Žiadna SIM karta"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"V tablete nie je žiadna SIM karta."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"V telefóne nie je žiadna SIM karta."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Vložte SIM kartu."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM karta chýba alebo sa z nej nedá čítať. Vložte SIM kartu."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM karta je nepoužiteľná."</string>
@@ -85,17 +83,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Zadajte kód PIN s dĺžkou 4 až 8 číslic."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Kód PUK musí obsahovať 8 alebo viac číslic."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Znova zadajte správny kód PUK. Opakované pokusy zakážu SIM kartu natrvalo."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kódy PIN sa nezhodujú"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Príliš veľa pokusov o nakreslenie vzoru"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Už <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát ste zadali nesprávny kód PIN. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Už <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát ste zadali nesprávne heslo. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Už <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát ste použili nesprávny bezpečnostný vzor. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Tablet ste sa pokúsili <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%2$d</xliff:g>) bude tento tablet obnovený a všetky údaje, ktoré sú v ňom uložené, budú odstránené."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Telefón ste sa pokúsili <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%2$d</xliff:g>) bude tento telefón obnovený a všetky údaje, ktoré sú v ňom uložené, budú odstránené."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Tablet ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Tablet bude obnovený a všetky údaje, ktoré sú v ňom uložené, budú odstránené."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Telefón ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Telefón bude obnovený a všetky údaje, ktoré sú v ňom uložené, budú odstránené."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Tablet ste sa pokúsili <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%2$d</xliff:g>) bude tento používateľ odstránený a spolu s ním všetky jeho údaje."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Telefón ste sa pokúsili <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%2$d</xliff:g>) bude tento používateľ odstránený a spolu s ním všetky jeho údaje."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -104,10 +95,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Tablet ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Pracovný profil bude odstránený spolu so všetkými údajmi."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Telefón ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Pracovný profil bude odstránený spolu so všetkými údajmi."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Už ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne nakreslili svoj bezpečnostný vzor. Po ďalších <xliff:g id="NUMBER_1">%2$d</xliff:g> neúspešných pokusoch sa zobrazí výzva na odomknutie tabletu pomocou e-mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Už ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie telefónu pomocou e-mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%3$d</xliff:g>} s."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Nesprávny kód PIN SIM karty. Teraz musíte kontaktovať svojho operátora, aby vám odomkol zariadenie."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="few">Nesprávny kód PIN SIM karty. Zostávajú vám <xliff:g id="NUMBER_1">%d</xliff:g> pokusy.</item>
diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml
index 8f08b0b..6286d10 100644
--- a/packages/SystemUI/res-keyguard/values-sl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sl/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Če želite odkleniti, pritisnite meni."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Omrežje je zaklenjeno"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Ni kartice SIM"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"V tabličnem računalniku ni kartice SIM."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"V telefonu ni kartice SIM."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Vstavite kartico SIM."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Ni kartice SIM ali je ni mogoče prebrati. Vstavite kartico SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Neuporabna kartica SIM."</string>
@@ -85,17 +83,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Vnesite kodo PIN, ki vsebuje od štiri do osem številk."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Koda PUK mora biti 8- ali večmestno število."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Znova vnesite pravilno kodo PUK. Večkratni poskusi bodo trajno onemogočili kartico SIM."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kodi PIN se ne ujemata"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Preveč poskusov vnosa vzorca"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Kodo PIN ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat vnesli napačno. \n\nPoskusite znova čez <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Geslo ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat vnesli napačno. \n\nPoskusite znova čez <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat nepravilno narisali. \n\nPoskusite znova čez <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, bo ponastavljen in vsi podatki v njem bodo izbrisani."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, bo ponastavljen in vsi podatki v njem bodo izbrisani."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat, zato bo ponastavljen, vsi podatki v njem pa bodo izbrisani."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat, zato bo ponastavljen, vsi podatki v njem pa bodo izbrisani."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, bo ta uporabnik odstranjen in vsi podatki uporabnika bodo izbrisani."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, bo ta uporabnik odstranjen in vsi podatki uporabnika bodo izbrisani."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -104,10 +95,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat. Delovni profil bo odstranjen in vsi podatki profila bodo izbrisani."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat. Delovni profil bo odstranjen in vsi podatki profila bodo izbrisani."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat napačno vnesli. Če ga neuspešno poskusite vnesti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, boste pozvani, da tablični računalnik odklenete z e-poštnim računom.\n\n Poskusite znova čez <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat napačno vnesli. Če ga neuspešno poskusite vnesti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, boste pozvani, da telefon odklenete z Googlovimi podatki za prijavo.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Napačna koda PIN kartice SIM. Zdaj se boste morali za odklenitev naprave obrniti na operaterja."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">Napačna koda PIN kartice SIM. Na voljo imate še <xliff:g id="NUMBER_1">%d</xliff:g> poskus.</item>
diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml
index 1336188..3980b0e 100644
--- a/packages/SystemUI/res-keyguard/values-sq/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sq/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Shtyp \"Meny\" për të shkyçur."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rrjeti është i kyçur"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Nuk ka kartë SIM"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nuk ka kartë SIM në tablet."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Në telefon nuk ka kartë SIM."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Fut një kartë SIM."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Karta SIM mungon ose është e palexueshme. Fut një kartë të re SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Kartë SIM është e papërdorshme."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Shkruaj një PIN me 4 deri në 8 numra."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Kodi PUK duhet të jetë me 8 numra ose më shumë."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Fut kodin e saktë PUK. Provat e përsëritura do ta çaktivizojnë përgjithmonë kartën SIM."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kodet PIN nuk përputhen"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Shumë tentativa për motivin"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"E ke shkruar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë gabimisht kodin PIN.\n\nProvo sërish për <xliff:g id="NUMBER_1">%2$d</xliff:g> sekonda."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"E ke shkruar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë gabimisht fjalëkalimin.\n\nProvo sërish për <xliff:g id="NUMBER_1">%2$d</xliff:g> sekonda."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses për të vizatuar motivin tënd. \n\nProvo sërish për <xliff:g id="NUMBER_1">%2$d</xliff:g> sekonda."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë gabimisht për ta shkyçur tabletin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> përpjekjeve të tjera të pasuksesshme, tableti do të rivendoset, gjë që do të rivendosë të gjitha të dhënat e tij."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë gabimisht për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> përpjekjeve të tjera të pasuksesshme, telefoni do të rivendoset, gjë që do të fshijë të gjitha të dhënat e tij."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur tabletin. Ky tablet do të rivendoset, gjë që do të fshijë të gjitha të dhënat e tij."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur telefonin. Ky telefon do të rivendoset, gjë që do të fshijë të gjitha të dhënat e tij."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, përdoruesi do të hiqet dhe të gjitha të dhënat e përdoruesit në të, do të fshihen."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, përdoruesi do të hiqet dhe të gjitha të dhënat e përdoruesit në të, do të fshihen."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur tabletin. Profili i punës do të hiqet, gjë që do të fshijë të gjitha të dhënat e profilit."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur telefonin. Profili i punës do të hiqet, gjë që do të fshijë të gjitha të dhënat e profilit."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Ke vizatuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses motivin tënd të shkyçjes. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, do të të duhet ta shkyçësh tabletin duke përdorur një llogari mail-i.\n\n Provo sërish për <xliff:g id="NUMBER_2">%3$d</xliff:g> sekonda."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Ke vizatuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses motivin tënd të shkyçjes. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, do të të duhet ta shkyçësh telefonin duke përdorur një llogari mail-i.\n\n Provo sërish për <xliff:g id="NUMBER_2">%3$d</xliff:g> sekonda."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Kodi PIN i kartës SIM është i pasaktë. Tani duhet të kontaktosh me operatorin për ta shkyçur pajisjen tënde."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">Kodi PIN i kartës SIM është i pasaktë. Të kanë mbetur edhe <xliff:g id="NUMBER_1">%d</xliff:g> tentativa.</item>
diff --git a/packages/SystemUI/res-keyguard/values-sr/strings.xml b/packages/SystemUI/res-keyguard/values-sr/strings.xml
index 41869e9..9d5ed28 100644
--- a/packages/SystemUI/res-keyguard/values-sr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sr/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Притисните Мени да бисте откључали."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Мрежа је закључана"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Нема SIM картице"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"У таблету нема SIM картице."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"У телефону нема SIM картице."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Уметните SIM картицу."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM картица недостаје или не може да се прочита. Уметните SIM картицу."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM картица је неупотребљива."</string>
@@ -84,17 +82,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Унесите PIN који има 4–8 бројева."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK кôд треба да има 8 или више бројева."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Поново унесите тачан PUK кôд. Поновљени покушаји ће трајно онемогућити SIM."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN кодови се не подударају"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Превише покушаја уноса шаблона"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Унели сте погрешан PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> сек."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Унели сте погрешну лозинку <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> сек."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Нацртали сте нетачан шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> сек."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, овај таблет ће се ресетовати, чиме се бришу сви подаци корисника."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, овај телефон ће се ресетовати, чиме се бришу сви подаци корисника."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER">%d</xliff:g> пута. Овај таблет ће се ресетовати, чиме се бришу сви подаци."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пута. Овај телефон ће се ресетовати, чиме се бришу сви подаци."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, уклонићемо овог корисника, чиме се бришу сви подаци корисника."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, уклонићемо овог корисника, чиме се бришу сви подаци корисника."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -103,10 +94,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER">%d</xliff:g> пута. Уклонићемо профил за Work, чиме се бришу сви подаци са профила."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пута. Уклонићемо профил за Work, чиме се бришу сви подаци са профила."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Нетачно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, затражићемо да откључате таблет помоћу имејл налога.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Нетачно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, затражићемо да откључате телефон помоћу имејл налога.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Нетачан PIN кôд за SIM. Сада морате да контактирате мобилног оператера да бисте откључали уређај."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">Нетачан PIN кôд за SIM. Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушај.</item>
diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml
index c35fc1a..595f411 100644
--- a/packages/SystemUI/res-keyguard/values-sv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Lås upp genom att trycka på Meny."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Nätverk låst"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Inget SIM-kort"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Inget SIM-kort i surfplattan."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Inget SIM-kort i mobilen."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Sätt i ett SIM-kort."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM-kort saknas eller kan inte läsas. Sätt i ett SIM-kort."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Oanvändbart SIM-kort."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Ange en pinkod med fyra till åtta siffror."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-koden ska vara minst åtta siffror."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Ange rätt PUK-kod. Om försöken upprepas inaktiveras SIM-kortet permanent."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Pinkoderna stämmer inte överens"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"För många försök med grafiskt lösenord"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Du har angett fel pinkod <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunder."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök återställs surfplattan och all data raderas."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök återställs mobilen och all data raderas."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Surfplattan återställs och all data raderas."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Mobilen återställs och all data raderas."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök tas användaren bort och all användardata raderas."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök tas användaren bort och all användardata raderas."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Jobbprofilen tas bort och all profildata raderas."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Jobbprofilen tas bort och all profildata raderas."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök måste du låsa upp surfplattan med hjälp av ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök måste du låsa upp mobilen med hjälp av ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Du angav fel pinkod för SIM-kortet och måste nu kontakta operatören för att låsa upp enheten."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">Du angav fel pinkod för SIM-kortet. <xliff:g id="NUMBER_1">%d</xliff:g> försök återstår.</item>
diff --git a/packages/SystemUI/res-keyguard/values-sw/strings.xml b/packages/SystemUI/res-keyguard/values-sw/strings.xml
index 30749bd..cb6409e 100644
--- a/packages/SystemUI/res-keyguard/values-sw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sw/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Bonyeza Menyu ili kufungua."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Mtandao umefungwa"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Hakuna SIM kadi"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Hakuna SIM kadi katika kompyuta kibao."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Hakuna SIM kadi kwenye simu."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Weka SIM kadi."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM kadi haiko au haisomeki. Weka SIM kadi."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM kadi isiyotumika."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Andika PIN ya tarakimu 4 hadi 8."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Nambari ya PUK inafaa kuwa na tarakimu 8 au zaidi."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Weka tena nambari sahihi wa PUK. Ukirudia mara nyingi utafunga SIM kabisa."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Nambari za PIN hazifanani"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Umejaribu kuchora mchoro mara nyingi mno"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Umeandika vibaya PIN mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Umeandika vibaya nenosiri lako mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Umechora vibaya mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Umejaribu kufungua kompyuta kibao mara <xliff:g id="NUMBER_0">%1$d</xliff:g> bila mafanikio. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>,  kompyuta hii kibao itarejeshwa katika hali iliyotoka nayo kiwandani, hatua itakayofuta data yake yote."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Umejaribu kufungua simu mara <xliff:g id="NUMBER_0">%1$d</xliff:g> bila mafanikio. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, simu hii itarejeshwa katika hali iliyotoka nayo kiwandani, hatua itakayofuta data yake yote."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Umejaribu kufungua simu mara <xliff:g id="NUMBER">%d</xliff:g> bila mafanikio. Kompyuta hii kibao itarejeshwa katika hali iliyotoka nayo kiwandani, hatua itakayofuta data yake yote."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Umejaribu kufungua simu mara <xliff:g id="NUMBER">%d</xliff:g> bila mafanikio. Simu hii itarejeshwa katika hali iliyotoka nayo kiwandani, hatua itakayofuta data yake yote."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Umejaribu kufungua kompyuta kibao mara <xliff:g id="NUMBER_0">%1$d</xliff:g> bila mafanikio. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, mtumiaji huyu ataondolewa, hatua itakayofuta data yake yote."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Umejaribu kufungua simu mara <xliff:g id="NUMBER_0">%1$d</xliff:g> bila mafanikio. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, mtumiaji huyu ataondolewa, hatua itakayofuta data yake yote."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Umejaribu kufungua kompyuta kibao mara <xliff:g id="NUMBER">%d</xliff:g> bila mafanikio. Wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Umejaribu kufungua simu mara <xliff:g id="NUMBER">%d</xliff:g> bila mafanikio. Wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, utaombwa kufungua kompyuta yako kibao kwa kutumia akaunti yako ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, utaombwa kufungua simu yako kwa kutumia akaunti ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Nambari ya PIN ya SIM si sahihi, sasa lazima uwasiliane na mtoa huduma za mtandao ndipo ufungue kifaa chako."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">Nambari ya PIN ya SIM si sahihi. Una nafasi zingine <xliff:g id="NUMBER_1">%d</xliff:g> za kujaribu.</item>
diff --git a/packages/SystemUI/res-keyguard/values-ta/strings.xml b/packages/SystemUI/res-keyguard/values-ta/strings.xml
index 756bd8c..63e1a1e 100644
--- a/packages/SystemUI/res-keyguard/values-ta/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ta/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"திறக்க, மெனுவை அழுத்தவும்."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"நெட்வொர்க் பூட்டப்பட்டது"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"சிம் கார்டு இல்லை"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"டேப்லெட்டில் சிம் கார்டு இல்லை."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"மொபைலில் சிம் கார்டு இல்லை."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"சிம் கார்டைச் செருகவும்."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"சிம் கார்டு செருகப்படவில்லை அல்லது படிக்கக்கூடியதாக இல்லை. சிம் கார்டைச் செருகவும்."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"பயன்படுத்த முடியாத சிம் கார்டு."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4 இலிருந்து 8 எண்கள் உள்ள பின்னை உள்ளிடவும்."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK குறியீட்டில் 8 அல்லது அதற்கும் அதிகமான எண்கள் இருக்க வேண்டும்."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"சரியான PUK குறியீட்டை மீண்டும் உள்ளிடவும். தொடர் முயற்சிகள் சிம்மை நிரந்தரமாக முடக்கிவிடும்."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"பின் குறியீடுகள் பொருந்தவில்லை"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"பேட்டர்னை அதிக முறை தவறாக வரைந்துவிட்டீர்கள்"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"உங்கள் பின்னை <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக உள்ளிட்டுவிட்டீர்கள். \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> வினாடிகளில் மீண்டும் முயலவும்."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"உங்கள் கடவுச்சொல்லை <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக உள்ளிட்டுவிட்டீர்கள். \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> வினாடிகளில் மீண்டும் முயலவும்."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"திறப்பதற்கான பேட்டர்னை, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக வரைந்துவிட்டீர்கள். \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> வினாடிகளில் மீண்டும் முயலவும்."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"டேப்லெட்டைத் திறக்க, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக முயன்றால், இந்த டேப்லெட் மீட்டமைக்கப்பட்டு, அதன் எல்லாத் தரவும் நீக்கப்படும்."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"மொபைலைத் திறக்க, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக முயன்றால், இந்த மொபைல் மீட்டமைக்கப்பட்டு, அதன் எல்லாத் தரவும் நீக்கப்படும்."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"டேப்லெட்டைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இந்த டேப்லெட் மீட்டமைக்கப்பட்டு, அதன் எல்லாத் தரவும் நீக்கப்படும்."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"மொபைலைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இந்த மொபைல் மீட்டமைக்கப்பட்டு, அதன் எல்லாத் தரவும் நீக்கப்படும்."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"டேப்லெட்டைத் திறக்க, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக முயன்றால், இந்தப் பயனர் அகற்றப்பட்டு, எல்லாப் பயனர் தரவும் நீக்கப்படும்."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"மொபைலைத் திறக்க, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக முயன்றால், இந்தப் பயனர் அகற்றப்பட்டு, எல்லாப் பயனர் தரவும் நீக்கப்படும்."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"டேப்லெட்டைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். பணிக் கணக்கு அகற்றப்பட்டு, எல்லாச் சுயவிவரத் தரவும் நீக்கப்படும்."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"மொபைலைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். பணிக் கணக்கு அகற்றப்பட்டு, எல்லாச் சுயவிவரத் தரவும் நீக்கப்படும்."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"திறப்பதற்கான பேட்டர்னை, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக வரைந்துவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக வரைந்தால், மின்னஞ்சல் கணக்கைப் பயன்படுத்தி டேப்லெட்டைத் திறக்கும்படி கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> வினாடிகளில் மீண்டும் முயலவும்."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"திறப்பதற்கான பேட்டர்னை, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக வரைந்துவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக வரைந்தால், மின்னஞ்சல் கணக்கைப் பயன்படுத்தி மொபைலைத் திறக்கும்படி கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> வினாடிகளில் மீண்டும் முயலவும்."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"சிம்மின் பின் குறியீடு தவறானது. இனி சாதனத்தைத் திறக்க, உங்கள் தொலைத்தொடர்பு நிறுவனத்தைத் தொடர்புகொள்ள வேண்டும்."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">சிம்மின் பின் குறியீடு தவறானது, இன்னும் நீங்கள் <xliff:g id="NUMBER_1">%d</xliff:g> முறை முயலலாம்.</item>
diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml
index f9986d9..a2f45c9 100644
--- a/packages/SystemUI/res-keyguard/values-te/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-te/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"అన్‌లాక్ చేయడానికి మెనుని నొక్కండి."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"నెట్‌వర్క్ లాక్ చేయబడింది"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM కార్డ్ లేదు"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"టాబ్లెట్‌లో SIM కార్డ్ లేదు."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ఫోన్‌లో SIM కార్డ్ లేదు."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM కార్డ్‌ని చొప్పించండి."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM కార్డ్ లేదు లేదా ఆమోదయోగ్యం కాదు. SIM కార్డ్‌ని చొప్పించండి."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM కార్డ్ నిరుపయోగకరంగా మారింది."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4 నుండి 8 సంఖ్యలు ఉండే పిన్‌ను టైప్ చేయండి."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK కోడ్ అనేది 8 లేదా అంతకంటే ఎక్కువ సంఖ్యలు ఉండాలి."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"సరైన PUK కోడ్‌ను మళ్లీ నమోదు చేయండి. ఎక్కువసార్లు ప్రయత్నించడం వలన SIM శాశ్వతంగా నిలిపివేయబడుతుంది."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"పిన్ కోడ్‌లు సరిపోలలేదు"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"నమూనాని చాలా ఎక్కువసార్లు గీసారు"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"మీరు మీ పిన్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"మీరు మీ పాస్‌వర్డ్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"మీరు టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఈ టాబ్లెట్ రీసెట్ చేయబడుతుంది, తద్వారా ఇందులోని మొత్తం డేటా తొలగించబడుతుంది."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఈ ఫోన్ రీసెట్ చేయబడుతుంది, తద్వారా ఇందులోని మొత్తం డేటా తొలగించబడుతుంది."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"మీరు టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. ఈ టాబ్లెట్ రీసెట్ చేయబడుతుంది, తద్వారా ఇందులోని మొత్తం డేటా తొలగించబడుతుంది."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. ఈ ఫోన్ రీసెట్ చేయబడుతుంది, తద్వారా ఇందులోని మొత్తం డేటా తొలగించబడుతుంది."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"మీరు టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఈ వినియోగదారు తీసివేయబడతారు, తద్వారా వినియోగదారు డేటా మొత్తం తొలగించబడుతుంది."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"మీరు ఫోన్‌ని అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఈ వినియోగదారు తీసివేయబడతారు, తద్వారా వినియోగదారు డేటా మొత్తం తొలగించబడుతుంది."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"మీరు టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. కార్యాలయ ప్రొఫైల్ తీసివేయబడుతుంది, తద్వారా ప్రొఫైల్ డేటా మొత్తం తొలగించబడుతుంది."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"మీరు ఫోన్‌ని అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. కార్యాలయ ప్రొఫైల్ తీసివేయబడుతుంది, తద్వారా ప్రొఫైల్ డేటా మొత్తం తొలగించబడుతుంది."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, మీరు ఇమెయిల్ ఖాతాను ఉపయోగించి మీ టాబ్లెట్‌ను అన్‌లాక్ చేయాల్సి వస్తుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, మీరు ఇమెయిల్ ఖాతాను ఉపయోగించి మీ ఫోన్‌ను అన్‌లాక్ చేయాల్సి వస్తుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM పిన్ కోడ్ తప్పు, ఇప్పుడు మీ డివైజ్‌ను అన్‌లాక్ చేయాలంటే, మీరు తప్పనిసరిగా మీ క్యారియర్‌ను సంప్రదించాలి."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">SIM పిన్ కోడ్ తప్పు, మీకు మరో <xliff:g id="NUMBER_1">%d</xliff:g> ప్రయత్నాలు మిగిలి ఉన్నాయి.</item>
diff --git a/packages/SystemUI/res-keyguard/values-th/strings.xml b/packages/SystemUI/res-keyguard/values-th/strings.xml
index 62b04dc..ce40efb 100644
--- a/packages/SystemUI/res-keyguard/values-th/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-th/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"กด \"เมนู\" เพื่อปลดล็อก"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"เครือข่ายถูกล็อก"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"ไม่มีซิมการ์ด"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ไม่มีซิมการ์ดในแท็บเล็ต"</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ไม่มีซิมการ์ดในโทรศัพท์"</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"ใส่ซิมการ์ด"</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"ไม่มีซิมการ์ดหรือไม่สามารถอ่านได้ โปรดใส่ซิมการ์ด"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"ซิมการ์ดใช้ไม่ได้"</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"พิมพ์ PIN ซึ่งเป็นเลข 4-8 หลัก"</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"รหัส PUK ต้องเป็นตัวเลขอย่างน้อย 8 หลัก"</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"ใส่รหัส PUK ที่ถูกต้องอีกครั้ง การพยายามซ้ำหลายครั้งจะทำให้ซิมการ์ดถูกปิดใช้งานอย่างถาวร"</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"รหัส PIN ไม่ตรง"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"ลองหลายรูปแบบมากเกินไป"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"คุณพิมพ์ PIN ไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้งแล้ว \n\nโปรดลองอีกครั้งใน <xliff:g id="NUMBER_1">%2$d</xliff:g> วินาที"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"คุณพิมพ์รหัสผ่านไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้งแล้ว \n\nโปรดลองอีกครั้งใน <xliff:g id="NUMBER_1">%2$d</xliff:g> วินาที"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้งแล้ว \n\nโปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> วินาที"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะรีเซ็ตแท็บเล็ตเครื่องนี้ ซึ่งจะเป็นการลบข้อมูลทั้งหมดในเครื่อง"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะรีเซ็ตโทรศัพท์เครื่องนี้ ซึ่งจะเป็นการลบข้อมูลทั้งหมดในเครื่อง"</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะรีเซ็ตแท็บเล็ตเครื่องนี้ ซึ่งจะเป็นการลบข้อมูลทั้งหมดในเครื่อง"</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะรีเซ็ตโทรศัพท์เครื่องนี้ ซึ่งจะเป็นการลบข้อมูลทั้งหมดในเครื่อง"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะนำผู้ใช้รายนี้ออก ซึ่งจะเป็นการลบข้อมูลทั้งหมดของผู้ใช้"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะนำผู้ใช้รายนี้ออก ซึ่งจะเป็นการลบข้อมูลทั้งหมดของผู้ใช้"</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะนำโปรไฟล์งานออก ซึ่งจะเป็นการลบข้อมูลโปรไฟล์ทั้งหมด"</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะนำโปรไฟล์งานออก ซึ่งจะเป็นการลบข้อมูลโปรไฟล์ทั้งหมด"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกแท็บเล็ตโดยใช้บัญชีอีเมล\n\n โปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_2">%3$d</xliff:g> วินาที"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกโทรศัพท์โดยใช้บัญชีอีเมล\n\n โปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_2">%3$d</xliff:g> วินาที"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"รหัส PIN ของซิมไม่ถูกต้อง ตอนนี้คุณต้องติดต่อผู้ให้บริการเพื่อปลดล็อกอุปกรณ์ของคุณ"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">รหัส PIN ของซิมไม่ถูกต้อง คุณพยายามได้อีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง</item>
diff --git a/packages/SystemUI/res-keyguard/values-tl/strings.xml b/packages/SystemUI/res-keyguard/values-tl/strings.xml
index 4841eae..15f9616 100644
--- a/packages/SystemUI/res-keyguard/values-tl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tl/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Pindutin ang Menu upang i-unlock."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Naka-lock ang network"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Walang SIM card"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Walang SIM card sa tablet."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Walang SIM card sa telepono."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Maglagay ng SIM card."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Wala o hindi nababasa ang SIM card. Maglagay ng SIM card."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Hindi na magagamit na SIM card."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Mag-type ng PIN na 4 hanggang 8 numero."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Dapat ay 8 numero o higit pa ang PUK code."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Muling ilagay ang tamang PUK code. Permanenteng madi-disable ang SIM dahil sa paulit-ulit na pagsubok."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Hindi nagtutugma ang mga PIN code"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Masyadong maraming pagsubok sa pattern"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Na-type mo nang mali ang iyong PIN nang <xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%2$d</xliff:g> (na) segundo."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Na-type mo nang hindi tama ang iyong password nang <xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%2$d</xliff:g> (na) segundo."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%2$d</xliff:g> (na) segundo."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, ire-reset ang tablet na ito, na magiging dahilan upang ma-delete ang lahat ng data nito."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, ire-reset ang teleponong ito, na magiging dahilan upang ma-delete ang lahat ng data nito."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Ire-reset ang tablet na ito, na magiging dahilan upang ma-delete ang lahat ng data nito."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Ire-reset ang teleponong ito, na magiging dahilan upang ma-delete ang lahat ng data nito."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, aalisin ang user na ito, na magiging dahilan upang ma-delete ang lahat ng data ng user."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, aalisin ang user na ito, na magiging dahilan upang ma-delete ang lahat ng data ng user."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Aalisin ang profile sa trabaho, na magiging dahilan upang ma-delete ang lahat ng data sa profile."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Aalisin ang profile sa trabaho, na magiging dahilan upang ma-delete ang lahat ng data sa profile."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, hihilingin sa iyong i-unlock ang tablet mo gamit ang isang email account.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%3$d</xliff:g> (na) segundo."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, hihilingin sa iyong i-unlock ang telepono mo gamit ang isang email account.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%3$d</xliff:g> (na) segundo."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Mali ang PIN code ng SIM, dapat ka nang makipag-ugnayan sa iyong carrier upang i-unlock ang iyong device."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">Mali ang PIN code ng SIM, mayroon kang <xliff:g id="NUMBER_1">%d</xliff:g> natitirang pagsubok.</item>
diff --git a/packages/SystemUI/res-keyguard/values-tr/strings.xml b/packages/SystemUI/res-keyguard/values-tr/strings.xml
index 3985163..2ddf26e 100644
--- a/packages/SystemUI/res-keyguard/values-tr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tr/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Kilidi açmak için Menü\'ye basın."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Ağ kilitli"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM kart yok"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Tablette SIM kart yok."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefonda SIM kart yok."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"SIM kart takın."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM kart yok veya okunamıyor. Bir SIM kart takın."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Kullanılamayan SIM kartı"</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4 ila 8 haneli bir PIN yazın."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK kodu 8 veya daha çok basamaklı bir sayı olmalıdır."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Doğru PUK kodunu tekrar girin. Çok sayıda deneme yapılırsa SIM kart kalıcı olarak devre dışı bırakılır."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodları eşleşmiyor"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Çok fazla sayıda desen denemesi yapıldı"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"PIN kodunuzu <xliff:g id="NUMBER_0">%1$d</xliff:g> kez yanlış girdiniz. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> saniye içinde tekrar deneyin."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Şifrenizi <xliff:g id="NUMBER_0">%1$d</xliff:g> kez yanlış yazdınız. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> saniye içinde tekrar deneyin."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%1$d</xliff:g> kez yanlış çizdiniz. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> saniye içinde tekrar deneyin."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Tabletin kilidini <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız bu tablet sıfırlanacak ve tüm verileri silinecektir."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Telefonun kilidini <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız bu telefon sıfırlanacak ve tüm verileri silinecektir."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Tabletin kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. Bu tablet sıfırlanacak ve tüm verileri silinecektir."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Telefonun kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. Bu telefon sıfırlanacak ve tüm verileri silinecektir."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Tabletin kilidini <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız bu kullanıcı kaldırılacak ve tüm kullanıcı verileri silinecektir."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Telefonun kilidini <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız bu kullanıcı kaldırılacak ve tüm kullanıcı verileri silinecektir."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Tabletin kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. İş profili kaldırılacak ve tüm profil verileri silinecektir."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Telefonun kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. İş profili kaldırılacak ve tüm profil verileri silinecektir."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%1$d</xliff:g> defa yanlış çizdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız denemeden sonra, tabletinizin kilidini bir e-posta hesabı kullanarak açmanız istenir.\n<xliff:g id="NUMBER_2">%3$d</xliff:g>\n saniye içinde tekrar deneyin."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%1$d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız denemeden sonra telefonunuzun kilidini bir e-posta hesabı kullanarak açmanız istenir.\n<xliff:g id="NUMBER_2">%3$d</xliff:g>\n saniye içinde tekrar deneyin."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Yanlış SIM PIN kodu. Cihazınızın kilidini açmak için artık operatörünüzle bağlantı kurmanız gerekiyor."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">Yanlış SIM PIN kodu, <xliff:g id="NUMBER_1">%d</xliff:g> deneme hakkınız kaldı.</item>
diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml
index 097d735..fd15745 100644
--- a/packages/SystemUI/res-keyguard/values-uk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uk/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Натисніть меню, щоб розблокувати."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Мережу заблоковано"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Немає SIM-карти"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"У пристрої немає SIM-карти."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"У телефоні немає SIM-карти."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Вставте SIM-карту."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM-карта відсутня або недоступна для читання. Вставте SIM-карту."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Непридатна SIM-карта."</string>
@@ -85,17 +83,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Введіть PIN-код із 4–8 цифр."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK-код має складатися зі щонайменше 8 цифр."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Повторно введіть правильний PUK-код. Численні спроби назавжди вимкнуть SIM-карту."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-коди не збігаються"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Забагато спроб намалювати ключ"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"PIN-код неправильно введено стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nПовторіть спробу через <xliff:g id="NUMBER_1">%2$d</xliff:g> с."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Пароль неправильно введено стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nПовторіть спробу через <xliff:g id="NUMBER_1">%2$d</xliff:g> с."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nПовторіть спробу через <xliff:g id="NUMBER_1">%2$d</xliff:g> с."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Кількість невдалих спроб розблокувати планшет: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі буде скинуто налаштування планшета й видалено всі його дані."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі буде скинуто налаштування телефона й видалено всі його дані."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Кількість невдалих спроб розблокувати планшет: <xliff:g id="NUMBER">%d</xliff:g>. Буде скинуто налаштування цього планшета й видалено всі його дані."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER">%d</xliff:g>. Буде скинуто налаштування цього телефона й видалено всі його дані."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Кількість невдалих спроб розблокувати планшет: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі буде видалено цього користувача й усі його дані."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі буде видалено цього користувача й усі його дані."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -104,10 +95,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Кількість невдалих спроб розблокувати планшет: <xliff:g id="NUMBER">%d</xliff:g>. Буде видалено робочий профіль і всі його дані."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER">%d</xliff:g>. Буде видалено робочий профіль і всі його дані."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі з’явиться запит розблокувати планшет за допомогою облікового запису електронної пошти.\n\n Повторіть спробу через <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі з’явиться запит розблокувати телефон за допомогою облікового запису електронної пошти.\n\n Повторіть спробу через <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Неправильний PIN-код SIM-карти. Зв’яжіться зі своїм оператором, щоб розблокувати пристрій."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">Неправильний PIN-код SIM-карти. У вас залишилася <xliff:g id="NUMBER_1">%d</xliff:g> спроба.</item>
diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml
index 0a4340f..04d29c6 100644
--- a/packages/SystemUI/res-keyguard/values-ur/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"غیر مقفل کرنے کیلئے مینو دبائیں۔"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"نیٹ ورک مقفل ہو گیا"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"‏کوئی SIM کارڈ نہیں ہے"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"‏ٹیبلیٹ میں کوئی SIM کارڈ نہیں ہے۔"</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"‏فون میں کوئی SIM کارڈ نہيں ہے۔"</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"‏ایک SIM کارڈ داخل کریں۔"</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"‏SIM کارڈ غائب ہے یا پڑھنے کے قابل نہیں ہے۔ ایک SIM کارڈ داخل کریں۔"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"‏ناقابل استعمال SIM کارڈ۔"</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"‏ایسا PIN ٹائپ کریں جو 4 تا 8 اعداد پر مشتمل ہو۔"</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"‏PUK کوڈ 8 یا زائد اعداد پر مشتمل ہونا چاہیے۔"</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"‏صحیح PUK کوڈ دوبارہ درج کریں۔ بار بار کی کوششیں SIM کو مستقل طور پر غیر فعال کر دیں گی۔"</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"‏PIN کوڈز مماثل نہیں ہیں"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"پیٹرن کی بہت ساری کوششیں"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"‏آپ نے اپنا PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ٹائپ کیا ہے۔ \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"آپ نے اپنا پاسورڈ <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ٹائپ کیا ہے۔ \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، اس ٹیبلیٹ کو دوبارہ ترتیب دے دیا جائے گا، جس سے اس کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، اس فون کو دوبارہ ترتیب دے دیا جائے گا، جس سے اس کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ اس ٹیبلیٹ کو دوبارہ ترتیب دے دیا جائے گا، جس سے اس کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ اس فون کو دوبارہ ترتیب دے دیا جائے گا، جس سے اس کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، اس صارف کو ہٹا دیا جائے گا، جس سے صارف کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، اس صارف کو ہٹا دیا جائے گا، جس سے صارف کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ دفتری پروفائل ہٹا دیا جائے گا، جس سے پروفائل کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ دفتری پروفائل ہٹا دیا جائے گا، جس سے پروفائل کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کرکے اپنا ٹیبلیٹ غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کرکے اپنا فون غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"‏غلط SIM PIN کوڈ، اب آپ کو اپنا آلہ غیر مقفل کرنے کیلئے اپنے کیریئر سے رابطہ کرنا ہوگا۔"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">‏غلط SIM PIN کوڈ، آپ کے پاس <xliff:g id="NUMBER_1">%d</xliff:g> کوششیں بچی ہیں۔</item>
diff --git a/packages/SystemUI/res-keyguard/values-uz/strings.xml b/packages/SystemUI/res-keyguard/values-uz/strings.xml
index 1780ba01..ce461fe 100644
--- a/packages/SystemUI/res-keyguard/values-uz/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uz/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Qulfdan chiqarish uchun Menyu tugmasini bosing."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Tarmoq qulflangan"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM karta solinmagan"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Planshetingizda SIM karta yo‘q."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefoningizda SIM karta yo‘q."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Telefonga SIM karta soling."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM karta solinmagan yoki u yaroqsiz. SIM karta soling."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Foydalanib bo‘lmaydigan SIM karta."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"4-8 ta raqamdan iborat PIN kodni kiriting."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK kod kamida 8 ta raqamdan iborat bo‘lishi shart."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"To‘g‘ri PUK kodni qayta kiriting. Qayta-qayta urinishlar SIM kartani butunlay o‘chirib qo‘yadi."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kod mos kelmadi"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Grafik kalit juda ko‘p marta chizildi"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"PIN kod <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato kiritildi. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> soniyadan keyin qaytadan urining."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Parol <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato kiritildi. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> soniyadan keyin qaytadan urining."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Grafik kalit <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato kiritildi. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> soniyadan keyin qayta urining."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu planshetda zavod sozlamalari qayta tiklanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu telefonda zavod sozlamalari qayta tiklanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ushbu planshetda zavod sozlamalari qayta tiklanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ushbu telefonda zavod sozlamalari qayta tiklanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu foydalanuvchi o‘chirib tashlanadi va undagi barcha foydalanuvchi ma’lumotlari ham o‘chib ketadi."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu foydalanuvchi o‘chirib tashlanadi va undagi barcha foydalanuvchi ma’lumotlari ham o‘chib ketadi."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ishchi profil o‘chirib tashlanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ishchi profil o‘chirib tashlanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Grafik kalit <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato chizildi. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan keyin, sizdan e-pochtangizdan foydalanib, planshet qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan keyin yana urinib ko‘ring."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Grafik kalit <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato chizildi. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan keyin, sizdan e-pochtangizdan foydalanib, telefon qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan keyin qayta urinib ko‘ring."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM kartaning PIN kodi xato. Qurilma qulfini ochish uchun operatoringizga murojaat qiling."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">SIM kartaning PIN kodi noto‘g‘ri. Sizda yana <xliff:g id="NUMBER_1">%d</xliff:g> ta urinish qoldi.</item>
diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml
index 57b359a..3ac2cd2 100644
--- a/packages/SystemUI/res-keyguard/values-vi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Nhấn vào Menu để mở khóa."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Mạng đã bị khóa"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Không có thẻ SIM"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Không có thẻ SIM nào trong máy tính bảng."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Không có thẻ SIM nào trong điện thoại."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Lắp thẻ SIM."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Thẻ SIM bị thiếu hoặc không thể đọc được. Hãy lắp thẻ SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Thẻ SIM không sử dụng được."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Nhập mã PIN có từ 4 đến 8 số."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Mã PUK phải có từ 8 số trở lên."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Hãy nhập lại mã PUK chính xác. Nhiều lần lặp lại sẽ vô hiệu hóa vĩnh viễn thẻ SIM."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Mã PIN không khớp"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Quá nhiều lần nhập hình mở khóa"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Bạn đã nhập sai mã PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. \n\nHãy thử lại sau <xliff:g id="NUMBER_1">%2$d</xliff:g> giây."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Bạn đã nhập sai mật khẩu <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. \n\nHãy thử lại sau <xliff:g id="NUMBER_1">%2$d</xliff:g> giây."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Bạn đã vẽ không chính xác hình mở khóa <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. \n\nHãy thử lại sau <xliff:g id="NUMBER_1">%2$d</xliff:g> giây."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần mở khóa không thành công nữa, máy tính bảng này sẽ được đặt lại, tức là tất cả dữ liệu của máy tính bảng sẽ bị xóa."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần mở khóa không thành công nữa, điện thoại này sẽ được đặt lại, tức là tất cả dữ liệu của điện thoại sẽ bị xóa."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER">%d</xliff:g> lần. Máy tính bảng này sẽ được đặt lại, tức là tất cả dữ liệu của máy tính bảng sẽ bị xóa."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER">%d</xliff:g> lần. Điện thoại này sẽ được đặt lại, tức là tất cả dữ liệu của điện thoại sẽ bị xóa."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần mở khóa không thành công nữa, người dùng này sẽ bị xóa, tức là tất cả dữ liệu người dùng sẽ bị xóa."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần mở khóa không thành công nữa, người dùng này sẽ bị xóa, tức là tất cả dữ liệu người dùng sẽ bị xóa."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER">%d</xliff:g> lần. Hồ sơ công việc sẽ bị xóa, tức là tất cả dữ liệu hồ sơ sẽ bị xóa."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER">%d</xliff:g> lần. Hồ sơ công việc sẽ bị xóa, tức là tất cả dữ liệu hồ sơ sẽ bị xóa."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Bạn đã vẽ không chính xác hình mở khóa <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa máy tính bảng bằng tài khoản email.\n\n Hãy thử lại sau <xliff:g id="NUMBER_2">%3$d</xliff:g> giây."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Bạn đã vẽ không chính xác hình mở khóa <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa điện thoại bằng tài khoản email.\n\n Hãy thử lại sau <xliff:g id="NUMBER_2">%3$d</xliff:g> giây."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Mã PIN của SIM không chính xác, bây giờ bạn phải liên hệ với nhà cung cấp dịch vụ để mở khóa thiết bị của mình."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">Mã PIN của SIM không chính xác, bạn còn <xliff:g id="NUMBER_1">%d</xliff:g> lần thử.</item>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
index 54f1296..0d97946 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"按“菜单”即可解锁。"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"网络已锁定"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"没有 SIM 卡"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"平板电脑中没有 SIM 卡。"</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"手机中没有 SIM 卡。"</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"请插入 SIM 卡。"</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"SIM 卡缺失或无法读取,请插入 SIM 卡。"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM 卡无法使用。"</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"请输入 4 到 8 位数的 PIN 码。"</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK 码应至少包含 8 位数字。"</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"请重新输入正确的 PUK 码。如果屡次输入错误,SIM 卡将被永久停用。"</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN 码不匹配"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"图案尝试次数过多"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"您已经 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次输错 PIN 码。\n\n请在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒后重试。"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"您已经 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次输错密码。\n\n请在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒后重试。"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"您已经 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。\n\n请在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒后重试。"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"您尝试解锁平板电脑后失败的次数已达 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,平板电脑将会被重置,而这将删除其中的所有数据。"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"您尝试解锁手机后失败的次数已达 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,手机将会被重置,而这将删除其中的所有数据。"</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"您尝试解锁平板电脑后失败的次数已达 <xliff:g id="NUMBER">%d</xliff:g> 次。这部平板电脑将会被重置,而这将删除其中的所有数据。"</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"您尝试解锁手机后失败的次数已达 <xliff:g id="NUMBER">%d</xliff:g> 次。这部手机将会被重置,而这将删除其中的所有数据。"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"您尝试解锁平板电脑后失败的次数已达 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统将移除此用户,而这将删除所有的用户数据。"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"您尝试解锁手机后失败的次数已达 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统将移除此用户,而这将删除所有的用户数据。"</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"您尝试解锁平板电脑后失败的次数已达 <xliff:g id="NUMBER">%d</xliff:g> 次。系统将移除此工作资料,而这将删除所有的工作资料数据。"</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"您尝试解锁手机后失败的次数已达 <xliff:g id="NUMBER">%d</xliff:g> 次。系统将移除此工作资料,而这将删除所有的工作资料数据。"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"您已 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁平板电脑。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"您已 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁手机。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM 卡 PIN 码不正确,您现在必须联系运营商为您解锁设备。"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">SIM 卡 PIN 码不正确,您还有 <xliff:g id="NUMBER_1">%d</xliff:g> 次尝试机会。</item>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
index c49380e..1f55b32 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"按下 [選單] 即可解鎖。"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"網絡已鎖定"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"沒有 SIM 卡"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"平板電腦中沒有 SIM 卡。"</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"手機中沒有 SIM 卡。"</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"請插入 SIM 卡。"</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"找不到或無法讀取 SIM 卡。請插入 SIM 卡。"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM 卡無法使用。"</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"請輸入 4 至 8 位數的 PIN 碼。"</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK 碼應由 8 個或以上數字組成。"</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"請重新輸入正確的 PUK 碼。如果錯誤輸入的次數過多,SIM 卡將永久停用。"</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN 碼不符"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"上鎖圖案畫錯次數過多"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"您已輸入錯誤的 PIN 碼 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"您已輸入錯誤的密碼 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統將重設此平板電腦,而平板電腦的所有資料亦會一併刪除。"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統將重設此手機,而手機的所有資料亦會一併刪除。"</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統將重設此平板電腦,而平板電腦的所有資料亦會一併刪除。"</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統將重設此手機,而手機的所有資料亦會一併刪除。"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統將移除此使用者,而所有使用者資料亦會一併刪除。"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統將移除此使用者,而所有使用者資料亦會一併刪除。"</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統將移除此工作設定檔,而所有設定檔資料亦會一併刪除。"</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統將移除此工作設定檔,而所有設定檔資料亦會一併刪除。"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解鎖平板電腦。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解鎖手機。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM 卡 PIN 碼不正確,您現在必須聯絡流動網絡供應商為您的裝置解鎖。"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">SIM 卡的 PIN 碼不正確,您還有 <xliff:g id="NUMBER_1">%d</xliff:g> 次輸入機會。</item>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
index 4d4d360..97653c9 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"按選單鍵解鎖。"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"網路已鎖定"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"沒有 SIM 卡"</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"平板電腦中沒有 SIM 卡。"</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"手機中沒有 SIM 卡。"</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"請插入 SIM 卡。"</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"找不到或無法讀取 SIM 卡。請插入 SIM 卡。"</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"SIM 卡無法使用。"</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"請輸入 4 到 8 碼的 PIN 碼。"</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK 碼至少必須為 8 碼。"</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"請重新輸入正確的 PUK 碼。如果錯誤次數過多,SIM 卡將會遭到永久停用。"</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN 碼不符"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"解鎖圖案畫錯次數過多"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"你已輸入錯誤的 PIN 碼 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"你已輸入錯誤的密碼 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"你已畫出錯誤的解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%2$d</xliff:g> 秒後再試一次。"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"你嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,系統會重設這台平板電腦,其中的所有資料也會一併遭到刪除。"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"你嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,系統會重設這支手機,其中的所有資料也會一併遭到刪除。"</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"你嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統會重設這台平板電腦,其中的所有資料也會一併遭到刪除。"</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"你嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統會重設這支手機,其中的所有資料也會一併遭到刪除。"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"你嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,這位使用者將遭到移除,所有相關的使用者資料也會一併遭到刪除。"</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"你嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,這位使用者將遭到移除,所有相關的使用者資料也會一併遭到刪除。"</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"你嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。你的工作資料夾將遭到移除,所有設定檔資料也會一併遭到刪除。"</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"你嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。你的工作資料夾將遭到移除,所有設定檔資料也會一併遭到刪除。"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"你的解鎖圖案已畫錯 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,系統就會要求你透過電子郵件帳戶解鎖平板電腦。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"你的解鎖圖案已畫錯 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,系統就會要求你透過電子郵件帳戶解鎖手機。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM 卡的 PIN 碼輸入錯誤,你現在必須請電信業者為裝置解鎖。"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="other">SIM 卡的 PIN 碼輸入錯誤,你還可以再試 <xliff:g id="NUMBER_1">%d</xliff:g> 次。</item>
diff --git a/packages/SystemUI/res-keyguard/values-zu/strings.xml b/packages/SystemUI/res-keyguard/values-zu/strings.xml
index 604bb9d..fe81d02 100644
--- a/packages/SystemUI/res-keyguard/values-zu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zu/strings.xml
@@ -42,8 +42,6 @@
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Chofoza Menyu ukuvula."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Inethiwekhi ivaliwe"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Alikho ikhadi le-SIM."</string>
-    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Alikho ikhadi le-SIM efonini."</string>
-    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Alikho ikhadi le-SIM efonini."</string>
     <string name="keyguard_missing_sim_instructions" msgid="1162120926141335918">"Faka ikhadi le-SIM."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="2712623293749378570">"Ikhadi le-SIM alitholakali noma alifundeki. Sicela ufake ikhadi le-SIM."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="5842745213110966962">"Ikhadi le-SIM elingasetshenzisiwe."</string>
@@ -83,17 +81,10 @@
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Thayipha i-PIN enezinombolo ezingu-4 kuya kwezingu-8."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Ikhodi ye-PUK kufanele ibe yizinombolo ezingu-8 noma eziningi."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Faka kabusha ikhodi ye-PUK elungile. Imizamo ephindiwe izokhubaza unaphakade i-SIM."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Iphinikhodi ayifani"</string>
     <string name="kg_login_too_many_attempts" msgid="4519957179182578690">"Kunemizamo eminingi kakhulu yephathini!"</string>
     <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"Ubhale iphinikhodi ykho ngendlela engafanele izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\nZama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Ubhale iphasiwedi yakho ngendlela engafanele <xliff:g id="NUMBER_0">%1$d</xliff:g> izikhathi. \n\nZama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Udwebe iphathini yakho yokuvula ngendlela engafanele-<xliff:g id="NUMBER_0">%1$d</xliff:g>. \n\n Zama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%2$d</xliff:g>"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%2$d</xliff:g> engaphumelelanga, le thebulethi izosethwa kabusha, okuzosusa yonke idatha yayo."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%2$d</xliff:g> engaphumelelanga, le foni izosethwa kabusha, okuzosusa yonke idatha yayo."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Le thebulethi izosethwa kabusha, okuzosusa yonke idatha yayo."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Le foni izosethwa kabusha, okuzosusa yonke idatha yayo."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%2$d</xliff:g> engaphumelelanga, lo msebenzisi uzosuswa, okuzosusa yonke idatha yomsebenzisi."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%2$d</xliff:g> engaphumelelanga, lo msebenzisi uzosuswa, okuzosusa yonke idatha yomsebenzisi."</string>
     <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
     <skip />
     <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
@@ -102,10 +93,6 @@
     <skip />
     <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
     <skip />
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Iphrofayela yomsebenzi izosuswa, okuzosusa yonke idatha yephrofayela."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Iphrofayela yomsebenzi izosuswa, okuzosusa yonke idatha yephrofayela."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Udwebe ngokungalungile iphethini yakho yokuvula ngezikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphumelelanga kaningi engu-<xliff:g id="NUMBER_1">%2$d</xliff:g>, uzocelwa ukuthi uvule ithebulethi yakho usebenzisa i-akhawunti ye-imeyili.\n\nZama futhi kumasekhondi angu-<xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Ukulayisha ungenisa iphathini yakho yokuvula ngendlela engalungile izikhathi ezi-<xliff:g id="NUMBER_0">%1$d</xliff:g> Emva kweminye imizamo engu-<xliff:g id="NUMBER_1">%2$d</xliff:g>, uzocelwa ukuvula ifoni yakho usebenzisa ukungena ngemvume ku-Google\n\n Zame futhi emumva kwengu- <xliff:g id="NUMBER_2">%3$d</xliff:g> imizuzwana."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Ikhodi yephinikhodi ye-SIM engalungile manje kumele uxhumane nenkampini yenethiwekhi yakho ukuvula idivayisi yakho."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
       <item quantity="one">Ikhodi engalungile yephinikhodi ye-SIM, unemizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g> esele.</item>
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 485240a..f7e9fed 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -91,10 +91,6 @@
     <string name="keyguard_network_locked_message">Network locked</string>
     <!-- Shown when there is no SIM card. -->
     <string name="keyguard_missing_sim_message_short">No SIM card</string>
-    <!-- Shown when there is no SIM card. -->
-    <string name="keyguard_missing_sim_message" product="tablet">No SIM card in tablet.</string>
-    <!-- Shown when there is no SIM card. -->
-    <string name="keyguard_missing_sim_message" product="default">No SIM card in phone.</string>
     <!-- Shown to ask the user to insert a SIM card. -->
     <string name="keyguard_missing_sim_instructions">Insert a SIM card.</string>
     <!-- Shown to ask the user to insert a SIM card when sim is missing or not readable. -->
@@ -189,8 +185,6 @@
     <string name="kg_invalid_sim_puk_hint">PUK code should be 8 numbers or more.</string>
     <!-- Message shown when the user enters an invalid PUK code -->
     <string name="kg_invalid_puk">Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM.</string>
-      <!-- String shown in PUK screen when PIN codes don't match -->
-    <string name="kg_invalid_confirm_pin_hint" product="default">PIN codes does not match</string>
     <!-- Message shown when the user exceeds the maximum number of pattern attempts -->
     <string name="kg_login_too_many_attempts">Too many pattern attempts</string>
     <!-- Message shown in dialog when max number of attempts are reached for PIN screen of keyguard -->
@@ -208,92 +202,6 @@
         \n\nTry again in <xliff:g id="number">%2$d</xliff:g> seconds.
     </string>
 
-    <!-- Message shown when user is almost at the limit of password attempts where the device will be wiped. [CHAR LIMIT=none] -->
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet">
-       You have incorrectly attempted to unlock the tablet <xliff:g id="number">%1$d</xliff:g> times.
-       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
-       this tablet will be reset, which will delete all its data.
-    </string>
-    <!-- Message shown when user is almost at the limit of password attempts where the device will be wiped. [CHAR LIMIT=none] -->
-    <string name="kg_failed_attempts_almost_at_wipe" product="default">
-       You have incorrectly attempted to unlock the phone <xliff:g id="number">%1$d</xliff:g> times.
-       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
-       this phone will be reset, which will delete all its data.
-    </string>
-    <!-- Message shown in dialog when user has exceeded the maximum attempts and the device will now be wiped [CHAR LIMIT=none] -->
-    <string name="kg_failed_attempts_now_wiping" product="tablet">
-       You have incorrectly attempted to unlock the tablet <xliff:g id="number">%d</xliff:g> times.
-       This tablet will be reset, which will delete all its data.
-    </string>
-    <!-- Message shown in dialog when user has exceeded the maximum attempts and the device will now be wiped [CHAR LIMIT=none] -->
-    <string name="kg_failed_attempts_now_wiping" product="default">
-       You have incorrectly attempted to unlock the phone <xliff:g id="number">%d</xliff:g> times.
-       This phone will be reset, which will delete all its data.
-    </string>
-
-    <!-- Message shown when user is almost at the limit of password attempts where the user will be removed. [CHAR LIMIT=none] -->
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet">
-       You have incorrectly attempted to unlock the tablet <xliff:g id="number">%1$d</xliff:g> times.
-       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
-       this user will be removed, which will delete all user data.
-    </string>
-    <!-- Message shown when user is almost at the limit of password attempts where the user will be removed. [CHAR LIMIT=none] -->
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default">
-       You have incorrectly attempted to unlock the phone <xliff:g id="number">%1$d</xliff:g> times.
-       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
-       this user will be removed, which will delete all user data.
-    </string>
-    <!-- Message shown in dialog when user has exceeded the maximum attempts and the user will be removed. [CHAR LIMIT=none] -->
-    <string name="kg_failed_attempts_now_erasing_user" product="tablet">
-       You have incorrectly attempted to unlock the tablet <xliff:g id="number">%d</xliff:g> times.
-       This user will be removed, which will delete all user data.
-    </string>
-    <!-- Message shown in dialog when user has exceeded the maximum attempts and the user will be removed. [CHAR LIMIT=none] -->
-    <string name="kg_failed_attempts_now_erasing_user" product="default">
-       You have incorrectly attempted to unlock the phone <xliff:g id="number">%d</xliff:g> times.
-       This user will be removed, which will delete all user data.
-    </string>
-
-    <!-- Message shown when user is almost at the limit of password attempts where the profile will be removed. [CHAR LIMIT=none] -->
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet">
-       You have incorrectly attempted to unlock the tablet <xliff:g id="number">%1$d</xliff:g> times.
-       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
-       the work profile will be removed, which will delete all profile data.
-    </string>
-    <!-- Message shown when user is almost at the limit of password attempts where the profile will be removed. [CHAR LIMIT=none] -->
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default">
-       You have incorrectly attempted to unlock the phone <xliff:g id="number">%1$d</xliff:g> times.
-       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
-       the work profile will be removed, which will delete all profile data.
-    </string>
-    <!-- Message shown in dialog when user has exceeded the maximum attempts and the profile will be removed. [CHAR LIMIT=none] -->
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet">
-       You have incorrectly attempted to unlock the tablet <xliff:g id="number">%d</xliff:g> times.
-       The work profile will be removed, which will delete all profile data.
-    </string>
-    <!-- Message shown in dialog when user has exceeded the maximum attempts and the profile will be removed. [CHAR LIMIT=none] -->
-    <string name="kg_failed_attempts_now_erasing_profile" product="default">
-       You have incorrectly attempted to unlock the phone <xliff:g id="number">%d</xliff:g> times.
-       The work profile will be removed, which will delete all profile data.
-    </string>
-
-    <!-- Message shown in dialog when user is almost at the limit where they will be
-    locked out and may have to enter an alternate username/password to unlock the phone -->
-    <string name="kg_failed_attempts_almost_at_login" product="tablet">
-       You have incorrectly drawn your unlock pattern <xliff:g id="number">%1$d</xliff:g> times.
-       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
-       you will be asked to unlock your tablet using an email account.\n\n
-       Try again in <xliff:g id="number">%3$d</xliff:g> seconds.
-    </string>
-    <!-- Message shown in dialog when user is almost at the limit where they will be
-    locked out and may have to enter an alternate username/password to unlock the phone -->
-    <string name="kg_failed_attempts_almost_at_login" product="default">
-       You have incorrectly drawn your unlock pattern <xliff:g id="number">%1$d</xliff:g> times.
-       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
-       you will be asked to unlock your phone using an email account.\n\n
-       Try again in <xliff:g id="number">%3$d</xliff:g> seconds.
-    </string>
-
     <!-- Instructions telling the user that they entered the wrong SIM PIN for the last time.
          Displayed in a dialog box.  -->
     <string name="kg_password_wrong_pin_code_pukked">Incorrect SIM PIN code you must now contact your carrier to unlock your device.</string>
diff --git a/packages/SystemUI/res-product/values-af/strings.xml b/packages/SystemUI/res-product/values-af/strings.xml
new file mode 100644
index 0000000..61ccec8
--- /dev/null
+++ b/packages/SystemUI/res-product/values-af/strings.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Geen SIM-kaart in tablet nie."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Geen SIM-kaart in foon nie."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-kodes stem nie ooreen nie"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Jy het die tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal hierdie tablet teruggestel word, wat al sy data sal uitvee."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Jy het die foon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal hierdie foon teruggestel word, wat al sy data sal uitvee."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Jy het die tablet <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Hierdie tablet sal teruggestel word, wat al sy data sal uitvee."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Jy het die foon <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Hierdie foon sal teruggestel word, wat al sy data sal uitvee."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Jy het die tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal hierdie gebruiker verwyder word, wat alle gebruikerdata sal uitvee."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Jy het die foon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal hierdie gebruiker verwyder word, wat alle gebruikerdata sal uitvee."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Die Android TV-toestel gaan binnekort afskakel; druk \'n knoppie om dit aan te hou."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Die toestel gaan binnekort afskakel; druk om dit aan te hou."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Jy het die tablet <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Die werkprofiel sal verwyder word, wat alle profieldata sal uitvee."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Jy het die foon <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Die werkprofiel sal verwyder word, wat alle profieldata sal uitvee."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd geteken. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal jy gevra word om jou e-posrekening te gebruik om jou tablet te ontsluit.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%3$d</xliff:g> sekondes."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd geteken. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal jy gevra word om jou e-posrekening te gebruik om jou foon te ontsluit.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%3$d</xliff:g> sekondes."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-am/strings.xml b/packages/SystemUI/res-product/values-am/strings.xml
new file mode 100644
index 0000000..4628b2b
--- /dev/null
+++ b/packages/SystemUI/res-product/values-am/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"በጡባዊ ውስጥ ምንም ሲም ካርድ የለም።"</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"በስልክ ውስጥ ምንም ሲም ካርድ የለም።"</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ፒን ኮዶቹ አይገጣጠሙም"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ጡባዊውን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ጡባዊ ዳግም ይጀመራል፣ ይህም ሁሉንም ውሂብ ይሰርዛል።"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ስልኩን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ስልክ ዳግም ይጀመራል፣ ይህም ሁሉንም ውሂብ ይሰርዛል።"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ጡባዊውን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ ሁኔታ ለማስከፈት ሞክረዋል። ስልኩ ዳግም ይጀመራል፣ ይህም ሁሉንም ውሂቡን ይሰርዛል።"</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ስልኩን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ ሁኔታ ለማስከፈት ሞክረዋል። ስልኩ ዳግም ይጀመራል፣ ይህም ሁሉንም ውሂቡን ይሰርዛል።"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ጡባዊውን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ተጠቃሚ ይወገዳል፣ ይህም ሁሉንም የተጠቃሚ ውሂብ ይሰርዛል።"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ስልኩን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ተጠቃሚ ይወገዳል፣ ይህም ሁሉንም የተጠቃሚ ውሂብ ይሰርዛል።"</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"የAndroid TV መሣሪያው በቅርቡ ይጠፋል፣ እንደበራ ለማቆየት ይጫኑ።"</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"መሣሪያው በቅርቡ ይጠፋል፤ እንደበራ ለማቆየት ይጫኑ።"</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ጡባዊውን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለመክፈት ሞክረዋል። የስራ መገለጫው ይወገዳል፣ ይህም ሁሉንም የመገለጫ ውሂብ ይሰርዛል።"</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ስልኩን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለመክፈት ሞክረዋል። የስራ መገለጫው ይወገዳል፣ ይህም ሁሉንም የመገለጫ ውሂብ ይሰርዛል።"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ጡባዊዎን እንዲከፍቱ ይጠየቃሉ።\n\n ከ<xliff:g id="NUMBER_2">%3$d</xliff:g> ከሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ስልክዎን እንዲከፍቱ ይጠየቃሉ።\n\nእባክዎ ከ<xliff:g id="NUMBER_2">%3$d</xliff:g> ሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-ar/strings.xml b/packages/SystemUI/res-product/values-ar/strings.xml
new file mode 100644
index 0000000..09aa42e
--- /dev/null
+++ b/packages/SystemUI/res-product/values-ar/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"‏ليست هناك شريحة SIM في الجهاز اللوحي."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"‏ليست هناك شريحة SIM في الهاتف."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"لا يتطابق رمز رقم التعريف الشخصي"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة غير ناجحة أخرى، ستتم إعادة تعيين هذا الجهاز، ومن ثم يتم حذف جميع بياناته."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة غير ناجحة أخرى، ستتم إعادة تعيين هذا الهاتف، ومن ثم يتم حذف جميع بياناته."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <xliff:g id="NUMBER">%d</xliff:g> مرة. ستتم إعادة تعيين هذا الجهاز، ومن ثم يتم حذف جميع بياناته."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER">%d</xliff:g> مرة. ستتم إعادة تعيين هذا الهاتف، ومن ثم يتم حذف جميع بياناته."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة غير ناجحة أخرى، ستتم إزالة هذا المستخدم، ومن ثم يتم حذف جميع بيانات المستخدم."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة غير ناجحة أخرى، ستتم إزالة هذا المستخدم، ومن ثم يتم حذف جميع بيانات المستخدم."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"‏سيتم إيقاف جهاز Android TV قريبًا، اضغط على أحد الأزرار لمواصلة تشغيله."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"سيتم إيقاف الجهاز قريبًا، اضغط لمواصلة تشغيله."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <xliff:g id="NUMBER">%d</xliff:g> مرة. ستتم إزالة الملف الشخصي للعمل، ومن ثم يتم حذف جميع بياناته."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER">%d</xliff:g> مرة. ستتم إزالة الملف الشخصي للعمل، ومن ثم يتم حذف جميع بياناته."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"لقد رسمت نقش فتح القفل بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة الأخرى، ستطالَب بإلغاء تأمين الجهاز اللوحي باستخدام معلومات حساب بريد إلكتروني.\n\n أعد المحاولة خلال <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"لقد رسمت نقش فتح القفل بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة الأخرى، ستُطالب بإلغاء تأمين الهاتف باستخدام حساب بريد إلكتروني لإلغاء تأمين الهاتف.\n\n أعد المحاولة خلال <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-as/strings.xml b/packages/SystemUI/res-product/values-as/strings.xml
new file mode 100644
index 0000000..1f1ca09
--- /dev/null
+++ b/packages/SystemUI/res-product/values-as/strings.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"টেবলেটত ছিম কার্ড নাই।"</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ফ\'নত ছিম কার্ড নাই।"</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"পিন ক\'ড মিলা নাই"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"আপুনি টেবলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে টেবলেটটো ৰিছেট কৰা হ\'ব, যি কার্যই টেবলেটটোত থকা সকলো ডেটা মচিব।"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"আপুনি ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে ফ\'নটো ৰিছেট কৰা হ\'ব, যি কার্যই ফ\'নটোত থকা সকলো ডেটা মচিব।"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"আপুনি টেবলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। এই টেবলেটটো ৰিছেট কৰা হ\'ব, যি কার্যই ইয়াৰ সকলো ডেটা মচিব।"</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"আপুনি ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। এই ফ\'নটো ৰিছেট কৰা হ\'ব, যিয়ে ইয়াৰ সকলো ডেটা মচিব।"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"আপুনি টেবলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে এই ব্যৱহাৰকাৰীক আঁতৰোৱা হ\'ব, যিয়ে ব্যৱহাৰকাৰীৰ সকলো ডেটা মচিব।"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"আপুনি ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিলে এই ব্যৱহাৰকাৰীক আঁতৰোৱা হ\'ব, যিয়ে ব্যৱহাৰকাৰীৰ সকলো ডেটা মচিব।"</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for notification_bubble_title (8330481035191903164) -->
+    <skip/>
+    <!-- no translation found for notification_channel_summary_bubble (7235935211580860537) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ডিভাইচটো অতি সোনকালে অফ হ\'ব, এইটো অন ৰাখিবলৈ যিকোনো এটা বুটাম টিপক।"</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"এই ডিভাইচটো অতি সোনকালে অফ হ\'ব, এইটো অন ৰাখিবলৈ টিপক।"</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"আপুনি টেবলেটটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইলটো আঁতৰোৱা হ\'ব, যি কার্যই প্ৰ\'ফাইলটোৰ সকলো ডেটা মচিব।"</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"আপুনি ফ\'নটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুল প্ৰয়াস কৰিছে। আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইলটো আঁতৰোৱা হ\'ব, যিয়ে প্ৰ\'ফাইলটোৰ সকলো ডেটা মচিব।"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"আপুনি আপোনাৰ আনলক আৰ্হিটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আঁকিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g>তকৈ বেছি বাৰ ভুল আৰ্হি আঁকিলে আপোনাৰ টেবলেটটো কোনো একাউণ্টৰ জৰিয়তে আনলক কৰিবলৈ কোৱা হ\'ব।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> ছেকেণ্ডৰ পিছত আকৌ চেষ্টা কৰক।"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"আপুনি আপোনাৰ আনলক আৰ্হিটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আঁকিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g>তকৈ বেছি বাৰ ভুল আৰ্হি আঁকিলে আপোনাৰ ফ\'নটো কোনো একাউণ্টৰ জৰিয়তে আনলক কৰিবলৈ কোৱা হ\'ব।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> ছেকেণ্ডৰ পিছত আকৌ চেষ্টা কৰক।"</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-az/strings.xml b/packages/SystemUI/res-product/values-az/strings.xml
new file mode 100644
index 0000000..c34b142
--- /dev/null
+++ b/packages/SystemUI/res-product/values-az/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Planşetdə SIM kart yoxdur."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefonda SIM kart yoxdur."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodlar uyğun gəlmir"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Planşetin kilidini açmaq üçün <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış cəhdlər etmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bu planşet sıfırlanacaq və bütün data silinəcək."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış cəhdlər etmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bu telefon sıfırlanacaq və bütün data silinəcək."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Planşetin kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhdlər etmisiniz. Bu planşet sıfırlanacaq və bütün data silinəcək."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhdlər etmisiniz. Bu telefon sıfırlanacaq və bütün data silinəcək."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Planşetin kilidini açmaq üçün <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bu istifadəçi silinəcək və bütün istifadəçi datası ləğv ediləcək."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bu istifadəçi silinəcək və bütün istifadəçi datası ləğv ediləcək."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV cihazı tezliklə sönəcək; aktiv saxlamaq üçün düyməyə basın."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Cihaz tezliklə sönəcək; aktiv saxlamaq üçün basın."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Planşetin kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhdlər etmisiniz. İş profili silinəcək və bütün data ləğv ediləcək."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhdlər etmisiniz. İş profili silinəcək və bütün data ləğv ediləcək."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Kilid açma modelini <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra planşet kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra yenidən cəhd edin."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Kilid açma modelini artıq <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra telefon kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra yenidən cəhd edin."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..e753e74
--- /dev/null
+++ b/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"U tabletu nema SIM kartice."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"U telefonu nema SIM kartice."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodovi se ne podudaraju"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, ovaj tablet će se resetovati, čime se brišu svi podaci korisnika."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, ovaj telefon će se resetovati, čime se brišu svi podaci korisnika."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER">%d</xliff:g> puta. Ovaj tablet će se resetovati, čime se brišu svi podaci."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Ovaj telefon će se resetovati, čime se brišu svi podaci."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, uklonićemo ovog korisnika, čime se brišu svi podaci korisnika."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, uklonićemo ovog korisnika, čime se brišu svi podaci korisnika."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV će se uskoro isključiti. Pritisnite dugme da bi ostao uključen."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Uređaj će se uskoro isključiti. Pritisnite da bi ostao uključen."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER">%d</xliff:g> puta. Uklonićemo profil za Work, čime se brišu svi podaci sa profila."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Uklonićemo profil za Work, čime se brišu svi podaci sa profila."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Netačno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, zatražićemo da otključate tablet pomoću imejl naloga.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Netačno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, zatražićemo da otključate telefon pomoću imejl naloga.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-be/strings.xml b/packages/SystemUI/res-product/values-be/strings.xml
new file mode 100644
index 0000000..e2dbd24
--- /dev/null
+++ b/packages/SystemUI/res-product/values-be/strings.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"У планшэце няма SIM-карты."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"У тэлефоне няма SIM-карты."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-коды не супадаюць"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Вы не змаглі разблакіраваць планшэт столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) ён будзе скінуты да заводскіх налад, гэта прывядзе да выдалення ўсіх даных."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) ён будзе скінуты да заводскіх налад, гэта прывядзе да выдалення ўсіх даных."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Вы не змаглі разблакіраваць планшэт столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Цяпер ён будзе скінуты да заводскіх налад, гэта прывядзе да выдалення ўсіх даных."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Цяпер ён будзе скінуты да заводскіх налад, гэта прывядзе да выдалення ўсіх даных."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Вы не змаглі разблакіраваць планшэт столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) гэты карыстальнік будзе выдалены, гэта прывядзе да выдалення ўсіх карыстальніцкіх даных."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) гэты карыстальнік будзе выдалены, гэта прывядзе да выдалення ўсіх карыстальніцкіх даных."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- String.format failed for translation -->
+    <!-- no translation found for accessibility_battery_level (5143715405241138822) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Прылада Android TV неўзабаве выключыцца. Каб пакінуць яе ўключанай, націсніце кнопку."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Прылада неўзабаве выключыцца. Націсніце, каб пакінуць яе ўключанай."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Вы не змаглі разблакіраваць планшэт столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Працоўны профіль будзе выдалены, гэта прывядзе да выдалення ўсіх даных у профілі."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Працоўны профіль будзе выдалены, гэта прывядзе да выдалення ўсіх даных у профілі."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Вы няправільна ўвялі ўзор разблакіроўкі столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакіраваць планшэт, увайшоўшы ва ўліковы запіс электроннай пошты.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Вы няправільна ўвялі ўзор разблакіроўкі столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакіраваць тэлефон, увайшоўшы ва ўліковы запіс электроннай пошты.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-bg/strings.xml b/packages/SystemUI/res-product/values-bg/strings.xml
new file mode 100644
index 0000000..4ae6d4c
--- /dev/null
+++ b/packages/SystemUI/res-product/values-bg/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"В таблета няма SIM карта."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"В телефона няма SIM карта."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ПИН кодовете не съвпадат"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Опитахте да отключите таблета и сбъркахте <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита той ще бъде нулиран, при което ще се изтрият всичките му данни."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Опитахте да отключите телефона и сбъркахте <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита той ще бъде нулиран, при което ще се изтрият всичките му данни."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Опитахте да отключите таблета и сбъркахте <xliff:g id="NUMBER">%d</xliff:g> пъти. Той ще бъде нулиран, при което ще се изтрият всичките му данни."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Опитахте да отключите телефона и сбъркахте <xliff:g id="NUMBER">%d</xliff:g> пъти. Той ще бъде нулиран, при което ще се изтрият всичките му данни."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Опитахте да отключите таблета и сбъркахте <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита този потребител ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Опитахте да отключите телефона и сбъркахте <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита този потребител ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Устройството с Android TV скоро ще се изключи. Натиснете бутон, за да остане включено."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Устройството скоро ще се изключи. Натиснете, за да остане включено."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Опитахте да отключите таблета и сбъркахте <xliff:g id="NUMBER">%d</xliff:g> пъти. Служебният потребителски профил ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Опитахте да отключите телефона и сбъркахте <xliff:g id="NUMBER">%d</xliff:g> пъти. Служебният потребителски профил ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита ще бъдете помолени да отключите таблета си посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита ще бъдете помолени да отключите телефона посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-bn/strings.xml b/packages/SystemUI/res-product/values-bn/strings.xml
new file mode 100644
index 0000000..260f7bc
--- /dev/null
+++ b/packages/SystemUI/res-product/values-bn/strings.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ট্যাবলেটের মধ্যে কোনো সিম কার্ড নেই।"</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ফোনের মধ্যে কোনো সিম কার্ড নেই।"</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"পিন কোডগুলি মিলছে না"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে ট্যাবলেটটি আনলক করার চেষ্টা করেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর এই ট্যাবলেটটিকে রিসেট করা হবে, যার ফলে এর সমস্ত ডেটা মুছে যাবে।"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে ফোনটি আনলক করার চেষ্টা করেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর এই ফোনটিকে রিসেট করা হবে, যার ফলে এর সমস্ত ডেটা মুছে যাবে।"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুলভাবে ট্যাবলেটটি আনলক করার চেষ্টা করেছেন। এই ফোনটিকে রিসেট করা হবে, যার ফলে এর সমস্ত ডেটা মুছে যাবে।"</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুলভাবে ফোনটি আনলক করার চেষ্টা করেছেন। এই ফোনটিকে রিসেট করা হবে, যার ফলে এর সমস্ত ডেটা মুছে যাবে।"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে ট্যাবলেটটি আনলক করার চেষ্টা করেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর এই ব্যবহারকারীকে সরিয়ে দেওয়া হবে, যার ফলে ব্যবহারকারীর সমস্ত ডেটা মুছে যাবে।"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে ফোনটি আনলক করার চেষ্টা করেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর এই ব্যবহারকারীকে সরিয়ে দেওয়া হবে, যার ফলে ব্যবহারকারীর সমস্ত ডেটা মুছে যাবে।"</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for notification_bubble_title (8330481035191903164) -->
+    <skip/>
+    <!-- no translation found for notification_channel_summary_bubble (7235935211580860537) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ডিভাইস শীঘ্রই বন্ধ হয়ে যাবে, চালু রাখতে বোতাম প্রেস করুন।"</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ডিভাইস শীঘ্রই বন্ধ হয়ে যাবে, চালু রাখতে প্রেস করুন।"</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুলভাবে ট্যাবলেটটি আনলক করার চেষ্টা করেছেন। কাজের প্রোফাইলটি সরিয়ে দেওয়া হবে, যার ফলে প্রোফাইলের সমস্ত ডেটা মুছে যাবে।"</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুলভাবে ফোনটি আনলক করার চেষ্টা করেছেন। কাজের প্রোফাইলটি সরিয়ে দেওয়া হবে, যার ফলে প্রোফাইলের সমস্ত ডেটা মুছে যাবে।"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে আনলকের প্যাটার্ন এঁকেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর আপনাকে একটি ইমেল অ্যাকাউন্টের মাধ্যমে আপনার ট্যাবলেটটি আনলক করতে বলা হবে।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন।"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুলভাবে আনলকের প্যাটার্ন এঁকেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টার পর আপনাকে একটি ইমেল অ্যাকাউন্টের মাধ্যমে আপনার ফোনটি আনলক করতে বলা হবে।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন।"</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-bs/strings.xml b/packages/SystemUI/res-product/values-bs/strings.xml
new file mode 100644
index 0000000..b9beecf
--- /dev/null
+++ b/packages/SystemUI/res-product/values-bs/strings.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nema SIM kartice u tabletu."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Nema SIM kartice u telefonu."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-ovi se ne poklapaju"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati tablet. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, tablet će se vratiti na fabričke postavke i svi podaci će se izbrisati."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati telefon. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, telefon će se vratiti na fabričke postavke i svi podaci će se izbrisati."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati tablet. Tablet će se sada vratiti na fabričke postavke i svi podaci će se izbrisati."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati telefon. Telefon će se sada vratiti na fabričke postavke i svi podaci će se izbrisati."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati tablet. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, ovaj korisnik će se ukloniti i svi podaci korisnika će se izbrisati."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Pokušali ste <xliff:g id="NUMBER_0">%1$d</xliff:g> puta neispravno otključati telefon. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, ovaj korisnik će se ukloniti i svi podaci korisnika će se izbrisati."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- String.format failed for translation -->
+    <!-- no translation found for volume_stream_content_description_unmute (7729576371406792977) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV uređaj će se uskoro isključiti. Pritisnite dugme da ostane uključen."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Uređaj će se uskoro isključiti. Pritisnite da ostane uključen."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati tablet. Poslovni profil će se ukloniti i svi podaci s profila će se izbrisati."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Pokušali ste <xliff:g id="NUMBER">%d</xliff:g> puta neispravno otključati telefon. Poslovni profil će se ukloniti i svi podaci s profila će se izbrisati."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da tablet otključate koristeći račun e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da telefon otključate koristeći račun e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-ca/strings.xml b/packages/SystemUI/res-product/values-ca/strings.xml
new file mode 100644
index 0000000..20d8e2f
--- /dev/null
+++ b/packages/SystemUI/res-product/values-ca/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No hi ha cap SIM a la tauleta."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No hi ha cap SIM al telèfon."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Els codis PIN no coincideixen"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, la tauleta es restablirà i se\'n suprimiran totes les dades."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, el telèfon es restablirà i se\'n suprimiran totes les dades."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. La tauleta es restablirà i se\'n suprimiran totes les dades."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. El telèfon es restablirà i se\'n suprimiran totes les dades."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, l\'usuari se suprimirà, juntament amb totes les seves dades."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, l\'usuari se suprimirà, juntament amb totes les seves dades."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"El dispositiu Android TV s\'apagarà aviat; prem un botó per mantenir-lo encès."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"El dispositiu s\'apagarà aviat; prem per mantenir-lo encès."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. El perfil professional se suprimirà, juntament amb totes les dades que contingui."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. El perfil professional se suprimirà, juntament amb totes les dades que contingui."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, se\'t demanarà que desbloquegis la tauleta amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%3$d</xliff:g> segons."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, se\'t demanarà que desbloquegis el telèfon amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%3$d</xliff:g> segons."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-cs/strings.xml b/packages/SystemUI/res-product/values-cs/strings.xml
new file mode 100644
index 0000000..feb3d95
--- /dev/null
+++ b/packages/SystemUI/res-product/values-cs/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"V tabletu není SIM karta."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"V telefonu není SIM karta."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kódy PIN se neshodují"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Již jste se <xliff:g id="NUMBER_0">%1$d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech bude tablet resetován, čímž se z něj smažou všechna data."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Již jste se <xliff:g id="NUMBER_0">%1$d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech bude telefon resetován, čímž se z něj smažou všechna data."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Tablet bude resetován, čímž z něj budou smazána všechna data."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Telefon bude resetován, čímž z něj budou smazána všechna data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Již jste se <xliff:g id="NUMBER_0">%1$d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech bude tento uživatel odstraněn, čímž se smažou všechna jeho data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Již jste se <xliff:g id="NUMBER_0">%1$d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech bude tento uživatel odstraněn, čímž se smažou všechna jeho data."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Zařízení Android TV se brzy vypne, stisknutím tlačítka ho ponecháte zapnuté."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Zařízení se brzy vypne, stisknutím ho ponecháte zapnuté."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Pracovní profil bude odstraněn, čímž budou smazána všechna jeho data."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Pracovní profil bude odstraněn, čímž budou smazána všechna jeho data."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste nesprávně zadali své bezpečnostní gesto. Po <xliff:g id="NUMBER_1">%2$d</xliff:g>dalších neúspěšných pokusech budete požádáni o odemčení tabletu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste nesprávně zadali své bezpečnostní gesto. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech budete požádáni o odemčení telefonu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-da/strings.xml b/packages/SystemUI/res-product/values-da/strings.xml
new file mode 100644
index 0000000..0a7135c
--- /dev/null
+++ b/packages/SystemUI/res-product/values-da/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Der er ikke noget SIM-kort i denne tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Der er ikke noget SIM-kort i telefonen."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Pinkoderne stemmer ikke overens"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Du har forsøgt at låse denne tablet op med den forkerte adgangskode <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg nulstilles denne tablet, hvilket sletter alle dens data."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Du har forsøgt at låse telefonen op med den forkerte adgangskode <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg nulstilles denne telefon, hvilket sletter alle dens data."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Du har forsøgt at låse denne tablet op på forkert vis <xliff:g id="NUMBER">%d</xliff:g> gange. Denne tablet nulstilles, hvilket sletter alle dens data."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Du har forsøgt at låse telefonen op på forkert vis <xliff:g id="NUMBER">%d</xliff:g> gange. Telefonen nulstilles, hvilket sletter alle dens data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Du har forsøgt at låse denne tablet op med den forkerte adgangskode <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg fjernes denne bruger, hvilket sletter alle brugerdata."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Du har forsøgt at låse telefonen op med den forkerte adgangskode <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg fjernes denne bruger, hvilket sletter alle brugerdata."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV-enheden slukker snart. Tryk på en knap for at holde den tændt."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Enheden slukker snart. Tryk for at holde den tændt."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Du har forsøgt at låse denne tablet op på forkert vis <xliff:g id="NUMBER">%d</xliff:g> gange. Arbejdsprofilen fjernes, hvilket sletter alle profildata."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Du har forsøgt at låse telefonen op på forkert vis <xliff:g id="NUMBER">%d</xliff:g> gange. Arbejdsprofilen fjernes, hvilket sletter alle profildata."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg bliver du bedt om at låse din tablet op ved hjælp af en mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg bliver du bedt om at låse din telefon op ved hjælp af en mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-de/strings.xml b/packages/SystemUI/res-product/values-de/strings.xml
new file mode 100644
index 0000000..0c0c513
--- /dev/null
+++ b/packages/SystemUI/res-product/values-de/strings.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Keine SIM-Karte im Tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Keine SIM-Karte im Telefon."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-Codes stimmen nicht überein"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird dieses Tablet zurückgesetzt. Dadurch werden alle Gerätedaten gelöscht."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird dieses Telefon zurückgesetzt. Dadurch werden alle Gerätedaten gelöscht."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Dieses Tablet wird nun zurückgesetzt und alle Gerätedaten werden gelöscht."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Dieses Telefon wird nun zurückgesetzt und alle Gerätedaten werden gelöscht."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird dieser Nutzer entfernt. Dadurch werden alle Nutzerdaten gelöscht."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Du hast <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wird dieser Nutzer entfernt. Dadurch werden alle Nutzerdaten gelöscht."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- String.format failed for translation -->
+    <!-- no translation found for accessibility_battery_level (5143715405241138822) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- String.format failed for translation -->
+    <!-- no translation found for accessibility_battery_level_charging (8892191177774027364) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Das Android TV-Gerät wird demnächst abgeschaltet. Drücke eine Taste, damit es eingeschaltet bleibt."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Das Gerät wird demnächst abgeschaltet. Drücke beispielsweise eine Taste oder berühre den Bildschirm, damit es eingeschaltet bleibt."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Das Arbeitsprofil wird nun entfernt und alle Profildaten werden gelöscht."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Das Arbeitsprofil wird nun entfernt und alle Profildaten werden gelöscht."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Tablet mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden noch einmal."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Telefon mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden noch einmal."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-el/strings.xml b/packages/SystemUI/res-product/values-el/strings.xml
new file mode 100644
index 0000000..cd76dac
--- /dev/null
+++ b/packages/SystemUI/res-product/values-el/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Δεν υπάρχει κάρτα SIM στο tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Δεν υπάρχει κάρτα SIM στο τηλέφωνο."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Δεν υπάρχει αντιστοιχία μεταξύ των κωδικών PIN"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Δοκιμάσατε να ξεκλειδώσετε το tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, αυτό το tablet θα ρυθμιστεί εκ νέου και θα διαγραφούν όλα τα δεδομένα του."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, αυτό το τηλέφωνο θα ρυθμιστεί εκ νέου και θα διαγραφούν όλα τα δεδομένα του."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Δοκιμάσατε να ξεκλειδώσετε αυτό το tablet <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Αυτό το tablet θα ρυθμιστεί εκ νέου και θα διαγραφούν όλα τα δεδομένα του."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Αυτό το τηλέφωνο θα ρυθμιστεί εκ νέου και θα διαγραφούν όλα τα δεδομένα του."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Δοκιμάσατε να ξεκλειδώσετε το tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, αυτός ο χρήστης θα καταργηθεί και θα διαγραφούν όλα τα δεδομένα χρήστη."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, αυτός ο χρήστης θα καταργηθεί και θα διαγραφούν όλα τα δεδομένα χρήστη."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Η συσκευή Android TV σύντομα θα απενεργοποιηθεί. Πατήστε ένα κουμπί για να την κρατήσετε ενεργοποιημένη."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Η συσκευή σύντομα θα απενεργοποιηθεί. Πατήστε για να την κρατήσετε ενεργοποιημένη."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Δοκιμάσατε να ξεκλειδώσετε το tablet <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Το προφίλ εργασίας θα καταργηθεί και θα διαγραφούν όλα τα δεδομένα προφίλ."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Το προφίλ εργασίας θα καταργηθεί και θα διαγραφούν όλα τα δεδομένα προφίλ."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, θα σας ζητηθεί να ξεκλειδώσετε το tablet με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε να συνδεθείτε ξανά σε <xliff:g id="NUMBER_2">%3$d</xliff:g> δευτερόλεπτα."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, θα σας ζητηθεί να ξεκλειδώσετε το τηλέφωνό σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε ξανά σε <xliff:g id="NUMBER_2">%3$d</xliff:g> δευτερόλεπτα."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-en-rAU/strings.xml b/packages/SystemUI/res-product/values-en-rAU/strings.xml
new file mode 100644
index 0000000..9e8ed2f
--- /dev/null
+++ b/packages/SystemUI/res-product/values-en-rAU/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No SIM card in tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No SIM card in phone."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN codes do not match"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This tablet will be reset, which will delete all its data."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This phone will be reset, which will delete all its data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"The Android TV device will soon turn off; press a button to keep it on."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"The device will soon turn off; press to keep it on."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-en-rCA/strings.xml b/packages/SystemUI/res-product/values-en-rCA/strings.xml
new file mode 100644
index 0000000..9e8ed2f
--- /dev/null
+++ b/packages/SystemUI/res-product/values-en-rCA/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No SIM card in tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No SIM card in phone."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN codes do not match"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This tablet will be reset, which will delete all its data."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This phone will be reset, which will delete all its data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"The Android TV device will soon turn off; press a button to keep it on."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"The device will soon turn off; press to keep it on."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-en-rGB/strings.xml b/packages/SystemUI/res-product/values-en-rGB/strings.xml
new file mode 100644
index 0000000..9e8ed2f
--- /dev/null
+++ b/packages/SystemUI/res-product/values-en-rGB/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No SIM card in tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No SIM card in phone."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN codes do not match"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This tablet will be reset, which will delete all its data."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This phone will be reset, which will delete all its data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"The Android TV device will soon turn off; press a button to keep it on."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"The device will soon turn off; press to keep it on."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-en-rIN/strings.xml b/packages/SystemUI/res-product/values-en-rIN/strings.xml
new file mode 100644
index 0000000..9e8ed2f
--- /dev/null
+++ b/packages/SystemUI/res-product/values-en-rIN/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No SIM card in tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No SIM card in phone."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN codes do not match"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this tablet will be reset, which will delete all its data."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. This tablet will be reset, which will delete all its data."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. This phone will be reset, which will delete all its data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, this user will be removed, which will delete all user data."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"The Android TV device will soon turn off; press a button to keep it on."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"The device will soon turn off; press to keep it on."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-en-rXC/strings.xml b/packages/SystemUI/res-product/values-en-rXC/strings.xml
new file mode 100644
index 0000000..2806288
--- /dev/null
+++ b/packages/SystemUI/res-product/values-en-rXC/strings.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‎‎‎‏‎‏‎‎‎‏‎‏‎‎‎‏‏‎‎‎‎‎‎‏‎‎‎‏‎‎‎‎‏‏‏‏‎‎‎‎‎‎‏‏‏‎‎‎‎‎‎‏‎‎The Android TV device will soon turn off; press a button to keep it on.‎‏‎‎‏‎"</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‎‏‎‏‎‏‏‏‎‏‏‎‏‏‏‏‎‏‎‏‎‎‏‎‎‏‎‎‎‎‏‎‎‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎‏‏‎‏‏‎The device will soon turn off; press to keep it on.‎‏‎‎‏‎"</string>
+<string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‏‏‏‎‏‏‎‎‏‎‏‎‎‎‎‏‎‏‏‏‎‏‎‎‎‏‎‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎‏‎‏‎‏‎‎‎‏‏‎No SIM card in tablet.‎‏‎‎‏‎"</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‏‏‏‎‎‎‏‎‎‎‏‏‏‏‎‏‎‎‎‎‏‏‏‏‎‎‏‎‎‎‎‎‎‏‎‏‎‏‎‏‎‏‎‏‏‎‏‏‎‎‏‏‏‎No SIM card in phone.‎‏‎‎‏‎"</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‏‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‎‎‎‎‎‏‏‎‎‎‎‎‏‏‎‎‏‏‎‏‏‏‎‏‎‏‏‎‎PIN codes does not match‎‏‎‎‏‎"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‎‎‎‏‏‎‎‎‏‎‎‏‏‏‏‎‎‏‏‎‎‏‏‏‏‏‎‎‏‏‎‎‏‎‏‏‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‎You have incorrectly attempted to unlock the tablet ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. After ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ more unsuccessful attempts, this tablet will be reset, which will delete all its data.‎‏‎‎‏‎"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‎‎‎‎‎‏‏‏‏‎‎‎‏‏‎‏‏‎‏‎‏‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‏‏‎‏‏‏‏‏‎‏‎‏‏‎‎‎‎‎‎You have incorrectly attempted to unlock the phone ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. After ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ more unsuccessful attempts, this phone will be reset, which will delete all its data.‎‏‎‎‏‎"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‏‎‎‎‏‏‎‏‏‎‏‏‏‏‏‎‎‎‏‎‎‏‎‎‎‏‏‎‏‏‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‎‎You have incorrectly attempted to unlock the tablet ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%d</xliff:g>‎‏‎‎‏‏‏‎ times. This tablet will be reset, which will delete all its data.‎‏‎‎‏‎"</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‎‎‏‎‎‏‎‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‎‎‏‎‏‎‎‎You have incorrectly attempted to unlock the phone ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%d</xliff:g>‎‏‎‎‏‏‏‎ times. This phone will be reset, which will delete all its data.‎‏‎‎‏‎"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‏‎‏‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‎‏‏‏‎‏‏‏‏‎‎‎‏‎‏‏‎‏‏‎‎‎‎‏‏‎‎‏‏‏‎‏‎‎‎‎‎You have incorrectly attempted to unlock the tablet ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. After ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ more unsuccessful attempts, this user will be removed, which will delete all user data.‎‏‎‎‏‎"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‏‎‏‎‎‎‏‎‏‎‏‎‏‏‎‏‎‎‏‎‎‎‎‎‎‏‏‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‏‎‏‏‏‎‎‎‎You have incorrectly attempted to unlock the phone ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. After ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ more unsuccessful attempts, this user will be removed, which will delete all user data.‎‏‎‎‏‎"</string>
+    <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="9046628517316763961">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‎‎‎‎‏‎‏‎‎‏‎‏‏‎‏‎‎‏‎‎‏‎‏‎‏‏‎‎‏‎‏‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‎‎‏‎You have incorrectly attempted to unlock the tablet ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%d</xliff:g>‎‏‎‎‏‏‏‎ times. This user will be removed, which will delete all user data.‎‏‎‎‏‎"</string>
+    <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="3588779327358321092">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‎‎‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‎‏‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‏‎‏‎‎‎‎‎‏‏‏‎‎‎‏‎‎‎You have incorrectly attempted to unlock the phone ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%d</xliff:g>‎‏‎‎‏‏‏‎ times. This user will be removed, which will delete all user data.‎‏‎‎‏‎"</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="6114158710353725041">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‎‏‏‏‎‏‏‎‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‎‎‏‏‏‎‎‎‏‎You have incorrectly attempted to unlock the tablet ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. After ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ more unsuccessful attempts, the work profile will be removed, which will delete all profile data.‎‏‎‎‏‎"</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="8345451368768804892">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‎‏‎‏‏‏‎‎‎‎‏‏‎‎‎‏‏‎‎‎‎‎‎‏‏‏‎‎‎You have incorrectly attempted to unlock the phone ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. After ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ more unsuccessful attempts, the work profile will be removed, which will delete all profile data.‎‏‎‎‏‎"</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‏‏‎‎‏‎‎‎‏‏‏‎‎‏‏‎‎‏‏‎‏‏‏‏‎‏‎‏‎‏‏‎‎‏‎‏‏‏‏‎‎‏‎‎‎‏‎‏‎You have incorrectly attempted to unlock the tablet ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%d</xliff:g>‎‏‎‎‏‏‏‎ times. The work profile will be removed, which will delete all profile data.‎‏‎‎‏‎"</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‎‏‏‏‎‏‏‎‏‎‏‎‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‎‎‎‎‎‏‏‏‏‎‎‏‎‏‎‏‎‏‎‎‎You have incorrectly attempted to unlock the phone ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%d</xliff:g>‎‏‎‎‏‏‏‎ times. The work profile will be removed, which will delete all profile data.‎‏‎‎‏‎"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‏‏‎‏‏‎‏‎‏‏‏‏‎‎‎‎‎‎‏‎‏‎‏‎‎‎‎‎‏‏‏‎‎‏‎‏‎‎‎‏‏‎‎‎‎‎‏‎‏‏‏‎‎‎You have incorrectly drawn your unlock pattern ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. After ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ more unsuccessful attempts, you will be asked to unlock your tablet using an email account.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎ Try again in ‎‏‎‎‏‏‎<xliff:g id="NUMBER_2">%3$d</xliff:g>‎‏‎‎‏‏‏‎ seconds.‎‏‎‎‏‎"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‏‏‏‎‏‏‏‎‎‏‏‎‎‎‏‏‎‎‎‎‏‏‏‎‎‎‏‎‎‏‎‏‎‎‎‏‎You have incorrectly drawn your unlock pattern ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. After ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ more unsuccessful attempts, you will be asked to unlock your phone using an email account.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎ Try again in ‎‏‎‎‏‏‎<xliff:g id="NUMBER_2">%3$d</xliff:g>‎‏‎‎‏‏‏‎ seconds.‎‏‎‎‏‎"</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-es-rUS/strings.xml b/packages/SystemUI/res-product/values-es-rUS/strings.xml
new file mode 100644
index 0000000..85d3dba
--- /dev/null
+++ b/packages/SystemUI/res-product/values-es-rUS/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No hay tarjeta SIM en la tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No hay tarjeta SIM en el teléfono."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Los códigos PIN no coinciden"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Intentaste desbloquear la tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se restablecerá la tablet, lo que borrará todos los datos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se restablecerá el teléfono, lo que borrará todos los datos."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Intentaste desbloquear la tablet <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se restablecerá la tablet, lo que borrará todos los datos."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se restablecerá el teléfono, lo que borrará todos los datos."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Intentaste desbloquear la tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se quitará este usuario, lo que borrará todos los datos asociados."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se quitará este usuario, lo que borrará todos los datos asociados."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Pronto se apagará el dispositivo Android TV; presiona un botón para mantenerlo encendido."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Pronto se apagará el dispositivo; presiona para mantenerlo encendido."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Intentaste desbloquear la tablet <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se quitará el perfil de trabajo, lo que borrará todos los datos asociados."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se quitará el perfil de trabajo, lo que borrará todos los datos asociados."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu tablet mediante una cuenta de correo electrónico.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu dispositivo mediante una cuenta de correo electrónico.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-es/strings.xml b/packages/SystemUI/res-product/values-es/strings.xml
new file mode 100644
index 0000000..ed94cb2
--- /dev/null
+++ b/packages/SystemUI/res-product/values-es/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"No se ha insertado ninguna tarjeta SIM en el tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"No se ha insertado ninguna tarjeta SIM en el teléfono."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Los códigos PIN no coinciden"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al desbloquear el tablet. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, se recuperarán los ajustes de fábrica de este tablet y se eliminarán todos sus datos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al desbloquear el teléfono. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, se recuperarán los ajustes de fábrica de este teléfono y se eliminarán todos sus datos."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Has fallado <xliff:g id="NUMBER">%d</xliff:g> veces al desbloquear el tablet. Se recuperarán los ajustes de fábrica de este tablet y se eliminarán todos sus datos."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Has fallado <xliff:g id="NUMBER">%d</xliff:g> veces al desbloquear el teléfono. Se recuperarán los ajustes de fábrica de este teléfono y se eliminarán todos sus datos."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al desbloquear el tablet. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, se quitará a este usuario y se eliminarán todos sus datos."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al desbloquear el teléfono. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, se quitará a este usuario y se eliminarán todos sus datos."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"El dispositivo Android TV pronto se apagará; pulsa un botón para evitarlo."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"El dispositivo pronto se apagará si no interactúas con él."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Has fallado <xliff:g id="NUMBER">%d</xliff:g> veces al desbloquear el tablet. Se quitará este perfil de trabajo se quitará y se eliminarán todos sus datos."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Has fallado <xliff:g id="NUMBER">%d</xliff:g> veces al desbloquear el teléfono. Se quitará este perfil de trabajo y se eliminarán todos sus datos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, tendrás que usar una cuenta de correo electrónico para desbloquear el tablet.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, tendrás que usar una cuenta de correo electrónico para desbloquear el teléfono.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-et/strings.xml b/packages/SystemUI/res-product/values-et/strings.xml
new file mode 100644
index 0000000..1c4688a
--- /dev/null
+++ b/packages/SystemUI/res-product/values-et/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Tahvelarvutis pole SIM-kaarti."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefonis pole SIM-kaarti."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-koodid ei ole vastavuses"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda tahvelarvutit valesti avada. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset tahvelarvuti lähtestatakse ja kõik selle andmed kustutatakse."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda telefoni valesti avada. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset telefon lähtestatakse ja kõik selle andmed kustutatakse."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda tahvelarvutit valesti avada. Tahvelarvuti lähtestatakse ja kõik selle andmed kustutatakse."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda telefoni valesti avada. Telefon lähtestatakse ja kõik selle andmed kustutatakse."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda tahvelarvutit valesti avada. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset kasutaja eemaldatakse ja kõik kasutajaandmed kustutatakse."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda telefoni valesti avada. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset kasutaja eemaldatakse ja kõik kasutajaandmed kustutatakse."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV seade lülitub varsti välja; selle aktiivsena hoidmiseks vajutage nuppu."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Seade lülitub värsti välja; selle aktiivsena hoidmiseks vajutage nuppu."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda tahvelarvutit valesti avada. Tööprofiil eemaldatakse ja kõik profiiliandmed kustutatakse."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda telefoni valesti avada. Tööprofiil eemaldatakse ja kõik profiiliandmed kustutatakse."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset palutakse teil tahvelarvuti avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundi pärast."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset palutakse teil telefon avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundi pärast."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-eu/strings.xml b/packages/SystemUI/res-product/values-eu/strings.xml
new file mode 100644
index 0000000..265400a
--- /dev/null
+++ b/packages/SystemUI/res-product/values-eu/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Ez dago SIM txartelik tabletan."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Ez dago SIM txartelik telefonoan."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodeak ez datoz bat"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, berrezarri egingo da tableta eta, ondorioz, bertako datu guztiak ezabatuko dira."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, berrezarri egingo da telefonoa eta, ondorioz, bertako datu guztiak ezabatuko dira."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Tableta berrezarri egingo da eta, ondorioz, bertako datu guztiak ezabatuko dira."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Telefonoa berrezarri egingo da eta, ondorioz, bertako datu guztiak ezabatuko dira."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, kendu egingo da erabiltzailea eta, ondorioz, haren datu guztiak ezabatuko dira."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, kendu egingo da erabiltzailea eta, ondorioz, haren datu guztiak ezabatuko dira."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV gailua laster itzaliko da; sakatu botoi bat piztuta mantentzeko."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Gailua laster itzaliko da; sakatu piztuta mantentzeko."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Laneko profila kendu egingo da eta, ondorioz, profileko datu guztiak ezabatuko dira."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Laneko profila kendu egingo da eta, ondorioz, profileko datu guztiak ezabatuko dira."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz marraztu duzu desblokeatzeko eredua, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, tableta posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%3$d</xliff:g> segundo barru."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"<xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz marraztu duzu desblokeatzeko eredua, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz huts egiten baduzu, telefonoa posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%3$d</xliff:g> segundo barru."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-fa/strings.xml b/packages/SystemUI/res-product/values-fa/strings.xml
new file mode 100644
index 0000000..018c17d
--- /dev/null
+++ b/packages/SystemUI/res-product/values-fa/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"سیم‌کارت درون رایانهٔ لوحی نیست."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"سیم‌کارت درون تلفن نیست."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"کدهای پین منطبق نیستند"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"<xliff:g id="NUMBER_0">%1$d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشته‌اید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، این رایانه لوحی بازنشانی می‌شود که با آن همه داده‌هایش حذف می‌شود."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"<xliff:g id="NUMBER_0">%1$d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشته‌اید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، تلفن بازنشانی می‌شود که با آن همه داده‌هایش حذف می‌شود."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشته‌اید. این رایانه لوحی بازنشانی می‌شود که با آن همه داده‌هایش حذف می‌شود."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشته‌اید. این تلفن بازنشانی می‌شود که با آن همه داده‌هایش حذف می‌شود."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"<xliff:g id="NUMBER_0">%1$d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشته‌اید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، این کاربر پاک می‌شود که با آن همه داده‌های کاربر حذف می‌شود."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"<xliff:g id="NUMBER_0">%1$d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشته‌اید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، این کاربر پاک می‌شود که با آن همه داده‌های کاربر حذف می‌شود."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"‏دستگاه Android TV به‌زودی خاموش می‌شود، برای روشن نگه‌داشتن آن، دکمه‌ای را فشار دهید."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"دستگاه به‌زودی خاموش می‌شود، برای روشن نگه‌داشتن آن فشار دهید."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشته‌اید. نمایه کاری پاک می‌شود که با آن همه داده‌های نمایه حذف می‌شود."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشته‌اید. نمایه کاری پاک می‌شود که با آن همه داده‌های نمایه حذف می‌شود."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"‏شما الگوی باز کردن قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‎اید. بعد از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته می‎شود که با استفاده از یک حساب ایمیل قفل رایانه لوحی خود را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"‏شما الگوی باز کردن قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‌اید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته می‎شود که با استفاده از یک حساب ایمیل قفل تلفن را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-fi/strings.xml b/packages/SystemUI/res-product/values-fi/strings.xml
new file mode 100644
index 0000000..377b577
--- /dev/null
+++ b/packages/SystemUI/res-product/values-fi/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Tabletissa ei ole SIM-korttia."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Puhelimessa ei ole SIM-korttia."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-koodit eivät täsmää"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos <xliff:g id="NUMBER_1">%2$d</xliff:g> seuraavaa yritystä epäonnistuu, tämä puhelin nollataan ja kaikki sen tiedot poistetaan."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos <xliff:g id="NUMBER_1">%2$d</xliff:g> seuraavaa yritystä epäonnistuu, tämä puhelin nollataan ja kaikki sen tiedot poistetaan."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Tämä tabletti nollataan ja kaikki sen tiedot poistetaan."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Tämä puhelin nollataan ja kaikki sen tiedot poistetaan."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos <xliff:g id="NUMBER_1">%2$d</xliff:g> seuraavaa yritystä epäonnistuu, tämä käyttäjä ja kaikki sen käyttäjätiedot poistetaan."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos <xliff:g id="NUMBER_1">%2$d</xliff:g> seuraavaa yritystä epäonnistuu, tämä käyttäjä ja kaikki käyttäjän tiedot poistetaan."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ‑laite sammuu pian. Pidä se päällä painamalla painiketta."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Laite sammuu pian. Pidä se päällä painamalla jotakin."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Työprofiili ja kaikki sen tiedot poistetaan."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Työprofiili ja kaikki sen tiedot poistetaan."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> kertaa, sinua pyydetään avaamaan tabletin lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> kertaa, sinua pyydetään avaamaan puhelimesi lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunnin kuluttua."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-fr-rCA/strings.xml b/packages/SystemUI/res-product/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..4429937
--- /dev/null
+++ b/packages/SystemUI/res-product/values-fr-rCA/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Aucune carte SIM n\'est insérée dans la tablette."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Aucune carte SIM n\'est insérée dans le téléphone."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Les NIP ne correspondent pas."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%2$d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), cette tablette sera réinitialisée, ce qui entraînera la suppression de toutes les données qu\'elle contient."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%2$d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), le téléphone sera réinitialisé, ce qui entraînera la suppression de toutes les données qu\'il contient."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Cette tablette sera réinitialisée, ce qui entraîne la suppression de toutes les données qu\'elle contient."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Ce téléphone sera réinitialisé, ce qui entraîne la suppression de toutes les données qu\'il contient."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%2$d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), cet utilisateur sera supprimé, ce qui entraînera la suppression de toutes ses données."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%2$d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), cet utilisateur sera supprimé, ce qui entraînera la suppression de toutes ses données."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"L\'appareil Android TV va bientôt s\'éteindre. Appuyez sur un bouton pour le laisser allumé."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"L\'appareil va bientôt s\'éteindre. Interagissez avec lui pour le laisser allumé."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel sera supprimé, ce qui entraîne la suppression de toutes ses données."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel sera supprimé, ce qui entraîne la suppression de toutes ses données."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de courriel.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de courriel.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-fr/strings.xml b/packages/SystemUI/res-product/values-fr/strings.xml
new file mode 100644
index 0000000..2838c02
--- /dev/null
+++ b/packages/SystemUI/res-product/values-fr/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Aucune carte SIM n\'est insérée dans la tablette."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Aucune carte SIM n\'est insérée dans le téléphone."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Les codes PIN ne correspondent pas"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, elle sera réinitialisée et toutes les données qu\'elle contient seront supprimées."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, il sera réinitialisé et toutes les données qu\'il contient seront supprimées."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Elle va être réinitialisée et toutes les données qu\'elle contient seront supprimées."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Il va être réinitialisé et toutes les données qu\'il contient seront supprimées."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, ce compte utilisateur et toutes les données associées seront supprimés."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, ce compte utilisateur et toutes les données associées seront supprimés."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"L\'appareil Android TV va bientôt passer en mode Veille. Appuyez sur un bouton pour qu\'il reste allumé."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"L\'appareil va bientôt passer en mode Veille. Appuyez dessus pour qu\'il reste allumé."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel et toutes les données associées vont être supprimés."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel et toutes les données associées vont être supprimés."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de messagerie électronique.\n\nRéessayez dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique.\n\nRéessayez dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-gl/strings.xml b/packages/SystemUI/res-product/values-gl/strings.xml
new file mode 100644
index 0000000..b1e045f
--- /dev/null
+++ b/packages/SystemUI/res-product/values-gl/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Non hai ningunha tarxeta SIM na tableta."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Non hai ningunha tarxeta SIM no teléfono."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Os códigos PIN non coinciden"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Tentaches desbloquear a tableta <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, restablecerase a tableta e, por conseguinte, eliminaranse todos os seus datos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, restablecerase o teléfono e, por conseguinte, eliminaranse todos os seus datos."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Tentaches desbloquear a tableta <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Restablecerase a tableta e, por conseguinte, eliminaranse todos os seus datos."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Restablecerase o teléfono e, por conseguinte, eliminaranse todos os seus datos."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Tentaches desbloquear a tableta <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, quitarase este usuario e, por conseguinte, todos os datos do usuario."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, quitarase este usuario e, por conseguinte, todos os datos do usuario."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Pronto se apagará o dispositivo Android TV. Preme un botón para mantelo acendido."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Pronto se apagará o dispositivo. Tócao para mantelo acendido."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Tentaches desbloquear a tableta <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Quitarase o perfil de traballo e, por conseguinte, todos os datos do perfil."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Quitarase o perfil de traballo e, por conseguinte, todos os datos do perfil."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Debuxaches o padrón de desbloqueo incorrectamente <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, terás que desbloquear a tableta a través dunha conta de correo electrónico.\n\n Téntao de novo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Debuxaches o padrón de desbloqueo incorrectamente <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, terás que desbloquear o teléfono a través dunha conta de correo electrónico.\n\n Téntao de novo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-gu/strings.xml b/packages/SystemUI/res-product/values-gu/strings.xml
new file mode 100644
index 0000000..1a9228e
--- /dev/null
+++ b/packages/SystemUI/res-product/values-gu/strings.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ટૅબ્લેટમાં સિમ કાર્ડ નથી."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ફોનમાં સિમ કાર્ડ નથી."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"પિન કોડ મેળ ખાતા નથી"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"તમે ટૅબ્લેટને <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, આ ટૅબ્લેટ ફરીથી સેટ કરવામાં આવશે, જે તેનો તમામ ડેટા કાઢી નાખશે."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"તમે ફોનને <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, આ ફોન ફરીથી સેટ કરવામાં આવશે, જે તેનો તમામ ડેટા કાઢી નાખશે."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"તમે ટૅબ્લેટને <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. આ ટૅબ્લેટ ફરીથી સેટ થશે, જે તેનો તમામ ડેટા કાઢી નાખશે."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"તમે ફોનને <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. આ ફોન ફરીથી સેટ કરાશે, જે તેનો તમામ ડેટા કાઢી નાખશે."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"તમે ટૅબ્લેટને <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. <xliff:g id="NUMBER_1">%2$d</xliff:g> વધુ અસફળ પ્રયાસો પછી, આ વપરાશકર્તાને દૂર કરવામાં આવશે, જે તમામ વપરાશકર્તા ડેટાને કાઢી નાખશે."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"તમે ફોનને <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, આ વપરાશકર્તાને દૂર કરવામાં આવશે, જે તમામ વપરાશકર્તા ડેટા કાઢી નાખશે."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for notification_bubble_title (8330481035191903164) -->
+    <skip/>
+    <!-- no translation found for notification_channel_summary_bubble (7235935211580860537) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android ટીવી ડિવાઇસ ટૂંક સમયમાં બંધ થશે; તેને ચાલુ રાખવા માટે બટન દબાવો."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ડિવાઇસ ટૂંક સમયમાં બંધ થશે; તેને ચાલુ રાખવા માટે દબાવો."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"તમે ટૅબ્લેટને <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. આ કાર્યાલયની પ્રોફાઇલ દૂર કરવામાં આવશે, જે તમામ પ્રોફાઇલ ડેટાને કાઢી નાખશે."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"તમે ફોનને <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. આ કાર્યાલયની પ્રોફાઇલ દૂર કરવામાં આવશે, જે તમામ પ્રોફાઇલ ડેટાને કાઢી નાખશે."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"તમે તમારી અનલૉક પૅટર્ન <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે દોરી છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, તમને એક ઇમેઇલ એકાઉન્ટનો ઉપયોગ કરીને તમારા ટૅબ્લેટને અનલૉક કરવાનું કહેવામાં આવશે.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> સેકન્ડમાં ફરી પ્રયાસ કરો."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"તમે તમારી અનલૉક પૅટર્ન <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે દોરી છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, તમને ઇમેઇલ એકાઉન્ટનો ઉપયોગ કરીને ફોન અનલૉક કરવાનું કહેવામાં આવશે.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> સેકન્ડમાં ફરીથી પ્રયાસ કરો."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-hi/strings.xml b/packages/SystemUI/res-product/values-hi/strings.xml
new file mode 100644
index 0000000..7babf18
--- /dev/null
+++ b/packages/SystemUI/res-product/values-hi/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"टैबलेट में कोई SIM कार्ड नहीं है."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"फ़ोन में कोई SIM कार्ड नहीं है."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"पिन कोड का मिलान नहीं हो रहा है"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"आपने टैबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से कोशिश की है. <xliff:g id="NUMBER_1">%2$d</xliff:g> और असफल कोशिशों के बाद, इस टैबलेट को रीसेट कर दिया जाएगा, जिससे इसका सारा डेटा हट जाएगा."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"आपने फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से कोशिश की है. <xliff:g id="NUMBER_1">%2$d</xliff:g> और असफल कोशिशों के बाद, इस फ़ोन को रीसेट कर दिया जाएगा, जिससे इसका सारा डेटा हट जाएगा."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"आपने टैबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से कोशिश की है. इस टैबलेट को रीसेट कर दिया जाएगा, जिससे इसका सारा डेटा हट जाएगा."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"आपने फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से कोशिश की है. इस फ़ोन को रीसेट कर दिया जाएगा, जिससे इसका सारा डेटा हट जाएगा."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"आपने टैबलेट का लॉक खोलने के लिए <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से कोशिश की है. <xliff:g id="NUMBER_1">%2$d</xliff:g> बार और गलत कोशिश करने पर, इस उपयोगकर्ता को निकाल दिया जाएगा, जिससे सभी उपयोगकर्ता डेटा मिट जाएगा."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"आपने फ़ोन का लॉक खोलने के लिए <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से कोशिश की है. <xliff:g id="NUMBER_1">%2$d</xliff:g> बार और गलत कोशिश करने पर, इस उपयोगकर्ता को निकाल दिया जाएगा, जिससे सभी उपयोगकर्ता डेटा मिट जाएगा."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV डिवाइस जल्द ही बंद हो जाएगा. इसे चालू रखने के लिए किसी बटन को दबाएं."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"डिवाइस जल्द ही बंद हो जाएगा. इसे चालू रखने के लिए स्क्रीन पर टैप करें या किसी बटन को दबाएं."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"आपने टैबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से कोशिश की है. वर्क प्रोफ़ाइल को निकाल दिया जाएगा, जिससे सभी प्रोफ़ाइल डेटा हट जाएगा."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"आपने फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से कोशिश की है. वर्क प्रोफ़ाइल को निकाल दिया जाएगा, जिससे सभी प्रोफ़ाइल डेटा हट जाएगा."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"आपने अपने लॉक खोलने के पैटर्न को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से ड्रॉ किया है. अगर आपने <xliff:g id="NUMBER_1">%2$d</xliff:g> बार और गलत ड्रॉ किया, तो आपसे अपने टैबलेट को किसी ईमेल खाते का इस्तेमाल करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड बाद फिर से कोशिश करें."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"आपने अपने लॉक खोलने के पैटर्न को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से ड्रॉ किया है. अगर आपने <xliff:g id="NUMBER_1">%2$d</xliff:g> बार और गलत ड्रॉ किया, तो आपसे अपने फ़ोन को किसी ईमेल खाते का इस्तेमाल करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड बाद फिर से कोशिश करें."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-hr/strings.xml b/packages/SystemUI/res-product/values-hr/strings.xml
new file mode 100644
index 0000000..690f58a
--- /dev/null
+++ b/packages/SystemUI/res-product/values-hr/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"U tabletu nema SIM kartice."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"U telefonu nema SIM kartice."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodovi nisu jednaki"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Neuspješno ste pokušali otključati tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja tablet će se vratiti na zadano, a time će se izbrisati i svi podaci na njemu."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Neuspješno ste pokušali otključati telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja telefon će se vratiti na zadano, a time će se izbrisati i svi podaci na njemu."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Neuspješno ste pokušali otključati tablet <xliff:g id="NUMBER">%d</xliff:g> put/a. Tablet će se vratiti na zadano, a time će se izbrisati i svi podaci na njemu."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Neuspješno ste pokušali otključati telefon <xliff:g id="NUMBER">%d</xliff:g> put/a. Telefon će se vratiti na zadano, a time će se izbrisati i svi podaci na njemu."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Neuspješno ste pokušali otključati tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja taj će se korisnik ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Neuspješno ste pokušali otključati telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja taj će se korisnik ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Uređaj Android TV uskoro će se isključiti. Pritisnite gumb da bi ostao uključen."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Uređaj će se uskoro isključiti. Pritisnite da bi ostao uključen."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Neuspješno ste pokušali otključati tablet <xliff:g id="NUMBER">%d</xliff:g> put/a. Radni će se profil ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Neuspješno ste pokušali otključati telefon <xliff:g id="NUMBER">%d</xliff:g> put/a. Radni će se profil ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja morat ćete otključati tablet pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja morat ćete otključati telefon pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-hu/strings.xml b/packages/SystemUI/res-product/values-hu/strings.xml
new file mode 100644
index 0000000..26160e4
--- /dev/null
+++ b/packages/SystemUI/res-product/values-hu/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nincs SIM-kártya a táblagépben."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Nincs SIM-kártya a telefonban."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"A PIN-kódok nem egyeznek"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után a rendszer visszaállítja a táblagépet, és ezzel az összes adat törlődik róla."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után a rendszer visszaállítja a telefont, és ezzel az összes adat törlődik róla."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. A rendszer visszaállítja a táblagépet, és ezzel a rajta lévő összes adat törlődik."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. A rendszer visszaállítja a telefont, és ezzel a rajta lévő összes adat törlődik."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után a rendszer eltávolítja a felhasználót, és ezzel a felhasználó összes adata törlődik majd."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után a rendszer eltávolítja a felhasználót, és ezzel a felhasználó összes adata törlődik majd."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Az Android TV eszköz hamarosan kikapcsol. Nyomja meg valamelyik gombot, hogy bekapcsolva tarthassa."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Az eszköz hamarosan kikapcsol. Nyomja meg, hogy bekapcsolva tarthassa."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. A rendszer eltávolítja a munkaprofilt, és ezzel a profil összes adata törlődik."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. A rendszer eltávolítja a munkaprofilt, és ezzel a profil összes adata törlődik."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után e-mail-fiók használatával kell feloldania táblagépét.\n\nPróbálja újra <xliff:g id="NUMBER_2">%3$d</xliff:g> másodperc múlva."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után e-mail-fiók használatával kell feloldania telefonját.\n\nPróbálja újra <xliff:g id="NUMBER_2">%3$d</xliff:g> másodperc múlva."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-hy/strings.xml b/packages/SystemUI/res-product/values-hy/strings.xml
new file mode 100644
index 0000000..008ac7ef
--- /dev/null
+++ b/packages/SystemUI/res-product/values-hy/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Պլանշետում SIM քարտ չկա:"</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Հեռախոսում SIM քարտ չկա:"</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN կոդերը չեն համընկնում"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Դուք կատարել եք պլանշետն ապակողպելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո այս պլանշետը կվերակայվի և բոլոր տվյալները կջնջվեն:"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո այս հեռախոսը կվերակայվի և բոլոր տվյալները կջնջվեն:"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Դուք կատարել եք պլանշետն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Այս պլանշետը կվերակայվի և բոլոր տվյալները կջնջվեն:"</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Այս հեռախոսը կվերակայվի և բոլոր տվյալները կջնջվեն:"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Դուք կատարել եք պլանշետն ապակողպելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո այս օգտվողը կհեռացվի և օգտվողի բոլոր տվյալները կջնջվեն:"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո այս օգտվողը կհեռացվի և օգտվողի բոլոր տվյալները կջնջվեն:"</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV սարքը շուտով կանջատվի: Սեղմեք որևէ կոճակ՝ միացրած թողնելու համար:"</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Սարքը շուտով կանջատվի: Սեղմեք՝ միացրած թողնելու համար:"</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Դուք կատարել եք պլանշետն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Աշխատանքային պրոֆիլը կհեռացվի և պրոֆիլի բոլոր տվյալները կջնջվեն:"</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Աշխատանքային պրոֆիլը կհեռացվի և պրոֆիլի բոլոր տվյալները կջնջվեն:"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Դուք կատարել եք ապակողպման նախշը մուտքագրելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո ձեզանից կպահանջվի ապակողպել պլանշետը էլփոստի հաշվի միջոցով։\n\n Խնդրում ենք փորձել կրկին <xliff:g id="NUMBER_2">%3$d</xliff:g> վայրկյանից:"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Դուք կատարել եք ապակողպման նախշը մուտքագրելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո ձեզանից կպահանջվի ապակողպել հեռախոսը էլփոստի հաշվի միջոցով։\n\n Խնդրում ենք փորձել կրկին <xliff:g id="NUMBER_2">%3$d</xliff:g> վայրկյանից:"</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-in/strings.xml b/packages/SystemUI/res-product/values-in/strings.xml
new file mode 100644
index 0000000..e87aab3
--- /dev/null
+++ b/packages/SystemUI/res-product/values-in/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Tidak ada kartu SIM dalam tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Tidak ada Kartu SIM di dalam ponsel."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kode PIN tidak cocok"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Sudah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, tablet ini akan disetel ulang, sehingga semua datanya akan dihapus."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Sudah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, ponsel ini akan disetel ulang, sehingga semua datanya akan dihapus."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Tablet ini akan disetel ulang, sehingga menghapus semua datanya."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Ponsel ini akan disetel ulang, sehingga menghapus semua datanya."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Sudah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, pengguna ini akan dihapus, sehingga semua data pengguna akan dihapus."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Sudah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, pengguna ini akan dihapus, sehingga semua data pengguna akan dihapus."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Perangkat Android TV akan segera dinonaktifkan; tekan tombol untuk terus menyalakannya."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Perangkat akan segera dinonaktifkan, tekan untuk terus menyalakannya."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Profil kerja akan dihapus, sehingga menghapus semua data profil."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Profil kerja akan dihapus, sehingga menghapus semua data profil."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka. Setelah gagal <xliff:g id="NUMBER_1">%2$d</xliff:g> kali lagi, Anda akan diminta membuka kunci tablet menggunakan akun email.\n\n Coba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka. Setelah gagal <xliff:g id="NUMBER_1">%2$d</xliff:g> kali lagi, Anda akan diminta membuka kunci ponsel menggunakan akun email.\n\n Coba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-is/strings.xml b/packages/SystemUI/res-product/values-is/strings.xml
new file mode 100644
index 0000000..38c651a
--- /dev/null
+++ b/packages/SystemUI/res-product/values-is/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Ekkert SIM-kort í spjaldtölvunni."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Ekkert SIM-kort í símanum."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-númerin stemma ekki"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Þú hefur gert <xliff:g id="NUMBER_0">%1$d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður spjaldtölvan endurstillt, með þeim afleiðingum að öllum gögnum hennar verður eytt."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Þú hefur gert <xliff:g id="NUMBER_0">%1$d</xliff:g> árangurslausar tilraunir til að opna símann. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður síminn endurstilltur, með þeim afleiðingum að öllum gögnum hans verður eytt."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Spjaldtölvan verður endurstillt, með þeim afleiðingum að öllum gögnum hennar verður eytt."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna símann. Síminn verður endurstilltur, með þeim afleiðingum að öllum gögnum hans verður eytt."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Þú hefur gert <xliff:g id="NUMBER_0">%1$d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður notandinn fjarlægður með þeim afleiðingum að öllum notandagögnum verður eytt."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Þú hefur gert <xliff:g id="NUMBER_0">%1$d</xliff:g> árangurslausar tilraunir til að opna símann. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður notandinn fjarlægður með þeim afleiðingum að öllum notandagögnum verður eytt."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV tækið slekkur á sér fljótlega. Ýttu á takka til að það slokkni ekki á því."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Tækið slekkur á sér fljótlega. Ýttu á takka til að það slokkni ekki á því."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Vinnusniðið verður fjarlægt, með þeim afleiðingum að öllum gögnum þess verður eytt."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna símann. Vinnusniðið verður fjarlægt, með þeim afleiðingum að öllum gögnum þess verður eytt."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður þú beðin(n) um að opna spjaldtölvuna með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%3$d</xliff:g> sekúndur."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verðurðu beðin(n) um að opna símann með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%3$d</xliff:g> sekúndur."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-it/strings.xml b/packages/SystemUI/res-product/values-it/strings.xml
new file mode 100644
index 0000000..1ca5706
--- /dev/null
+++ b/packages/SystemUI/res-product/values-it/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nessuna scheda SIM presente nel tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Nessuna scheda SIM presente nel telefono."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"I codici PIN non corrispondono"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER_0">%1$d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, il tablet verrà ripristinato e verranno quindi eliminati tutti i relativi dati."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER_0">%1$d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, il telefono verrà ripristinato e verranno quindi eliminati tutti i relativi dati."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il tablet verrà ripristinato e verranno quindi eliminati tutti i relativi dati."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il telefono verrà ripristinato e verranno quindi eliminati tutti i relativi dati."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER_0">%1$d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, questo utente verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER_0">%1$d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, questo utente verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"A breve il dispositivo Android TV si spegnerà. Premi un pulsante per tenerlo acceso."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"A breve il dispositivo si spegnerà. Premi per tenerlo acceso."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il profilo di lavoro verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il profilo di lavoro verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il tablet con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%3$d</xliff:g> secondi."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%3$d</xliff:g> secondi."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-iw/strings.xml b/packages/SystemUI/res-product/values-iw/strings.xml
new file mode 100644
index 0000000..3a6f6f1
--- /dev/null
+++ b/packages/SystemUI/res-product/values-iw/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"‏אין כרטיס SIM בטאבלט."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"‏אין כרטיס SIM בטלפון."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"קודי הגישה אינם תואמים"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ניסית לבטל את נעילת הטאבלט <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, טאבלט זה יאופס וכל הנתונים שבו יימחקו."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, טלפון זה יאופס וכל הנתונים שבו יימחקו."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ניסית לבטל את נעילת הטאבלט <xliff:g id="NUMBER">%d</xliff:g> פעמים. הטאבלט יאופס וכל הנתונים שלו יימחקו."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER">%d</xliff:g> פעמים. הטלפון יאופס וכל הנתונים שבו יימחקו."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ניסית לבטל את נעילת הטאבלט <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, משתמש זה יוסר וכל נתוני המשתמש יימחקו."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, משתמש זה יוסר וכל נתוני המשתמש יימחקו."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"‏מכשיר Android TV ייכבה בקרוב. יש ללחוץ על לחצן כלשהו כדי שהוא ימשיך לפעול."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"המכשיר ייכבה בקרוב, יש ללחוץ כדי שהוא ימשיך לפעול."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ניסית לבטל את נעילת הטאבלט <xliff:g id="NUMBER">%d</xliff:g> פעמים. פרופיל העבודה יוסר וכל נתוני הפרופיל יימחקו."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER">%d</xliff:g> פעמים. פרופיל העבודה יוסר וכל נתוני הפרופיל יימחקו."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"שרטטת קו ביטול נעילה שגוי <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילת הטאבלט באמצעות חשבון אימייל‏.\n\nנסה שוב בעוד <xliff:g id="NUMBER_2">%3$d</xliff:g> שניות."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"שרטטת קו ביטול נעילה שגוי <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילת הטלפון באמצעות חשבון אימייל‏.\n\n נסה שוב בעוד <xliff:g id="NUMBER_2">%3$d</xliff:g> שניות."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-ja/strings.xml b/packages/SystemUI/res-product/values-ja/strings.xml
new file mode 100644
index 0000000..b0ea11c
--- /dev/null
+++ b/packages/SystemUI/res-product/values-ja/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"タブレットに SIM カードが挿入されていません。"</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"スマートフォンに SIM カードが挿入されていません。"</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN コードが一致しません"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"タブレットのロック解除に <xliff:g id="NUMBER_0">%1$d</xliff:g> 回失敗しました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回失敗すると、このタブレットはリセットされ、データはすべて消去されます。"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"スマートフォンのロック解除に <xliff:g id="NUMBER_0">%1$d</xliff:g> 回失敗しました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回失敗すると、このスマートフォンはリセットされ、データはすべて消去されます。"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"タブレットのロック解除に <xliff:g id="NUMBER">%d</xliff:g> 回失敗しました。このタブレットはリセットされ、データはすべて消去されます。"</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"スマートフォンのロック解除に <xliff:g id="NUMBER">%d</xliff:g> 回失敗しました。このスマートフォンはリセットされ、データはすべて消去されます。"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"タブレットのロック解除に <xliff:g id="NUMBER_0">%1$d</xliff:g> 回失敗しました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回失敗すると、このユーザーは削除され、ユーザー データはすべて消去されます。"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"スマートフォンのロック解除に <xliff:g id="NUMBER_0">%1$d</xliff:g> 回失敗しました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回失敗すると、このユーザーは削除され、ユーザー データはすべて消去されます。"</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV デバイスはまもなく OFF になります。ON 状態を維持するには、ボタンを押してください。"</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"このデバイスはまもなく OFF になります。ON 状態を維持するには、ボタンを押してください。"</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"タブレットのロック解除に <xliff:g id="NUMBER">%d</xliff:g> 回失敗しました。仕事用プロファイルは削除され、プロファイルのデータはすべて消去されます。"</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"スマートフォンのロック解除に <xliff:g id="NUMBER">%d</xliff:g> 回失敗しました。仕事用プロファイルは削除され、プロファイルのデータはすべて消去されます。"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ロック解除パターンの入力を <xliff:g id="NUMBER_0">%1$d</xliff:g> 回間違えました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回間違えると、タブレットのロック解除にメール アカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後にもう一度お試しください。"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ロック解除パターンの入力を <xliff:g id="NUMBER_0">%1$d</xliff:g> 回間違えました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回間違えると、スマートフォンのロック解除にメール アカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後にもう一度お試しください。"</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-ka/strings.xml b/packages/SystemUI/res-product/values-ka/strings.xml
new file mode 100644
index 0000000..1f5a2022
--- /dev/null
+++ b/packages/SystemUI/res-product/values-ka/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ტაბლეტში არ არის SIM ბარათი."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ტელეფონში არ არის SIM ბარათი."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-კოდები არ ემთხვევა"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"თქვენ არასწორად ცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ამ ტაბლეტის გადაყენება განხორციელდება, რაც მისი მონაცემების მთლიანად წაშლას გამოიწვევს."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"თქვენ არასწორად ცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ამ ტელეფონის გადაყენება განხორციელდება, რაც მისი მონაცემების მთლიანად წაშლას გამოიწვევს."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"თქვენ არასწორად ცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g>-ჯერ. ამის გამო, ამ ტაბლეტის გადაყენება განხორციელდება, რაც მისი მონაცემების მთლიანად წაშლას გამოიწვევს."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"თქვენ არასწორად ცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g>-ჯერ. ამის გამო, ამ ტელეფონის გადაყენება განხორციელდება, რაც მისი მონაცემების მთლიანად წაშლას გამოიწვევს."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"თქვენ არასწორად ცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ეს მომხმარებელი ამოიშლება, რაც მომხმარებლის ყველა მონაცემის წაშლას გამოიწვევს."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"თქვენ არასწორად ცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ეს მომხმარებელი ამოიშლება, რაც მომხმარებლის ყველა მონაცემის წაშლას გამოიწვევს."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV მოწყობილობა მალე გამოირთვება, დააჭირეთ ღილაკს, რომ ჩართული დარჩეს."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"მოწყობილობა მალე გამოირთვება, დააჭირეთ, რომ ჩართული დარჩეს."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"თქვენ არასწორად ცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g>-ჯერ. ამის გამო, სამსახურის პროფილი ამოიშლება, რაც პროფილის ყველა მონაცემის წაშლას გამოიწვევს."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"თქვენ არასწორად ცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g>-ჯერ. ამის გამო, სამსახურის პროფილი ამოიშლება, რაც პროფილის ყველა მონაცემის წაშლას გამოიწვევს."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ტაბლეტის განბლოკვა თქვენი ელფოსტის ანგარიშის მეშვეობით მოგიწევთ.\n\n ცადეთ ხელახლა <xliff:g id="NUMBER_2">%3$d</xliff:g> წამში."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ტელეფონის განბლოკვა თქვენი ელფოსტის ანგარიშის მეშვეობით მოგიწევთ.\n\n ცადეთ ხელახლა <xliff:g id="NUMBER_2">%3$d</xliff:g> წამში."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-kk/strings.xml b/packages/SystemUI/res-product/values-kk/strings.xml
new file mode 100644
index 0000000..8185a16
--- /dev/null
+++ b/packages/SystemUI/res-product/values-kk/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Планшетте SIM картасы жоқ."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Телефонда SIM картасы жоқ."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN коды сәйкес келмейді"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Планшет құлпын ашуға <xliff:g id="NUMBER_0">%1$d</xliff:g> рет сәтсіз әрекет жасалды. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін осы планшет бастапқы күйіне қайтарылып, оның бүкіл деректері жойылады."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Телефон құлпын ашуға <xliff:g id="NUMBER_0">%1$d</xliff:g> рет сәтсіз әрекет жасалды. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін осы телефон бастапқы күйіне қайтарылып, оның бүкіл деректері жойылады."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Планшет құлпын ашуға <xliff:g id="NUMBER">%d</xliff:g> рет сәтсіз әрекет жасалды. Осы планшет бастапқы күйіне қайтарылып, оның бүкіл деректері жойылады."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Телефон құлпын ашуға <xliff:g id="NUMBER">%d</xliff:g> рет сәтсіз әрекет жасалды. Осы телефон бастапқы күйіне қайтарылып, оның бүкіл деректері жойылады."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Планшет құлпын ашуға <xliff:g id="NUMBER_0">%1$d</xliff:g> рет сәтсіз әрекет жасалды. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін пайдаланушы өшіріліп, оның бүкіл деректері жойылады."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Телефон құлпын ашуға <xliff:g id="NUMBER_0">%1$d</xliff:g> рет сәтсіз әрекет жасалды. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін пайдаланушы өшіріліп, оның бүкіл деректері жойылады."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV құрылғысы жақын арада өшеді. Оны қосулы қалдыру үшін басыңыз."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Құрылғы жақын арада өшеді. Оны қосулы қалдыру үшін басыңыз."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Планшет құлпын ашуға <xliff:g id="NUMBER">%d</xliff:g> рет сәтсіз әрекет жасалды. Жұмыс профилі өшіріліп, оның бүкіл деректері жойылады."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Телефон құлпын ашуға <xliff:g id="NUMBER">%d</xliff:g> рет сәтсіз әрекет жасалды. Жұмыс профилі өшіріліп, оның бүкіл деректері жойылады."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Құлыпты ашу өрнегі <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате енгізілді. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін планшетті есептік жазба арқылы ашу сұралады. \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін әрекетті қайталаңыз."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Құлыпты ашу өрнегі <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате енгізілді. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін телефонды есептік жазба арқылы ашу сұралады. \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін әрекетті қайталаңыз."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-km/strings.xml b/packages/SystemUI/res-product/values-km/strings.xml
new file mode 100644
index 0000000..1c3c7f4
--- /dev/null
+++ b/packages/SystemUI/res-product/values-km/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"គ្មាន​ស៊ីម​កាត​នៅ​ក្នុង​ថេប្លេត​ទេ។"</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"គ្មាន​ស៊ីមកាត​នៅ​ក្នុង​ទូរសព្ទ​ទេ។"</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"កូដ PIN មិន​ត្រូវ​គ្នា​ទេ"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"អ្នក​បាន​ព្យាយាម​ដោះសោ​ថេប្លេត​នេះ​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដង​ហើយ។ ប្រសិន​បើ​ការ​ព្យាយាម​ដោះ​សោ​ចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀត​មិន​ទទួល​បាន​ជោគជ័យទេ ថេប្លេត​នេះ​នឹង​ត្រូវ​បាន​កំណត់​ឡើងវិញ ហើយ​វា​នឹង​លុប​ទិន្នន័យ​របស់វា​ទាំងអស់។"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"អ្នក​បាន​ព្យាយាម​ដោះសោ​ទូរសព្ទ​នេះ​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដង​ហើយ។ ប្រសិន​បើ​ការ​ព្យាយាម​ដោះ​សោ​ចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀត​មិន​ទទួល​បាន​ជោគជ័យទេ ទូរសព្ទ​នេះ​នឹង​ត្រូវ​បាន​កំណត់​ឡើងវិញ ហើយ​វា​នឹង​លុប​ទិន្នន័យ​របស់វា​ទាំងអស់។"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"អ្នក​បាន​ព្យាយាម​ដោះសោ​ថេប្លេត​នេះ​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER">%d</xliff:g> ដង។ ថេប្លេត​នេះ​នឹង​ត្រូវ​បាន​កំណត់​ឡើងវិញ ហើយ​វា​នឹង​លុប​ទិន្នន័យ​ទាំងអស់​របស់​វា។"</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"អ្នក​បាន​ព្យាយាម​ដោះសោ​ទូរសព្ទ​នេះ​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER">%d</xliff:g> ដង​ហើយ។ ទូរសព្ទ​នេះ​នឹង​ត្រូវ​បាន​កំណត់​ឡើងវិញ ហើយ​វា​នឹង​លុប​ទិន្នន័យ​ទាំងអស់​របស់​វា។"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"អ្នក​បាន​ព្យាយាម​ដោះ​សោ​ថេប្លេត​នេះ​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដង​ហើយ។ ប្រសិន​បើ​ការ​ព្យាយាម​ដោះ​សោ​ចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀត​មិន​ទទួល​បាន​ជោគជ័យទេ អ្នក​ប្រើប្រាស់​នេះនឹង​ត្រូវ​បាន​លុប ហើយ​វា​នឹង​លុប​ទិន្នន័យ​របស់​អ្នក​ប្រើប្រាស់​ទាំងអស់។"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"អ្នក​បាន​ព្យាយាម​ដោះ​សោ​ទូរសព្ទ​នេះ​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដង​ហើយ។ ប្រសិន​បើ​ការ​ព្យាយាមដោះសោ​ចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀត​មិន​ទទួល​បាន​ជោគជ័យទេ អ្នក​ប្រើប្រាស់​នេះនឹង​ត្រូវ​បាន​លុប ហើយ​វា​នឹង​លុប​ទិន្នន័យ​របស់​អ្នក​ប្រើប្រាស់​ទាំងអស់។"</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"ឧបករណ៍ Android TV នឹង​បិទ​ក្នុងពេល​ឆាប់ៗនេះ សូមចុច​ប៊ូតុង​ដើម្បី​បន្ត​បើក​ឧបករណ៍។"</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ឧបករណ៍​នឹង​បិទ​ក្នុងពេល​ឆាប់ៗនេះ សូមចុច​ដើម្បី​បន្ត​បើក​ឧបករណ៍។"</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"អ្នក​បាន​ព្យាយាម​ដោះសោ​ថេប្លេត​នេះ​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER">%d</xliff:g> ដង​ហើយ។ កម្រង​ព័ត៌មាន​ការងារ​នេះ​នឹង​ត្រូវ​បាន​លុប ហើយ​វា​នឹង​លុប​ទិន្នន័យ​កម្រង​ព័ត៌មាន​ទាំងអស់។"</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"អ្នក​បាន​ព្យាយាម​ដោះសោ​ទូរសព្ទ​នេះ​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER">%d</xliff:g> ដង​ហើយ។ កម្រង​ព័ត៌មាន​ការងារ​នេះ​នឹង​ត្រូវ​បាន​លុប ហើយ​វា​នឹង​លុប​ទិន្នន័យ​កម្រង​ព័ត៌មាន​ទាំងអស់។"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"អ្នក​បាន​គូរ​លំនាំ​ដោះ​សោ​របស់​អ្នក​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដង​ហើយ។ ប្រសិន​បើ​ការ​ព្យាយាម​ដោះ​សោ​ចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀត​មិន​ទទួល​បាន​ជោគជ័យទេ អ្នក​នឹង​ត្រូវ​បាន​ស្នើ​ឲ្យ​ដោះ​សោ​ថេប្លេត​របស់​អ្នក​ ដោយ​ប្រើ​គណនី​អ៊ីមែល។\n\n សូមព្យាយាម​ម្ដង​ទៀត​ក្នុង​រយៈ​ពេល <xliff:g id="NUMBER_2">%3$d</xliff:g> វិនាទី​ទៀត។"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"អ្នក​បាន​គូរ​លំនាំ​ដោះ​សោ​របស់​អ្នក​មិន​ត្រឹមត្រូវ​ចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដង​ហើយ។ ប្រសិន​បើ​ការ​ព្យាយាម​ដោះ​សោ​ចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀត​មិន​ទទួល​បាន​ជោគជ័យទេ អ្នក​នឹង​ត្រូវ​បាន​ស្នើ​ឲ្យ​ដោះ​សោ​ទូរសព្ទ​របស់​អ្នក​ ដោយ​ប្រើ​គណនី​អ៊ីមែល។\n\n សូម​ព្យាយាម​ម្ដង​ទៀត​ក្នុង​រយៈ​ពេល <xliff:g id="NUMBER_2">%3$d</xliff:g> វិនាទី​ទៀត។"</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-kn/strings.xml b/packages/SystemUI/res-product/values-kn/strings.xml
new file mode 100644
index 0000000..06644f4
--- /dev/null
+++ b/packages/SystemUI/res-product/values-kn/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ಟ್ಯಾಬ್ಲೆಟ್‌ನಲ್ಲಿ ಸಿಮ್‌ ಕಾರ್ಡ್ ಇಲ್ಲ."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ಪೋನ್‌ನಲ್ಲಿ ಯಾವುದೇ ಸಿಮ್‌ ಕಾರ್ಡ್ ಇಲ್ಲ."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ಪಿನ್‌ ಕೋಡ್‍ಗಳು ಹೊಂದಾಣಿಕೆಯಾಗುತ್ತಿಲ್ಲ"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ಫೋನ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಫೋನ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಈ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲಾಗುತ್ತದೆ, ಇದು ಅದರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ಫೋನ್  ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಈ ಫೋನ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲಾಗುತ್ತದೆ, ಇದು ಅದರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಬಳಕೆದಾರರನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಬಳಕೆದಾರರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ಫೋನ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಬಳಕೆದಾರರನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಬಳಕೆದಾರರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"ಈ Android TV ಸಾಧನವು ಶೀಘ್ರವೇ ಆಫ್ ಆಗುತ್ತದೆ; ಇದನ್ನು ಆನ್‌ನಲ್ಲಿಡಲು ಬಟನ್ ಅನ್ನು ಒತ್ತಿರಿ."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ಈ ಸಾಧನವು ಶೀಘ್ರವೇ ಆಫ್ ಆಗುತ್ತದೆ; ಇದನ್ನು ಆನ್‌ನಲ್ಲಿಡಲು ಒತ್ತಿರಿ."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಪ್ರೊಫೈಲ್ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ಫೋನ್ ಅನ್‌ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಪ್ರೊಫೈಲ್ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ನಿಮ್ಮ ಅನ್‍‍ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಎಳೆದಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ನಿಮ್ಮ ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್‌ಲಾಕ್ ಮಾಡುವಂತೆ ನಿಮ್ಮಲ್ಲಿ ಕೇಳಿಕೊಳ್ಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ನಿಮ್ಮ ಅನ್‍‍ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಎಳೆದಿದ್ದೀರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ನಿಮ್ಮ ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿ ಫೋನ್ ಅನ್‌ಲಾಕ್ ಮಾಡುವಂತೆ ನಿಮ್ಮಲ್ಲಿ ಕೇಳಿಕೊಳ್ಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-ko/strings.xml b/packages/SystemUI/res-product/values-ko/strings.xml
new file mode 100644
index 0000000..1d5152e
--- /dev/null
+++ b/packages/SystemUI/res-product/values-ko/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"태블릿에 SIM 카드가 없습니다."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"휴대전화에 SIM 카드가 없습니다."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN 코드가 일치하지 않음"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"태블릿 잠금 해제에 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 태블릿이 재설정되며 모든 데이터가 삭제됩니다."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"휴대전화 잠금 해제에 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 휴대전화가 재설정되며 모든 데이터가 삭제됩니다."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"태블릿 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 태블릿이 재설정되며 모든 데이터가 삭제됩니다."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"휴대전화 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 휴대전화가 재설정되며 모든 데이터가 삭제됩니다."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"태블릿 잠금 해제에 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 이 사용자와 모든 사용자 데이터가 삭제됩니다."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"휴대전화 잠금 해제에 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 이 사용자와 모든 사용자 데이터가 삭제됩니다."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV가 곧 꺼집니다. 계속 켜 두려면 버튼을 누르세요."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"기기가 곧 꺼집니다. 계속 켜 두려면 누르세요."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"태블릿 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 직장 프로필과 모든 프로필 데이터가 삭제됩니다."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"휴대전화 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 직장 프로필과 모든 프로필 데이터가 삭제됩니다."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 잘못 그렸습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 이메일 계정을 사용하여 태블릿을 잠금 해제해야 합니다.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g>초 후에 다시 시도해 주세요."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%1$d</xliff:g>번 잘못 그렸습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>번 더 실패하면 이메일 계정을 사용하여 휴대전화를 잠금 해제해야 합니다.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g>초 후에 다시 시도해 주세요."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-ky/strings.xml b/packages/SystemUI/res-product/values-ky/strings.xml
new file mode 100644
index 0000000..bc4ffa0
--- /dev/null
+++ b/packages/SystemUI/res-product/values-ky/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Планшетте SIM-карта жок."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Телефондо SIM-карта жок."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-коддор дал келген жок"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Планшеттин кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, бул планшет баштапкы абалга келтирилип, андагы бардык дайындар жок болот."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Телефондун кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, бул телефон баштапкы абалга келтирилип, андагы бардык дайындар жок болот."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Планшеттин кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Бул планшет баштапкы абалга келтирилип, андагы бардык дайындар жок болот."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Телефондун кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес аракет жасадыңыз. Бул телефон баштапкы абалга келтирилип, андагы бардык дайындар жок болот."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Планшеттин кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, бул колдонуучу чыгарылып салынып, колдонуучунун бардык дайындары жок болот."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Телефондун кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу ийгиликсиз аракет кылсаңыз, бул колдонуучу чыгарылып салынып, колдонуучунун бардык дайындары жок болот."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV түзмөгү жакында өчүрүлөт, аны күйүк боюнча калтыруу үчүн баскычты басыңыз."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Түзмөк жакында өчүрүлөт, күйүк боюнча калтыруу үчүн басып коюңуз."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Планшеттин кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Жумуш профили чыгарылып салынып, андагы бардык дайындар жок болот."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Телефондун кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Жумуш профили чыгарылып салынып, андагы бардык дайындар жок болот."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Сиз графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин планшетиңизди бөгөттөн электрондук почтаңыз аркылуу чыгарышыңыз талап кылынат.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секунддан кийин кайра аракеттениңиз."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Сиз графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин телефонуңузду бөгөттөн электрондук почтаңыз аркылуу чыгаруу талап кылынат.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секунддан кийин кайра аракеттениңиз."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-lo/strings.xml b/packages/SystemUI/res-product/values-lo/strings.xml
new file mode 100644
index 0000000..8d2e0f3
--- /dev/null
+++ b/packages/SystemUI/res-product/values-lo/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ບໍ່ມີຊິມກາດໃນແທັບເລັດ."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ບໍ່ມີ SIM card ໃນໂທລະສັບ."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ລະຫັດ PIN ບໍ່ກົງກັນ"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER_0">%1$d</xliff:g> ຄັ້ງ. ຫຼັງຈາກລອງບໍ່ສຳເລັດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ຄັ້ງ, ແທັບເລັດນີ້ຈະຖືກຕັ້ງຄ່າໃໝ່, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຂອງມັນ."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER_0">%1$d</xliff:g> ຄັ້ງ. ຫຼັງຈາກລອງບໍ່ສຳເລັດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ຄັ້ງ, ໂທລະສັບນີ້ຈະຖືກຕັ້ງຄ່າໃໝ່, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຂອງມັນ."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ແທັບເລັດນີ້ຈະຖືກຕັ້ງຄ່າໃໝ່, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຂອງມັນ."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ໂທລະສັບນີ້ຈະຖືກຕັ້ງຄ່າໃໝ່, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຂອງມັນ."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER_0">%1$d</xliff:g> ຄັ້ງ. ຫຼັງຈາກລອງບໍ່ສຳເລັດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g>ຄັ້ງ, ຜູ້ໃຊ້ນີ້ຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຜູ້ໃຊ້."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER_0">%1$d</xliff:g> ຄັ້ງ. ຫຼັງຈາກລອງບໍ່ສຳເລັດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ຄັ້ງ, ຜູ້ໃຊ້ນີ້ຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຜູ້ໃຊ້."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"ອຸປະກອນ Android TV ຈະປິດໃນອີກບໍ່ດົນ, ກົດປຸ່ມໃດໜຶ່ງເພື່ອເປີດມັນໄວ້ຕໍ່."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ອຸປະກອນຈະປິດໃນອີກບໍ່ດົນ, ກົດເພື່ອເປີດມັນໄວ້ຕໍ່."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນໂປຣໄຟລ໌."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນໂປຣໄຟລ໌."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຜິດ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກແຕ້ມຜິດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ເທື່ອ, ທ່ານຈະຖືກຖາມໃຫ້ປົດລັອກແທັບເລັດຂອງທ່ານ ດ້ວຍການເຂົ້າສູ່ລະບົບໂດຍໃຊ້ອີເມວຂອງທ່ານ.\n\n ກະລຸນາລອງໃໝ່ອີກຄັ້ງໃນອີກ <xliff:g id="NUMBER_2">%3$d</xliff:g> ວິນາທີ."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຂອງທ່ານຜິດ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກຄວາມພະຍາຍາມອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ເທື່ອ ທ່ານຈະຖືກຖາມໃຫ້ປົດລັອກໂທລະສັບຂອງທ່ານດ້ວຍບັນຊີອີເມວ.\n\n ລອງໃໝ່ອີກຄັ້ງໃນ <xliff:g id="NUMBER_2">%3$d</xliff:g> ວິນາທີ."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-lt/strings.xml b/packages/SystemUI/res-product/values-lt/strings.xml
new file mode 100644
index 0000000..f291681
--- /dev/null
+++ b/packages/SystemUI/res-product/values-lt/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Planšetiniame kompiuteryje nėra SIM kortelės."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefone nėra SIM kortelės."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodai nesutampa"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. šis planšetinis kompiuteris bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. šis telefonas bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Šis planšetinis kompiuteris bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Šis telefonas bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. šis naudotojas bus pašalintas ir visi naudotojo duomenys bus ištrinti."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. šis naudotojas bus pašalintas ir visi naudotojo duomenys bus ištrinti."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"„Android TV“ įrenginys netrukus išsijungs. Paspauskite mygtuką, kad jis liktų įjungtas."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Įrenginys netrukus išsijungs. Paspauskite, kad jis liktų įjungtas."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Darbo profilis bus pašalintas ir visi profilio duomenys bus ištrinti."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Darbo profilis bus pašalintas ir visi profilio duomenys bus ištrinti."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. netinkamai nupiešėte atrakinimo piešinį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. būsite paprašyti atrakinti planšetinį kompiuterį naudodami el. pašto paskyrą.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. netinkamai nupiešėte atrakinimo piešinį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. būsite paprašyti atrakinti telefoną naudodami el. pašto paskyrą.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-lv/strings.xml b/packages/SystemUI/res-product/values-lv/strings.xml
new file mode 100644
index 0000000..6459e25
--- /dev/null
+++ b/packages/SystemUI/res-product/values-lv/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Planšetdatorā nav SIM kartes."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Tālrunī nav SIM kartes."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodi neatbilst."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt planšetdatoru. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) šis planšetdators tiks atiestatīts, kā arī visi planšetdatora dati tiks dzēsti."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt tālruni. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) šis tālrunis tiks atiestatīts, kā arī visi tālruņa dati tiks dzēsti."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt planšetdatoru. Šis planšetdators tiks atiestatīts, kā arī visi planšetdatora dati tiks dzēsti."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt tālruni. Šis tālrunis tiks atiestatīts, kā arī visi tālruņa dati tiks dzēsti."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt planšetdatoru. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) šis lietotājs tiks noņemts, kā arī visi lietotāja dati tiks dzēsti."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt tālruni. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) šis lietotājs tiks noņemts, kā arī visi lietotāja dati tiks dzēsti."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ierīce drīz izslēgsies. Nospiediet pogu, lai tā paliktu ieslēgta."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Ierīce drīz izslēgsies. Nospiediet, lai tā paliktu ieslēgta."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt planšetdatoru. Darba profils tiks noņemts, kā arī visi profila dati tiks dzēsti."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt tālruni. Darba profils tiks noņemts, kā arī visi profila dati tiks dzēsti."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nepareizi norādījāt atbloķēšanas kombināciju. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) planšetdators būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundes(-ēm)."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nepareizi norādījāt atbloķēšanas kombināciju. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) tālrunis būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundes(-ēm)."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-mk/strings.xml b/packages/SystemUI/res-product/values-mk/strings.xml
new file mode 100644
index 0000000..21fde4d
--- /dev/null
+++ b/packages/SystemUI/res-product/values-mk/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Во таблетот нема SIM-картичка."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Во телефонот нема SIM-картичка."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-кодовите не се совпаѓаат"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Неправилно се обидовте да го отклучите таблетот <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, таблетот ќе се ресетира, со што ќе се избришат сите негови податоци."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, телефонот ќе се ресетира, со што ќе се избришат сите негови податоци."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Неправилно се обидовте да го отклучите таблетот <xliff:g id="NUMBER">%d</xliff:g> пати. Овој таблет ќе се ресетира, со што ќе се избришат сите негови податоци."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER">%d</xliff:g> пати. Овој телефон ќе се ресетира, со што ќе се избришат сите негови податоци."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Неправилно се обидовте да го отклучите таблетот <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, корисникот ќе се отстрани, со што ќе се избришат сите негови податоци."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, корисникот ќе се отстрани, со што ќе се избришат сите податоци на корисникот."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Уредот со Android TV наскоро ќе се исклучи, притиснете копче за да остане вклучен."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Уредот наскоро ќе се исклучи, притиснете за да остане вклучен."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Неправилно се обидовте да го отклучите таблетот <xliff:g id="NUMBER">%d</xliff:g> пати. Работниот профил ќе се отстрани, со што ќе се избришат сите податоци на профилот."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER">%d</xliff:g> пати. Работниот профил ќе се отстрани, со што ќе се избришат сите податоци на профилот."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Погрешно сте ја употребиле вашата шема на отклучување <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, ќе побараме да го отклучите таблетот со сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Погрешно сте ја употребиле вашата шема на отклучување <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, ќе побараме да го отклучите телефонот со сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-ml/strings.xml b/packages/SystemUI/res-product/values-ml/strings.xml
new file mode 100644
index 0000000..c39cce1
--- /dev/null
+++ b/packages/SystemUI/res-product/values-ml/strings.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ടാബ്‌ലെറ്റിൽ സിം കാർഡൊന്നുമില്ല."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ഫോണിൽ സിം കാർഡൊന്നുമില്ല."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"പിൻ കോഡുകൾ പൊരുത്തപ്പെടുന്നില്ല"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി ടാബ്‌ലെറ്റ് അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ, ഈ ടാബ്‌ലെറ്റ് ‌റീസെറ്റുചെയ്യപ്പെടുകയും, അതുവഴി അതിലെ എല്ലാ ‌ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി ഫോൺ അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ ഈ ഫോൺ റീസെറ്റുചെയ്യപ്പെടുകയും, അതുവഴി അതിലെ എല്ലാ ‌ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"നിങ്ങൾ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി ടാബ്‌ലെറ്റ് അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഈ ഫോൺ റീസെറ്റുചെയ്യപ്പെടുകയും, അതുവഴി അതിലെ എല്ലാ ‌ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"നിങ്ങൾ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി ഫോൺ അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഈ ഫോൺ റീസെറ്റുചെയ്യപ്പെടുകയും, അതുവഴി അതിലെ എല്ലാ ‌ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി ടാബ്‌ലെറ്റ് അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ ഈ ഉപയോക്താവിനെ ‌നീക്കം ചെയ്യുകയും, അതുവഴി ‌ഉപയോക്താവിന്റെ എല്ലാ ‌ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി ഫോൺ അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ ഈ ഉപയോക്താവിനെ ‌നീക്കം ചെയ്യുകയും, അതുവഴി ‌ഉപയോക്താവിന്റെ എല്ലാ ‌ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for notification_bubble_title (8330481035191903164) -->
+    <skip/>
+    <!-- no translation found for notification_channel_summary_bubble (7235935211580860537) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android ടിവി ഉടൻ ഓഫാകും, ഓണാക്കി നിർത്താൻ ഒരു ബട്ടൺ അമർത്തുക."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ഉപകരണം ഉടൻ ഓഫാകും, ഓണാക്കി നിർത്താൻ അമർത്തുക."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"നിങ്ങൾ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി ടാബ്‌ലെറ്റ് അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഔദ്യോഗിക പ്രൊഫൈൽ നീക്കംചെയ്യപ്പെടുകയും, അതുവഴി എല്ലാ പ്രൊഫൈൽ ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"നിങ്ങൾ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി ഫോൺ അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഔദ്യോഗിക പ്രൊഫൈൽ നീക്കംചെയ്യപ്പെടുകയും, അതുവഴി എല്ലാ പ്രൊഫൈൽ ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി അൺലോക്ക് പാറ്റേൺ വരച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ, ഒരു ഇമെയിൽ അക്കൗണ്ടുപയോഗിച്ച് ടാബ്‌ലെറ്റ് അൺലോക്കുചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> സെക്കന്റ് കഴിഞ്ഞ് വീണ്ടും ‌ശ്രമിക്കുക."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി അൺലോക്ക് പാറ്റേൺ വരച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ, ഒരു ഇമെയിൽ അക്കൗണ്ടുപയോഗിച്ച് ഫോൺ അൺലോക്കുചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> സെക്കന്റ് കഴിഞ്ഞ് വീണ്ടും ‌ശ്രമിക്കുക."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-mn/strings.xml b/packages/SystemUI/res-product/values-mn/strings.xml
new file mode 100644
index 0000000..32f3bf9
--- /dev/null
+++ b/packages/SystemUI/res-product/values-mn/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Таблетад SIM карт алга."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Утсанд SIM карт алга."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ПИН код тохирохгүй байна"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Та таблетын түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу хийлээ. Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд энэ таблетыг шинэчлэх бөгөөд бүх өгөгдөл нь устах болно."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу хийлээ.Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд энэ утсыг шинэчлэх бөгөөд бүх өгөгдөл нь устах болно."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Та таблетын түгжээг тайлах оролдлогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу хийлээ. Энэ таблетыг шинэчлэх бөгөөд ингэснээр бүх өгөгдөл нь устах болно."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу хийлээ. Энэ утсыг шинэчлэх бөгөөд ингэснээр бүх өгөгдөл нь устах болно."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Та таблетын түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу хийсэн байна. Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд энэ хэрэглэгчийг устгах бөгөөд ингэснээр хэрэглэгчийн бүх өгөгдөл устах болно."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу хийсэн байна. Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд энэ хэрэглэгчийг устгах бөгөөд ингэснээр хэрэглэгчийн бүх өгөгдөл устах болно."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Андройд ТВ төхөөрөмж удахгүй унтрах тул асаалттай хэвээр байлгахын тулд товчлуур дээр дарна уу."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Төхөөрөмж удахгүй унтрах тул асаалттай хэвээр байлгахын тулд дарна уу."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Та таблетын түгжээг тайлах оролдогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу хийсэн байна. Ажлын профайлыг устгах бөгөөд ингэснээр профайлын бүх өгөгдөл устах болно."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу хийлээ. Ажлын профайлыг устгах бөгөөд ингэснээр профайлын бүх өгөгдлийг устгах болно."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Та түгжээ тайлах загварыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу орууллаа. Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд таблетынхаа түгжээг имэйл бүртгэлээрээ тайлах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Та түгжээ тайлах загварыг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу орууллаа. Хэрэв та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд утасныхаа түгжээг имэйл бүртгэлээрээ тайлах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-mr/strings.xml b/packages/SystemUI/res-product/values-mr/strings.xml
new file mode 100644
index 0000000..8ef190e
--- /dev/null
+++ b/packages/SystemUI/res-product/values-mr/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"टॅबलेटमध्ये सिम कार्ड नाही."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"फोनमध्ये सिम कार्ड नाही."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"पिन कोड जुळत नाहीत"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"तुम्ही टॅबलेट अनलॉक करण्याचा <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, हे टॅबलेट रीसेट केला जाईल, जे त्याचा सर्व डेटा हटवेल."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"तुम्ही फोन अनलॉक करण्याचा <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, हा फोन रीसेट केला जाईल, जे त्याचा सर्व डेटा हटवेल."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"तुम्ही टॅबलेट अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. हे टॅबलेट रीसेट केले जाईल, जे त्याचा सर्व डेटा हटवेल."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"तुम्ही फोन अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. हा फोन रीसेट केला जाईल, जे त्याचा सर्व डेटा हटवेल."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"तुम्ही टॅबलेट अनलॉक करण्याचा <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, या वापरकर्त्याला काढले जाईल, जे सर्व वापरकर्ता डेटा हटवेल."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"तुम्ही फोन अनलॉक करण्याचा <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, या वापरकर्त्याला काढले जाईल, जे सर्व वापरकर्ता डेटा हटवेल."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV डिव्हाइस लवकरच बंद होणार आहे; सुरू ठेवण्यासाठी बटण दाबा."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"डिव्हाइस लवकरच बंद होणार आहे; सुरू ठेवण्यासाठी स्क्रीनवर किंवा बटण दाबा."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"तुम्ही टॅबलेट अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. कार्य प्रोफाइल काढली जाईल, जे सर्व प्रोफाइल डेटा हटवेल."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"तुम्ही फोन अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. कार्य प्रोफाइल काढली जाईल, जे सर्व प्रोफाइल डेटा हटवेल."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"तुम्ही तुमचा अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यपणे काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, तुम्हाला ईमेल खाते वापरून तुमचा टॅब्लेट अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"तुम्ही तुमचा अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यपणे काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, तुम्हाला ईमेल खाते वापरून तुमचा फोन अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-ms/strings.xml b/packages/SystemUI/res-product/values-ms/strings.xml
new file mode 100644
index 0000000..5443a54
--- /dev/null
+++ b/packages/SystemUI/res-product/values-ms/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Tiada kad SIM dalam tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Tiada kad SIM dalam telefon."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kod PIN tidak sepadan"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, tablet ini akan ditetapkan semula sekali gus memadamkan semua data."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, telefon ini akan ditetapkan semula sekali gus memadamkan semua data."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Tablet ini akan ditetapkan semula sekali gus memadamkan semua data."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Telefon ini akan ditetapkan semula sekali gus memadamkan semua data."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, pengguna ini akan dialih keluar sekali gus memadamkan semua data pengguna."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, pengguna ini akan dialih keluar sekali gus memadamkan semua data pengguna."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Peranti Android TV akan mati tidak lama lagi; tekan butang untuk memastikan peranti terus hidup."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Peranti akan mati tidak lama lagi; tekan untuk memastikan peranti terus hidup."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Profil kerja ini akan dialih keluar sekali gus memadamkan semua data profil."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Profil kerja ini akan dialih keluar sekali gus memadamkan semua data profil."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Anda telah tersilap melukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, anda akan diminta membuka kunci tablet anda menggunakan akaun e-mel.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> saat."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, anda akan diminta membuka kunci telefon anda menggunakan akaun e-mel.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> saat."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-my/strings.xml b/packages/SystemUI/res-product/values-my/strings.xml
new file mode 100644
index 0000000..3f2891d
--- /dev/null
+++ b/packages/SystemUI/res-product/values-my/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"တက်ဘလက်ထဲတွင် ဆင်းမ်ကဒ် မရှိပါ။"</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ဖုန်းထဲတွင် ဆင်းမ်ကဒ် မရှိပါ။"</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ပင်နံပါတ် ကိုက်ညီမှုမရှိပါ"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"တက်ဘလက်ကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းခဲ့လျှင် ဤတက်ဘလက်ကို ပြင်ဆင်သတ်မှတ်လိုက်မည် ဖြစ်ပြီး ၎င်းအတွင်းရှိ ဒေတာများအားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ဖုန်းကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းခဲ့လျှင် ဤဖုန်းကို ပြင်ဆင်သတ်မှတ်လိုက်မည် ဖြစ်ပြီး ၎င်းအတွင်းရှိ ဒေတာများအားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"တက်ဘလက်ကို <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ ဤတက်ဘလက်ကို ပြင်ဆင်သတ်မှတ်လိုက်မည် ဖြစ်ပြီး ၎င်းအတွင်းရှိ ဒေတာများအားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ဖုန်းကို <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ ဤဖုန်းကို ပြင်ဆင်သတ်မှတ်လိုက်မည် ဖြစ်ပြီး ၎င်းအတွင်းရှိ ဒေတာများအားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"တက်ဘလက်ကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းခဲ့လျှင် ဤအသုံးပြုသူကို ဖယ်ရှားလိုက်မည်ဖြစ်ပြီး အသုံးပြုသူဒေတာများ အားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ဖုန်းကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းသွားလျှင် ဤအသုံးပြုသူကို ဖယ်ရှားလိုက်မည်ဖြစ်ပြီး အသုံးပြုသူဒေတာများ အားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV စက်သည် မကြာမီ ပိတ်သွားပါမည်၊ ဆက်ဖွင့်ထားရန် ခလုတ်တစ်ခုနှိပ်ပါ။"</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"စက်သည် မကြာမီ ပိတ်သွားပါမည်၊ ဆက်ဖွင့်ထားပါ။"</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"တက်ဘလက်ကို <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ အလုပ်ပရိုဖိုင်ကို ဖယ်ရှားလိုက်မည်ဖြစ်ပြီး ပရိုဖိုင်ဒေတာများ အားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ဖုန်းကို <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ အလုပ်ပရိုဖိုင်ကို ဖယ်ရှားလိုက်မည်ဖြစ်ပြီး ပရိုဖိုင်ဒေတာများ အားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"သင်သည် သင်၏ လော့ခ်ဖွင့်ခြင်းပုံစံကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ ဆွဲခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းပြီးသည့်နောက်တွင် သင့်အီးမေးလ်အကောင့်အား အသုံးပြု၍ တက်ဘလက်ကို လော့ခ်ဖွင့်ရန် တောင်းဆိုသွားပါမည်။\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> စက္ကန့်အကြာတွင် ထပ်စမ်းကြည့်ပါ။"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"သင်သည် သင်၏ လော့ခ်ဖွင့်ခြင်းပုံစံကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ ဆွဲခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းပြီးသည့်နောက်တွင် သင့်အီးမေးလ်အကောင့်အား အသုံးပြု၍ ဖုန်းကို လော့ခ်ဖွင့်ရန် တောင်းဆိုသွားပါမည်။\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> စက္ကန့်အကြာတွင် ထပ်စမ်းကြည့်ပါ။"</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-nb/strings.xml b/packages/SystemUI/res-product/values-nb/strings.xml
new file mode 100644
index 0000000..6608b25
--- /dev/null
+++ b/packages/SystemUI/res-product/values-nb/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nettbrettet mangler SIM-kort."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefonen mangler SIM-kort."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-kodene stemmer ikke overens"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Nettbrettet tilbakestilles etter <xliff:g id="NUMBER_1">%2$d</xliff:g> nye mislykkede forsøk, noe som sletter alle dataene på nettbrettet."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Telefonen tilbakestilles etter <xliff:g id="NUMBER_1">%2$d</xliff:g> nye mislykkede forsøk, noe som sletter alle dataene på telefonen."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER">%d</xliff:g> ganger. Dette nettbrettet blir tilbakestilt, og alle dataene blir slettet."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER">%d</xliff:g> ganger. Denne telefonen blir tilbakestilt, og alle dataene blir slettet."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Brukeren fjernes etter <xliff:g id="NUMBER_1">%2$d</xliff:g> nye mislykkede forsøk, noe som sletter alle brukerdataene."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Brukeren fjernes etter <xliff:g id="NUMBER_1">%2$d</xliff:g> nye mislykkede forsøk, noe som sletter alle brukerdataene."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV-enheten slås snart av. Trykk på en knapp for å holde den på."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Enheten slås snart av. Trykk for å holde den på."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER">%d</xliff:g> ganger. Jobbprofilen blir fjernet, og alle profildataene blir slettet."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER">%d</xliff:g> ganger. Jobbprofilen blir fjernet, og alle profildataene blir slettet."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Du har tegnet opplåsingsmønsteret feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%2$d</xliff:g> feil forsøk blir du bedt om å låse opp nettbrettet via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Du har tegnet opplåsingsmønsteret feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%2$d</xliff:g> feil forsøk blir du bedt om å låse opp telefonen via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-ne/strings.xml b/packages/SystemUI/res-product/values-ne/strings.xml
new file mode 100644
index 0000000..2361ac9
--- /dev/null
+++ b/packages/SystemUI/res-product/values-ne/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ट्याब्लेटमा SIM कार्ड छैन।"</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"फोनमा SIM कार्ड छैन।"</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN कोडहरू मिलेनन्"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, यो ट्याब्लेट यसमा भएका सबै डेटा मेटिने गरी रिसेट हुनेछ।"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, यो फोन यसमा भएका सबै डेटा मेटिने गरी रिसेट हुनेछ।"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"तपाईंले <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नुभएको छ। यो ट्याब्लेट यसमा भएका सबै डेटा मेटिने गरी रिसेट हुनेछ।"</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"तपाईंले <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नुभएको छ। यो फोन यसमा भएका सबै डेटा मेटिने गरी रिसेट हुनेछ।"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले  ट्याब्लेट अनलक गर्ने प्रयास गर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, यस प्रयोगकर्तालाई यसका सबै डेटा मेटिने गरी हटाइने छ।"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नुभएको छ। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, यस प्रयोगकर्तालाई यसका सबै डेटा मेटिने गरी हटाइने छ।"</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV यन्त्र चाँडै निष्क्रिय हुने छ; सक्रिय राख्न कुनै बटन थिच्नुहोस्।"</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"यो यन्त्र चाँडै निष्क्रिय हुने छ; सक्रिय राख्न थिच्नुहोस्।"</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"तपाईं <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नुभएको छ। कार्य प्रोफाइललाई यसका सबै डेटा मेटिने गरी हटाइने छ।"</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"तपाईंले <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नुभएको छ। कार्य प्रोफाइललाई यसका सबै डेटा मेटिने गरी हटाइने छ।"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक आफ्नो अनलक गर्ने ढाँचा गलत रूपमा कोर्नुभयो। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, तपाईंलाई एउटा इमेल खाता प्रयोग गरेर आफ्नो ट्याब्लेट अनलक गर्न आग्रह गरिनेछ।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक आफ्नो अनलक गर्ने ढाँचा गलत रूपमा कोर्नुभयो। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, तपाईंलाई एउटा इमेल खाता प्रयोग गरेर आफ्नो फोन अनलक गर्न आग्रह गरिनेछ।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-nl/strings.xml b/packages/SystemUI/res-product/values-nl/strings.xml
new file mode 100644
index 0000000..6f71d98
--- /dev/null
+++ b/packages/SystemUI/res-product/values-nl/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Geen simkaart in tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Geen simkaart in telefoon."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Pincodes komen niet overeen"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Je hebt <xliff:g id="NUMBER_0">%1$d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt deze tablet gereset, waardoor alle gegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Je hebt <xliff:g id="NUMBER_0">%1$d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt deze telefoon gereset, waardoor alle gegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Deze tablet wordt gereset, waardoor alle gegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Deze telefoon wordt gereset, waardoor alle gegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Je hebt <xliff:g id="NUMBER_0">%1$d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt deze gebruiker verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Je hebt <xliff:g id="NUMBER_0">%1$d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt deze gebruiker verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Het Android TV-apparaat wordt binnenkort uitgeschakeld. Druk op een knop om het ingeschakeld te houden."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Het apparaat wordt binnenkort uitgeschakeld. Druk om het ingeschakeld te houden."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Het werkprofiel wordt verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Het werkprofiel wordt verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt je gevraagd je tablet te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%3$d</xliff:g> seconden opnieuw."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt je gevraagd je telefoon te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%3$d</xliff:g> seconden opnieuw."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-or/strings.xml b/packages/SystemUI/res-product/values-or/strings.xml
new file mode 100644
index 0000000..a6190fc
--- /dev/null
+++ b/packages/SystemUI/res-product/values-or/strings.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ଟାବଲେଟ୍‌ରେ କୌଣସି SIM‍ କାର୍ଡ ନାହିଁ।"</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ଫୋନରେ କୌଣସି SIM କାର୍ଡ ନାହିଁ।"</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN କୋଡ୍‍ ମେଳ ହେଉନାହିଁ"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ଆପଣ ଟାବଲେଟକୁ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଭୁଲ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ୍‍ ପ୍ରୟାସ ପରେ, ଏହି ଟାବଲେଟଟି ରିସେଟ୍‍ ହୋଇଯିବ, ଯାହାଦ୍ୱାରା ଏହାର ସମସ୍ତ ଡାଟା ଲିଟ୍‍ ହୋଇଯିବ।"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ଆପଣ ଫୋନକୁ ଅନଲକ୍‍ କରିବାକୁ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଭୁଲ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ୍‍ ପ୍ରୟାସ ପରେ, ଏହି ଫୋନଟି ରିସେଟ୍‍ ହୋଇଯିବ, ଯାହାଦ୍ୱାରା ଏହାର ସମସ୍ତ ଡାଟା ଲିଟ୍‍ ହୋଇଯିବ।"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ଆପଣ ଟାବଲେଟକୁ ଅନଲକ୍‍ କରିବାକୁ <xliff:g id="NUMBER">%d</xliff:g> ଥର ଭୁଲ୍‍ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ଏହି ଟାବଲେଟକୁ ରିସେଟ୍‍ କରାଯିବ, ଯାହାଦ୍ୱାରା ଏହାର ସମସ୍ତ ଡାଟା ଡିଲିଟ୍‍ ହୋଇଯିବ।"</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ଆପଣ ଫୋନଟି ଅନଲକ୍‍ କରିବାକୁ <xliff:g id="NUMBER">%d</xliff:g>ଥର ଭୁଲ୍‍ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ଏହି ଫୋନ୍‍ ରିସେଟ୍‍ କରାଯିବ, ଯାହା ଦ୍ୱାରା ଏହାର ସମସ୍ତ ଡାଟା ଡିଲିଟ୍‍ ହୋଇଯିବ।"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ଆପଣ ଟାବଲେଟ୍‌ଟିକୁ ଅନଲକ୍‍ କରିବା ପାଇଁ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ଭାବେ ଚେଷ୍ଟା କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g> ଟି ଭୁଲ୍‍ ପ୍ରୟାସ ପରେ, ୱାର୍କ ପ୍ରୋଫାଇଲ୍‍କୁ ବାହାର କରିଦିଆଯିବ ଏବଂ ଏହା ଦ୍ୱାରା ସମସ୍ତ ପ୍ରୋଫାଇଲ୍‍ ଡାଟା ଡିଲିଟ୍‍ ହୋଇଯିବ।"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ଆପଣ ଫୋନଟି ଅନଲକ୍‍ କରିବାକୁ <xliff:g id="NUMBER_0">%1$d</xliff:g>ଥର ଭୁଲ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ୍‍ ପ୍ରୟାସ ପରେ, ଏହି ୟୁଜରଙ୍କୁ ବାହାର କରିଦିଆଯିବ ଏବଂ ଏହାଦ୍ୱାରା ସମସ୍ତ ୟୁଜର୍‍ ଡାଟା ଡିଲିଟ୍‍ ହୋଇଯିବ।"</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for notification_bubble_title (8330481035191903164) -->
+    <skip/>
+    <!-- no translation found for notification_channel_summary_bubble (7235935211580860537) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android ଟିଭି ଡିଭାଇସ୍ ଶୀଘ୍ର ବନ୍ଦ ହୋଇଯିବ; ଏହା ଚାଲୁ ରଖିବା ପାଇଁ ଏକ ବଟନ୍ ଦବାନ୍ତୁ।"</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ଡିଭାଇସ୍ ଶୀଘ୍ର ବନ୍ଦ ହୋଇଯିବ; ଚାଲୁ ରଖିବା ପାଇଁ ଦବାନ୍ତୁ।"</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ଆପଣ ଟାବଲେଟକୁ ଅନଲକ୍‍ କରିବାକୁ <xliff:g id="NUMBER">%d</xliff:g> ଭୁଲ୍‍ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। କାର୍ଯ୍ୟ ପ୍ରୋଫାଇଲ୍‍ ବାହାର କରିଦିଆଯିବ, ଯାହାଦ୍ୱାରା ସମସ୍ତ ପ୍ରୋଫାଇଲ୍‍ ଡାଟା ଡିଲିଟ୍‍ ହୋଇଯିବ।"</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ଆପଣ ଫୋନଟି ଅନଲକ୍‍ କରିବାକୁ <xliff:g id="NUMBER">%d</xliff:g>ଥର ଭୁଲ୍‍ ଭାବେ ପ୍ରୟାସ କରିଛନ୍ତି। ୱର୍କ ପ୍ରୋଫାଇଲ୍‍ ବାହାର କରିଦିଆଯିବ, ଯାହା ଦ୍ୱାରା ସମସ୍ତ ପ୍ରୋଫାଇଲ୍‍ ଡାଟା ଡିଲିଟ୍‍ ହୋଇଯିବ।"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ଆପଣଙ୍କ ଅନଲକ୍‍ ପାଟର୍ନକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ଭାବେ ଅଙ୍କନ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g> ଟି ଭୁଲ ପ୍ରୟାସ ପରେ ଏକ ଇମେଲ୍‍ ଆକାଉଣ୍ଟ ବ୍ୟବହାର କରି ନିଜ ଟାବଲେଟକୁ ଅନଲକ୍‌ କରିବା ପାଇଁ କୁହାଯିବ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ଆପଣଙ୍କ ଅନଲକ୍‍ ପାଟର୍ନକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ଭାବେ ଅଙ୍କନ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g> ଟି ଭୁଲ ପ୍ରୟାସ ପରେ ଏକ ଇମେଲ୍‍ ଆକାଉଣ୍ଟ ବ୍ୟବହାର କରି ନିଜ ଫୋନକୁ ଅନଲକ୍‌ କରିବା ପାଇଁ କୁହାଯିବ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-pa/strings.xml b/packages/SystemUI/res-product/values-pa/strings.xml
new file mode 100644
index 0000000..bc16b5a
--- /dev/null
+++ b/packages/SystemUI/res-product/values-pa/strings.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ਟੈਬਲੈੱਟ ਵਿੱਚ ਕੋਈ ਸਿਮ ਕਾਰਡ ਮੌਜੂਦ ਨਹੀਂ।"</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ਫ਼ੋਨ ਵਿੱਚ ਕੋਈ ਸਿਮ ਕਾਰਡ ਮੌਜੂਦ ਨਹੀਂ।"</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"ਪਿੰਨ ਕੋਡ ਮੇਲ ਨਹੀਂ ਖਾਂਦੇ"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਹ ਟੈਬਲੈੱਟ ਰੀਸੈੱਟ ਕੀਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਇਸਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਫ਼ੋਨ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਹ ਫ਼ੋਨ ਰੀਸੈੱਟ ਕੀਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਇਸਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। ਇਹ ਟੈਬਲੈੱਟ ਰੀਸੈੱਟ ਕੀਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਇਸਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਫ਼ੋਨ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। ਇਹ ਫ਼ੋਨ ਰੀਸੈੱਟ ਕੀਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਇਸਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਸ ਵਰਤੋਂਕਾਰ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਸਾਰਾ ਵਰਤੋਂਕਾਰ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਫ਼ੋਨ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਸ ਵਰਤੋਂਕਾਰ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਸਾਰਾ ਵਰਤੋਂਕਾਰ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for notification_bubble_title (8330481035191903164) -->
+    <skip/>
+    <!-- no translation found for notification_channel_summary_bubble (7235935211580860537) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ਡੀਵਾਈਸ ਜਲਦ ਹੀ ਬੰਦ ਹੋ ਜਾਵੇਗਾ; ਇਸਨੂੰ ਚਾਲੂ ਰੱਖਣ ਲਈ ਕੋਈ ਬਟਨ ਦਬਾਓ।"</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ਡੀਵਾਈਸ ਜਲਦ ਹੀ ਬੰਦ ਹੋ ਜਾਵੇਗਾ, ਇਸਨੂੰ ਚਾਲੂ ਰੱਖਣ ਲਈ ਦਬਾਓ।"</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਸਾਰਾ ਪ੍ਰੋਫਾਈਲ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਫ਼ੋਨ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਸਾਰਾ ਪ੍ਰੋਫਾਈਲ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਣਲਾਕ ਪੈਟਰਨ ਗਲਤ ਢੰਗ ਨਾਲ ਉਲੀਕਿਆ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਨੂੰ ਇੱਕ ਈਮੇਲ ਖਾਤਾ ਵਰਤਦੇ ਹੋਏ ਆਪਣੇ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਲਈ ਕਿਹਾ ਜਾਵੇਗਾ।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਣਲਾਕ ਪੈਟਰਨ ਗਲਤ ਢੰਗ ਨਾਲ ਡ੍ਰਾ ਕੀਤਾ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਨੂੰ ਇੱਕ ਈਮੇਲ ਖਾਤਾ ਵਰਤਦੇ ਹੋਏ ਆਪਣਾ ਫ਼ੋਨ ਅਣਲਾਕ ਕਰਨ ਲਈ ਕਿਹਾ ਜਾਏਗਾ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-pl/strings.xml b/packages/SystemUI/res-product/values-pl/strings.xml
new file mode 100644
index 0000000..9ba9b65
--- /dev/null
+++ b/packages/SystemUI/res-product/values-pl/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Brak karty SIM w tablecie."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Brak karty SIM w telefonie."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kody PIN nie pasują"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> próbowałeś nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach tablet zostanie zresetowany, co spowoduje skasowanie wszystkich jego danych."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> próbowałeś nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach telefon zostanie zresetowany, co spowoduje skasowanie wszystkich jego danych."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowałeś nieprawidłowo odblokować tablet. Tablet zostanie zresetowany, co spowoduje skasowanie wszystkich jego danych."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowałeś nieprawidłowo odblokować telefon. Telefon zostanie zresetowany, co spowoduje skasowanie wszystkich jego danych."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> próbowałeś nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach użytkownik zostanie usunięty, co spowoduje skasowanie wszystkich danych użytkownika."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> próbowałeś nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach użytkownik zostanie usunięty, co spowoduje skasowanie wszystkich danych użytkownika."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Urządzenie z Androidem TV za chwilę się wyłączy. Naciśnij przycisk, by pozostało włączone."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Urządzenie za chwilę się wyłączy. Naciśnij, by pozostało włączone."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowałeś nieprawidłowo odblokować tablet. Profil służbowy zostanie usunięty, co spowoduje skasowanie wszystkich danych tego profilu."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowałeś nieprawidłowo odblokować telefon. Profil służbowy zostanie usunięty, co spowoduje skasowanie wszystkich danych tego profilu."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach konieczne będzie odblokowanie tabletu przy użyciu konta e-mail.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach konieczne będzie odblokowanie telefonu przy użyciu konta e-mail.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-pt-rBR/strings.xml b/packages/SystemUI/res-product/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..73a0983
--- /dev/null
+++ b/packages/SystemUI/res-product/values-pt-rBR/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Não há um chip no tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Não há um chip no smartphone."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Os códigos PIN não coincidem"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este smartphone será redefinido, o que excluirá todos os dados dele."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este smartphone será redefinido, o que excluirá todos os dados dele."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este tablet será redefinido, o que excluirá todos os dados dele."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este smartphone será redefinido, o que excluirá todos os dados dele."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este usuário será removido, o que excluirá todos os dados do usuário."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este usuário será removido, o que excluirá todos os dados do usuário."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"O dispositivo Android TV entrará no modo de espera em breve. Pressione um botão para mantê-lo ativado."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"O dispositivo entrará no modo de espera em breve. Pressione para mantê-lo ativado."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-pt-rPT/strings.xml b/packages/SystemUI/res-product/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..e324686
--- /dev/null
+++ b/packages/SystemUI/res-product/values-pt-rPT/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nenhum cartão SIM no tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Nenhum cartão SIM no telemóvel."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Os códigos PIN não coincidem"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, este tablet será reposto, o que eliminará todos os dados do mesmo."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, este telemóvel será reposto, o que eliminará todos os dados do mesmo."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER">%d</xliff:g> vezes. Este tablet será reposto, o que eliminará todos os dados do mesmo."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER">%d</xliff:g> vezes. Este telemóvel será reposto, o que eliminará todos os dados do mesmo."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, este utilizador será removido, o que eliminará todos os dados do mesmo."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, este utilizador será removido, o que eliminará todos os dados do mesmo."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"O dispositivo Android TV irá desligar-se brevemente. Prima um botão para o manter ligado."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"O dispositivo irá desligar-se brevemente. Prima para o manter ligado."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que eliminará todos os dados do mesmo."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que eliminará todos os dados do mesmo."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Desenhou o padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, ser-lhe-á pedido para desbloquear o tablet através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Desenhou o padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, ser-lhe-á pedido para desbloquear o telemóvel através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-pt/strings.xml b/packages/SystemUI/res-product/values-pt/strings.xml
new file mode 100644
index 0000000..73a0983
--- /dev/null
+++ b/packages/SystemUI/res-product/values-pt/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Não há um chip no tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Não há um chip no smartphone."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Os códigos PIN não coincidem"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este smartphone será redefinido, o que excluirá todos os dados dele."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este smartphone será redefinido, o que excluirá todos os dados dele."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este tablet será redefinido, o que excluirá todos os dados dele."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este smartphone será redefinido, o que excluirá todos os dados dele."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este usuário será removido, o que excluirá todos os dados do usuário."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, este usuário será removido, o que excluirá todos os dados do usuário."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"O dispositivo Android TV entrará no modo de espera em breve. Pressione um botão para mantê-lo ativado."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"O dispositivo entrará no modo de espera em breve. Pressione para mantê-lo ativado."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-ro/strings.xml b/packages/SystemUI/res-product/values-ro/strings.xml
new file mode 100644
index 0000000..536d7d9
--- /dev/null
+++ b/packages/SystemUI/res-product/values-ro/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nu există card SIM în tabletă."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Nu există card SIM în telefon."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Codurile PIN nu coincid"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, această tabletă va fi resetată, iar toate datele acesteia vor fi șterse."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acest telefon va fi resetat, iar toate datele acestuia vor fi șterse."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Această tabletă va fi resetată, iar toate datele acesteia vor fi șterse."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Acest telefon va fi resetat, iar toate datele acestuia vor fi șterse."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acest utilizator va fi eliminat, iar toate datele utilizatorului vor fi șterse."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acest utilizator va fi eliminat, iar toate datele utilizatorului vor fi șterse."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Dispozitivul Android TV se va opri în curând. Apăsați un buton pentru a-l menține pornit."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Dispozitivul se va opri în curând. Apăsați pentru a-l menține pornit."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați tableta cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați telefonul cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-ru/strings.xml b/packages/SystemUI/res-product/values-ru/strings.xml
new file mode 100644
index 0000000..a870774
--- /dev/null
+++ b/packages/SystemUI/res-product/values-ru/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Нет SIM-карты."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Нет SIM-карты."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-коды не совпадают."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Вы пытались разблокировать планшет несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи произойдет сброс настроек и все данные на устройстве будут удалены."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Вы пытались разблокировать телефон несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи произойдет сброс настроек и все данные на устройстве будут удалены."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Достигнуто максимальное количество неудачных попыток разблокировать планшет (<xliff:g id="NUMBER">%d</xliff:g>). Настройки устройства будут сброшены, а все его данные – удалены."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Достигнуто максимальное количество неудачных попыток разблокировать телефон (<xliff:g id="NUMBER">%d</xliff:g>). Настройки устройства будут сброшены, а все его данные – удалены."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Вы пытались разблокировать планшет несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи профиль пользователя и все его данные будут удалены."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Вы пытались разблокировать телефон несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи профиль пользователя и все его данные будут удалены."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Устройство Android TV скоро выключится. Чтобы этого не произошло, нажмите любую кнопку."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Устройство скоро выключится. Чтобы этого не произошло, нажмите любую кнопку или коснитесь экрана."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Достигнуто максимальное количество неудачных попыток разблокировать планшет (<xliff:g id="NUMBER">%d</xliff:g>). Рабочий профиль и все его данные будут удалены."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Достигнуто максимальное количество неудачных попыток разблокировать телефон (<xliff:g id="NUMBER">%d</xliff:g>). Рабочий профиль и все его данные будут удалены."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Вы ввели неверный графический ключ несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи вам будет предложено разблокировать планшет с помощью аккаунта электронной почты.\n\nПовторите попытку через <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Вы ввели неверный графический ключ несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи вам будет предложено разблокировать телефон с помощью аккаунта электронной почты.\n\nПовторите попытку через <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-si/strings.xml b/packages/SystemUI/res-product/values-si/strings.xml
new file mode 100644
index 0000000..2d02d1f
--- /dev/null
+++ b/packages/SystemUI/res-product/values-si/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ටැබ්ලටයේ SIM පත නොමැත."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"දුරකථනය තුල SIM පතක් නැත."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN කේත නොගැළපේ."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"ඔබ ටැබ්ලට් පරිගණකය අගුළු හැරීමට <xliff:g id="NUMBER_0">%1$d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. තවත් අසාර්ථක උත්සාහයන් <xliff:g id="NUMBER_1">%2$d</xliff:g>කින් පසුව, මෙම ටැබ්ලට් පරිගණකය යළි සකසනු ඇති අතර, එය එහි සියලු දත්ත මකනු ඇත."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"ඔබ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER_0">%1$d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. තවත් අසාර්ථක උත්සාහයන් <xliff:g id="NUMBER_1">%2$d</xliff:g>කින් පසුව, මෙම දුරකථනය යළි සකසනු ඇති අතර, එය එහි සියලු දත්ත මකනු ඇත."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"ඔබ ටැබ්ලට් පරිගණකය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. මෙම ටැබ්ලට් පරිගණකය යළි සකසනු ඇති අතර, එය එහි සියලු පදත්ත මකනු ඇත."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"ඔබ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. මෙම දුරකථනය යළි සකසනු ඇති අතර, එය එහි සියලු පදත්ත මකනු ඇත."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"ඔබ ටැබ්ලට් පරිගණකය අගුළු හැරීමට <xliff:g id="NUMBER_0">%1$d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. තවත් අසාර්ථක උත්සාහයන් <xliff:g id="NUMBER_1">%2$d</xliff:g>කින් පසුව, මෙම පරිශීලකයා ඉවත් කරනු ඇති අතර, එය සියලු පරිශීලක දත්ත මකනු ඇත."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"ඔබ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER_0">%1$d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. තවත් අසාර්ථක උත්සාහයන් <xliff:g id="NUMBER_1">%2$d</xliff:g>කින් පසුව, මෙම පරිශීලකයා ඉවත් කරනු ඇති අතර, එය සියලු පරිශීලක දත්ත මකනු ඇත."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV උපාංගය ඉක්මනින් ක්‍රියා විරහිත වනු ඇත; එය දිගටම ක්‍රියාත්මක කර තැබීමට බොත්තමක් ඔබන්න."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"උපාංගය ඉක්මනින් ක්‍රියා විරහිත වනු ඇත; එය දිගටම ක්‍රියාත්මක කර තැබීමට ඔබන්න."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"ඔබ ටැබ්ලට් පරිගණකය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. කාර්යාල පැතිකඩ ඉවත් කරනු ඇති අතර, එය සියලු පැතිකඩ දත්ත මකනු ඇත."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"ඔබ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. කාර්යාල පැතිකඩ ඉවත් කරනු ඇති අතර, එය සියලු පැතිකඩ දත්ත මකනු ඇත."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"ඔබ අගුළු ඇරිමේ රටාව <xliff:g id="NUMBER_0">%1$d</xliff:g> වතාවක් වැරදියට ඇඳ ඇත. තවත් අසාර්ථක උත්සාහ <xliff:g id="NUMBER_1">%2$d</xliff:g> කින් පසුව, ඊ-තැපැල් ගිණුම භාවිතා කරමින් ඔබගේ ටැබ්ලටයේ අගුළු ඇරීමට ඔබට පවසනු ඇත.\n\n නැවත තත්පර <xliff:g id="NUMBER_2">%3$d</xliff:g> කින් උත්සාහ කරන්න."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"ඔබ වැරදියට <xliff:g id="NUMBER_0">%1$d</xliff:g> වතාවක් ඔබගේ අගුළු හැරීමේ රටාව ඇඳ ඇත. අසාර්ථක උත්සහ කිරීම් <xliff:g id="NUMBER_1">%2$d</xliff:g> න් පසුව, ඔබගේ ඊ-තැපැල් ලිපිනය භාවිතයෙන් ඔබගේ දුරකථනය අගුළු හැරීමට ඔබගෙන් අසයි.\n\n තත්පර <xliff:g id="NUMBER_2">%3$d</xliff:g> න් පසුව නැවත උත්සහ කරන්න."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-sk/strings.xml b/packages/SystemUI/res-product/values-sk/strings.xml
new file mode 100644
index 0000000..b57ecf9
--- /dev/null
+++ b/packages/SystemUI/res-product/values-sk/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"V tablete nie je žiadna SIM karta."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"V telefóne nie je žiadna SIM karta."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kódy PIN sa nezhodujú"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Tablet ste sa pokúsili <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%2$d</xliff:g>) bude tento tablet obnovený a všetky údaje, ktoré sú v ňom uložené, budú odstránené."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Telefón ste sa pokúsili <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%2$d</xliff:g>) bude tento telefón obnovený a všetky údaje, ktoré sú v ňom uložené, budú odstránené."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Tablet ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Tablet bude obnovený a všetky údaje, ktoré sú v ňom uložené, budú odstránené."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Telefón ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Telefón bude obnovený a všetky údaje, ktoré sú v ňom uložené, budú odstránené."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Tablet ste sa pokúsili <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%2$d</xliff:g>) bude tento používateľ odstránený a spolu s ním všetky jeho údaje."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Telefón ste sa pokúsili <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%2$d</xliff:g>) bude tento používateľ odstránený a spolu s ním všetky jeho údaje."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Zariadenie Android TV sa čoskoro vypne. Ak ho chcete ponechať zapnuté, stlačte ľubovoľné tlačidlo."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Zariadenie sa čoskoro vypne. Ak ho chcete ponechať zapnuté, stlačte ľubovoľné tlačidlo."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Tablet ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Pracovný profil bude odstránený spolu so všetkými údajmi."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Telefón ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Pracovný profil bude odstránený spolu so všetkými údajmi."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Už ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne nakreslili svoj bezpečnostný vzor. Po ďalších <xliff:g id="NUMBER_1">%2$d</xliff:g> neúspešných pokusoch sa zobrazí výzva na odomknutie tabletu pomocou e-mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Už ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krát nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie telefónu pomocou e-mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%3$d</xliff:g>} s."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-sl/strings.xml b/packages/SystemUI/res-product/values-sl/strings.xml
new file mode 100644
index 0000000..99cb111
--- /dev/null
+++ b/packages/SystemUI/res-product/values-sl/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"V tabličnem računalniku ni kartice SIM."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"V telefonu ni kartice SIM."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kodi PIN se ne ujemata"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, bo ponastavljen in vsi podatki v njem bodo izbrisani."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, bo ponastavljen in vsi podatki v njem bodo izbrisani."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat, zato bo ponastavljen, vsi podatki v njem pa bodo izbrisani."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat, zato bo ponastavljen, vsi podatki v njem pa bodo izbrisani."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, bo ta uporabnik odstranjen in vsi podatki uporabnika bodo izbrisani."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, bo ta uporabnik odstranjen in vsi podatki uporabnika bodo izbrisani."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Naprava Android TV se bo kmalu izklopila. Če tega ne želite, pritisnite poljuben gumb."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Naprava se bo kmalu izklopila. Če tega ne želite, pritisnite poljuben gumb."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat. Delovni profil bo odstranjen in vsi podatki profila bodo izbrisani."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat. Delovni profil bo odstranjen in vsi podatki profila bodo izbrisani."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat napačno vnesli. Če ga neuspešno poskusite vnesti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, boste pozvani, da tablični računalnik odklenete z e-poštnim računom.\n\n Poskusite znova čez <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat napačno vnesli. Če ga neuspešno poskusite vnesti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, boste pozvani, da telefon odklenete z Googlovimi podatki za prijavo.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-sq/strings.xml b/packages/SystemUI/res-product/values-sq/strings.xml
new file mode 100644
index 0000000..723c475
--- /dev/null
+++ b/packages/SystemUI/res-product/values-sq/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Nuk ka kartë SIM në tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Në telefon nuk ka kartë SIM."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Kodet PIN nuk përputhen"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë gabimisht për ta shkyçur tabletin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> përpjekjeve të tjera të pasuksesshme, tableti do të rivendoset, gjë që do të rivendosë të gjitha të dhënat e tij."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë gabimisht për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> përpjekjeve të tjera të pasuksesshme, telefoni do të rivendoset, gjë që do të fshijë të gjitha të dhënat e tij."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur tabletin. Ky tablet do të rivendoset, gjë që do të fshijë të gjitha të dhënat e tij."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur telefonin. Ky telefon do të rivendoset, gjë që do të fshijë të gjitha të dhënat e tij."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, përdoruesi do të hiqet dhe të gjitha të dhënat e përdoruesit në të, do të fshihen."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, përdoruesi do të hiqet dhe të gjitha të dhënat e përdoruesit në të, do të fshihen."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Pajisja Android TV do të fiket së shpejti. Shtyp një buton për ta mbajtur të ndezur."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Pajisja do të fiket së shpejti. Shtype për ta mbajtur të ndezur."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur tabletin. Profili i punës do të hiqet, gjë që do të fshijë të gjitha të dhënat e profilit."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur telefonin. Profili i punës do të hiqet, gjë që do të fshijë të gjitha të dhënat e profilit."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Ke vizatuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses motivin tënd të shkyçjes. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, do të të duhet ta shkyçësh tabletin duke përdorur një llogari mail-i.\n\n Provo sërish për <xliff:g id="NUMBER_2">%3$d</xliff:g> sekonda."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Ke vizatuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses motivin tënd të shkyçjes. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, do të të duhet ta shkyçësh telefonin duke përdorur një llogari mail-i.\n\n Provo sërish për <xliff:g id="NUMBER_2">%3$d</xliff:g> sekonda."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-sr/strings.xml b/packages/SystemUI/res-product/values-sr/strings.xml
new file mode 100644
index 0000000..0e6106e
--- /dev/null
+++ b/packages/SystemUI/res-product/values-sr/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"У таблету нема SIM картице."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"У телефону нема SIM картице."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN кодови се не подударају"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, овај таблет ће се ресетовати, чиме се бришу сви подаци корисника."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, овај телефон ће се ресетовати, чиме се бришу сви подаци корисника."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER">%d</xliff:g> пута. Овај таблет ће се ресетовати, чиме се бришу сви подаци."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пута. Овај телефон ће се ресетовати, чиме се бришу сви подаци."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, уклонићемо овог корисника, чиме се бришу сви подаци корисника."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, уклонићемо овог корисника, чиме се бришу сви подаци корисника."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ће се ускоро искључити. Притисните дугме да би остао укључен."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Уређај ће се ускоро искључити. Притисните да би остао укључен."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER">%d</xliff:g> пута. Уклонићемо профил за Work, чиме се бришу сви подаци са профила."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пута. Уклонићемо профил за Work, чиме се бришу сви подаци са профила."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Нетачно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, затражићемо да откључате таблет помоћу имејл налога.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Нетачно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, затражићемо да откључате телефон помоћу имејл налога.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-sv/strings.xml b/packages/SystemUI/res-product/values-sv/strings.xml
new file mode 100644
index 0000000..05de9eb
--- /dev/null
+++ b/packages/SystemUI/res-product/values-sv/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Inget SIM-kort i surfplattan."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Inget SIM-kort i mobilen."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Pinkoderna stämmer inte överens"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök återställs surfplattan och all data raderas."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök återställs mobilen och all data raderas."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Surfplattan återställs och all data raderas."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Mobilen återställs och all data raderas."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök tas användaren bort och all användardata raderas."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök tas användaren bort och all användardata raderas."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV-enheten stängs snart av. Tryck på en knapp för att behålla den på."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Enheten stängs snart av. Tryck för att behålla den på."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Jobbprofilen tas bort och all profildata raderas."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Jobbprofilen tas bort och all profildata raderas."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök måste du låsa upp surfplattan med hjälp av ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök måste du låsa upp mobilen med hjälp av ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-sw/strings.xml b/packages/SystemUI/res-product/values-sw/strings.xml
new file mode 100644
index 0000000..09eb0b2b
--- /dev/null
+++ b/packages/SystemUI/res-product/values-sw/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Hakuna SIM kadi katika kompyuta kibao."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Hakuna SIM kadi kwenye simu."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Nambari za PIN hazifanani"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Umejaribu kufungua kompyuta kibao mara <xliff:g id="NUMBER_0">%1$d</xliff:g> bila mafanikio. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>,  kompyuta hii kibao itarejeshwa katika hali iliyotoka nayo kiwandani, hatua itakayofuta data yake yote."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Umejaribu kufungua simu mara <xliff:g id="NUMBER_0">%1$d</xliff:g> bila mafanikio. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, simu hii itarejeshwa katika hali iliyotoka nayo kiwandani, hatua itakayofuta data yake yote."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Umejaribu kufungua simu mara <xliff:g id="NUMBER">%d</xliff:g> bila mafanikio. Kompyuta hii kibao itarejeshwa katika hali iliyotoka nayo kiwandani, hatua itakayofuta data yake yote."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Umejaribu kufungua simu mara <xliff:g id="NUMBER">%d</xliff:g> bila mafanikio. Simu hii itarejeshwa katika hali iliyotoka nayo kiwandani, hatua itakayofuta data yake yote."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Umejaribu kufungua kompyuta kibao mara <xliff:g id="NUMBER_0">%1$d</xliff:g> bila mafanikio. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, mtumiaji huyu ataondolewa, hatua itakayofuta data yake yote."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Umejaribu kufungua simu mara <xliff:g id="NUMBER_0">%1$d</xliff:g> bila mafanikio. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, mtumiaji huyu ataondolewa, hatua itakayofuta data yake yote."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Kifaa cha Android TV kitazima hivi karibuni; bonyeza kitufe ili kisizime."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Kifaa kitazima hivi karibuni; bonyeza ili kisizime."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Umejaribu kufungua kompyuta kibao mara <xliff:g id="NUMBER">%d</xliff:g> bila mafanikio. Wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Umejaribu kufungua simu mara <xliff:g id="NUMBER">%d</xliff:g> bila mafanikio. Wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, utaombwa kufungua kompyuta yako kibao kwa kutumia akaunti yako ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, utaombwa kufungua simu yako kwa kutumia akaunti ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-ta/strings.xml b/packages/SystemUI/res-product/values-ta/strings.xml
new file mode 100644
index 0000000..35e3f82
--- /dev/null
+++ b/packages/SystemUI/res-product/values-ta/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"டேப்லெட்டில் சிம் கார்டு இல்லை."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"மொபைலில் சிம் கார்டு இல்லை."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"பின் குறியீடுகள் பொருந்தவில்லை"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"டேப்லெட்டைத் திறக்க, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக முயன்றால், இந்த டேப்லெட் மீட்டமைக்கப்பட்டு, அதன் எல்லாத் தரவும் நீக்கப்படும்."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"மொபைலைத் திறக்க, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக முயன்றால், இந்த மொபைல் மீட்டமைக்கப்பட்டு, அதன் எல்லாத் தரவும் நீக்கப்படும்."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"டேப்லெட்டைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இந்த டேப்லெட் மீட்டமைக்கப்பட்டு, அதன் எல்லாத் தரவும் நீக்கப்படும்."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"மொபைலைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இந்த மொபைல் மீட்டமைக்கப்பட்டு, அதன் எல்லாத் தரவும் நீக்கப்படும்."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"டேப்லெட்டைத் திறக்க, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக முயன்றால், இந்தப் பயனர் அகற்றப்பட்டு, எல்லாப் பயனர் தரவும் நீக்கப்படும்."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"மொபைலைத் திறக்க, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக முயன்றால், இந்தப் பயனர் அகற்றப்பட்டு, எல்லாப் பயனர் தரவும் நீக்கப்படும்."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV விரைவில் ஆஃப் ஆகலாம். இதைத் தொடர்ந்து ஆனில் வைக்க ஒரு பட்டனைத் தட்டவும்."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"இந்தச் சாதனம் விரைவில் ஆஃப் ஆகலாம், இதைத் தொடர்ந்து ஆனில் வைக்கத் தட்டவும்."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"டேப்லெட்டைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். பணிக் கணக்கு அகற்றப்பட்டு, எல்லாச் சுயவிவரத் தரவும் நீக்கப்படும்."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"மொபைலைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயன்றுவிட்டீர்கள். பணிக் கணக்கு அகற்றப்பட்டு, எல்லாச் சுயவிவரத் தரவும் நீக்கப்படும்."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"திறப்பதற்கான பேட்டர்னை, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக வரைந்துவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக வரைந்தால், மின்னஞ்சல் கணக்கைப் பயன்படுத்தி டேப்லெட்டைத் திறக்கும்படி கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> வினாடிகளில் மீண்டும் முயலவும்."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"திறப்பதற்கான பேட்டர்னை, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக வரைந்துவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக வரைந்தால், மின்னஞ்சல் கணக்கைப் பயன்படுத்தி மொபைலைத் திறக்கும்படி கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> வினாடிகளில் மீண்டும் முயலவும்."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-te/strings.xml b/packages/SystemUI/res-product/values-te/strings.xml
new file mode 100644
index 0000000..6f172ee
--- /dev/null
+++ b/packages/SystemUI/res-product/values-te/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"టాబ్లెట్‌లో SIM కార్డ్ లేదు."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ఫోన్‌లో SIM కార్డ్ లేదు."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"పిన్ కోడ్‌లు సరిపోలలేదు"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"మీరు టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఈ టాబ్లెట్ రీసెట్ చేయబడుతుంది, తద్వారా ఇందులోని మొత్తం డేటా తొలగించబడుతుంది."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఈ ఫోన్ రీసెట్ చేయబడుతుంది, తద్వారా ఇందులోని మొత్తం డేటా తొలగించబడుతుంది."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"మీరు టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. ఈ టాబ్లెట్ రీసెట్ చేయబడుతుంది, తద్వారా ఇందులోని మొత్తం డేటా తొలగించబడుతుంది."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. ఈ ఫోన్ రీసెట్ చేయబడుతుంది, తద్వారా ఇందులోని మొత్తం డేటా తొలగించబడుతుంది."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"మీరు టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఈ వినియోగదారు తీసివేయబడతారు, తద్వారా వినియోగదారు డేటా మొత్తం తొలగించబడుతుంది."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"మీరు ఫోన్‌ని అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఈ వినియోగదారు తీసివేయబడతారు, తద్వారా వినియోగదారు డేటా మొత్తం తొలగించబడుతుంది."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV పరికరం త్వరలో ఆఫ్ అయిపోతుంది; దాన్ని ఆన్‌లో ఉంచడానికి బటన్‌ను నొక్కండి."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"పరికరం త్వరలో ఆఫ్ అయిపోతుంది; దీన్ని ఆన్‌లో ఉంచడానికి నొక్కండి."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"మీరు టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. కార్యాలయ ప్రొఫైల్ తీసివేయబడుతుంది, తద్వారా ప్రొఫైల్ డేటా మొత్తం తొలగించబడుతుంది."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"మీరు ఫోన్‌ని అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేసారు. కార్యాలయ ప్రొఫైల్ తీసివేయబడుతుంది, తద్వారా ప్రొఫైల్ డేటా మొత్తం తొలగించబడుతుంది."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, మీరు ఇమెయిల్ ఖాతాను ఉపయోగించి మీ టాబ్లెట్‌ను అన్‌లాక్ చేయాల్సి వస్తుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, మీరు ఇమెయిల్ ఖాతాను ఉపయోగించి మీ ఫోన్‌ను అన్‌లాక్ చేయాల్సి వస్తుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-th/strings.xml b/packages/SystemUI/res-product/values-th/strings.xml
new file mode 100644
index 0000000..8c9e72a
--- /dev/null
+++ b/packages/SystemUI/res-product/values-th/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"ไม่มีซิมการ์ดในแท็บเล็ต"</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"ไม่มีซิมการ์ดในโทรศัพท์"</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"รหัส PIN ไม่ตรง"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะรีเซ็ตแท็บเล็ตเครื่องนี้ ซึ่งจะเป็นการลบข้อมูลทั้งหมดในเครื่อง"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะรีเซ็ตโทรศัพท์เครื่องนี้ ซึ่งจะเป็นการลบข้อมูลทั้งหมดในเครื่อง"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะรีเซ็ตแท็บเล็ตเครื่องนี้ ซึ่งจะเป็นการลบข้อมูลทั้งหมดในเครื่อง"</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะรีเซ็ตโทรศัพท์เครื่องนี้ ซึ่งจะเป็นการลบข้อมูลทั้งหมดในเครื่อง"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะนำผู้ใช้รายนี้ออก ซึ่งจะเป็นการลบข้อมูลทั้งหมดของผู้ใช้"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะนำผู้ใช้รายนี้ออก ซึ่งจะเป็นการลบข้อมูลทั้งหมดของผู้ใช้"</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"อุปกรณ์ Android TV จะปิดเครื่องในอีกไม่ช้า กดปุ่มเพื่อเปิดอุปกรณ์ต่อไป"</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"อุปกรณ์จะปิดเครื่องในอีกไม่ช้า กดเพื่อเปิดอุปกรณ์ต่อไป"</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะนำโปรไฟล์งานออก ซึ่งจะเป็นการลบข้อมูลโปรไฟล์ทั้งหมด"</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะนำโปรไฟล์งานออก ซึ่งจะเป็นการลบข้อมูลโปรไฟล์ทั้งหมด"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกแท็บเล็ตโดยใช้บัญชีอีเมล\n\n โปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_2">%3$d</xliff:g> วินาที"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกโทรศัพท์โดยใช้บัญชีอีเมล\n\n โปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_2">%3$d</xliff:g> วินาที"</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-tl/strings.xml b/packages/SystemUI/res-product/values-tl/strings.xml
new file mode 100644
index 0000000..d3901ee
--- /dev/null
+++ b/packages/SystemUI/res-product/values-tl/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Walang SIM card sa tablet."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Walang SIM card sa telepono."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Hindi nagtutugma ang mga PIN code"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, ire-reset ang tablet na ito, na magiging dahilan upang ma-delete ang lahat ng data nito."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, ire-reset ang teleponong ito, na magiging dahilan upang ma-delete ang lahat ng data nito."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Ire-reset ang tablet na ito, na magiging dahilan upang ma-delete ang lahat ng data nito."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Ire-reset ang teleponong ito, na magiging dahilan upang ma-delete ang lahat ng data nito."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, aalisin ang user na ito, na magiging dahilan upang ma-delete ang lahat ng data ng user."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, aalisin ang user na ito, na magiging dahilan upang ma-delete ang lahat ng data ng user."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Mao-off na ang Android TV device; pumindot ng button para panatilihin itong naka-on."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Mao-off na ang device; pumindot para panatilihin itong naka-on."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Aalisin ang profile sa trabaho, na magiging dahilan upang ma-delete ang lahat ng data sa profile."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Aalisin ang profile sa trabaho, na magiging dahilan upang ma-delete ang lahat ng data sa profile."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, hihilingin sa iyong i-unlock ang tablet mo gamit ang isang email account.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%3$d</xliff:g> (na) segundo."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, hihilingin sa iyong i-unlock ang telepono mo gamit ang isang email account.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%3$d</xliff:g> (na) segundo."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-tr/strings.xml b/packages/SystemUI/res-product/values-tr/strings.xml
new file mode 100644
index 0000000..d6e0c39
--- /dev/null
+++ b/packages/SystemUI/res-product/values-tr/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Tablette SIM kart yok."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefonda SIM kart yok."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kodları eşleşmiyor"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Tabletin kilidini <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız bu tablet sıfırlanacak ve tüm verileri silinecektir."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Telefonun kilidini <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız bu telefon sıfırlanacak ve tüm verileri silinecektir."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Tabletin kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. Bu tablet sıfırlanacak ve tüm verileri silinecektir."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Telefonun kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. Bu telefon sıfırlanacak ve tüm verileri silinecektir."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Tabletin kilidini <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız bu kullanıcı kaldırılacak ve tüm kullanıcı verileri silinecektir."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Telefonun kilidini <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız bu kullanıcı kaldırılacak ve tüm kullanıcı verileri silinecektir."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV cihazı kısa süre içinde kapanacak. Cihazınızı açık tutmak için bir düğmeye basın."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Cihaz kısa süre içinde kapanacak. Cihazı açık tutmak için düğmeye basın."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Tabletin kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. İş profili kaldırılacak ve tüm profil verileri silinecektir."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Telefonun kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. İş profili kaldırılacak ve tüm profil verileri silinecektir."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%1$d</xliff:g> defa yanlış çizdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız denemeden sonra, tabletinizin kilidini bir e-posta hesabı kullanarak açmanız istenir.\n<xliff:g id="NUMBER_2">%3$d</xliff:g>\n saniye içinde tekrar deneyin."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%1$d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız denemeden sonra telefonunuzun kilidini bir e-posta hesabı kullanarak açmanız istenir.\n<xliff:g id="NUMBER_2">%3$d</xliff:g>\n saniye içinde tekrar deneyin."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-uk/strings.xml b/packages/SystemUI/res-product/values-uk/strings.xml
new file mode 100644
index 0000000..a53043c
--- /dev/null
+++ b/packages/SystemUI/res-product/values-uk/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"У пристрої немає SIM-карти."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"У телефоні немає SIM-карти."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN-коди не збігаються"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Кількість невдалих спроб розблокувати планшет: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі буде скинуто налаштування планшета й видалено всі його дані."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі буде скинуто налаштування телефона й видалено всі його дані."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Кількість невдалих спроб розблокувати планшет: <xliff:g id="NUMBER">%d</xliff:g>. Буде скинуто налаштування цього планшета й видалено всі його дані."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER">%d</xliff:g>. Буде скинуто налаштування цього телефона й видалено всі його дані."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Кількість невдалих спроб розблокувати планшет: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі буде видалено цього користувача й усі його дані."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі буде видалено цього користувача й усі його дані."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Незабаром пристрій Android TV буде вимкнено. Натисніть кнопку, щоб цього не сталося."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Незабаром пристрій буде вимкнено. Натисніть, щоб цього не сталося."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Кількість невдалих спроб розблокувати планшет: <xliff:g id="NUMBER">%d</xliff:g>. Буде видалено робочий профіль і всі його дані."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER">%d</xliff:g>. Буде видалено робочий профіль і всі його дані."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі з’явиться запит розблокувати планшет за допомогою облікового запису електронної пошти.\n\n Повторіть спробу через <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі з’явиться запит розблокувати телефон за допомогою облікового запису електронної пошти.\n\n Повторіть спробу через <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-ur/strings.xml b/packages/SystemUI/res-product/values-ur/strings.xml
new file mode 100644
index 0000000..4569ee3
--- /dev/null
+++ b/packages/SystemUI/res-product/values-ur/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"‏ٹیبلیٹ میں کوئی SIM کارڈ نہیں ہے۔"</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"‏فون میں کوئی SIM کارڈ نہيں ہے۔"</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"‏PIN کوڈز مماثل نہیں ہیں"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، اس ٹیبلیٹ کو دوبارہ ترتیب دے دیا جائے گا، جس سے اس کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، اس فون کو دوبارہ ترتیب دے دیا جائے گا، جس سے اس کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ اس ٹیبلیٹ کو دوبارہ ترتیب دے دیا جائے گا، جس سے اس کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ اس فون کو دوبارہ ترتیب دے دیا جائے گا، جس سے اس کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، اس صارف کو ہٹا دیا جائے گا، جس سے صارف کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، اس صارف کو ہٹا دیا جائے گا، جس سے صارف کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"‏Android TV آلہ جلد ہی بند ہوجائے گا آن رکھنے کے ليے بٹن دبائیں۔"</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"آلہ جلد ہی بند ہوجائے گا اسے آن رکھنے کے ليے دبائیں۔"</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ دفتری پروفائل ہٹا دیا جائے گا، جس سے پروفائل کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ دفتری پروفائل ہٹا دیا جائے گا، جس سے پروفائل کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کرکے اپنا ٹیبلیٹ غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کرکے اپنا فون غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-uz/strings.xml b/packages/SystemUI/res-product/values-uz/strings.xml
new file mode 100644
index 0000000..105ae9d
--- /dev/null
+++ b/packages/SystemUI/res-product/values-uz/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Planshetingizda SIM karta yo‘q."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Telefoningizda SIM karta yo‘q."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN kod mos kelmadi"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu planshetda zavod sozlamalari qayta tiklanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu telefonda zavod sozlamalari qayta tiklanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ushbu planshetda zavod sozlamalari qayta tiklanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ushbu telefonda zavod sozlamalari qayta tiklanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu foydalanuvchi o‘chirib tashlanadi va undagi barcha foydalanuvchi ma’lumotlari ham o‘chib ketadi."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ushbu foydalanuvchi o‘chirib tashlanadi va undagi barcha foydalanuvchi ma’lumotlari ham o‘chib ketadi."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV qurilmasi oʻchish arafasida, yoniq qolishi uchun istalgan tugmani bosing."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Qurilma oʻchish arafasida, yoniq qolishi uchun istalgan tugmani bosing."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ishchi profil o‘chirib tashlanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ishchi profil o‘chirib tashlanadi va undagi barcha ma’lumotlar ham o‘chib ketadi."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Grafik kalit <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato chizildi. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan keyin, sizdan e-pochtangizdan foydalanib, planshet qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan keyin yana urinib ko‘ring."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Grafik kalit <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato chizildi. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan keyin, sizdan e-pochtangizdan foydalanib, telefon qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan keyin qayta urinib ko‘ring."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-vi/strings.xml b/packages/SystemUI/res-product/values-vi/strings.xml
new file mode 100644
index 0000000..c9022ee
--- /dev/null
+++ b/packages/SystemUI/res-product/values-vi/strings.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Không có thẻ SIM nào trong máy tính bảng."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Không có thẻ SIM nào trong điện thoại."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Mã PIN không khớp"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần mở khóa không thành công nữa, máy tính bảng này sẽ được đặt lại, tức là tất cả dữ liệu của máy tính bảng sẽ bị xóa."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần mở khóa không thành công nữa, điện thoại này sẽ được đặt lại, tức là tất cả dữ liệu của điện thoại sẽ bị xóa."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER">%d</xliff:g> lần. Máy tính bảng này sẽ được đặt lại, tức là tất cả dữ liệu của máy tính bảng sẽ bị xóa."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER">%d</xliff:g> lần. Điện thoại này sẽ được đặt lại, tức là tất cả dữ liệu của điện thoại sẽ bị xóa."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần mở khóa không thành công nữa, người dùng này sẽ bị xóa, tức là tất cả dữ liệu người dùng sẽ bị xóa."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần mở khóa không thành công nữa, người dùng này sẽ bị xóa, tức là tất cả dữ liệu người dùng sẽ bị xóa."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for notification_bubble_title (8330481035191903164) -->
+    <skip/>
+    <!-- no translation found for notification_channel_summary_bubble (7235935211580860537) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Thiết bị Android TV sẽ sớm tắt. Hãy nhấn vào một nút để thiết bị vẫn bật."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Thiết bị sẽ sớm tắt. Hãy nhấn vào một nút để thiết bị vẫn bật."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER">%d</xliff:g> lần. Hồ sơ công việc sẽ bị xóa, tức là tất cả dữ liệu hồ sơ sẽ bị xóa."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER">%d</xliff:g> lần. Hồ sơ công việc sẽ bị xóa, tức là tất cả dữ liệu hồ sơ sẽ bị xóa."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Bạn đã vẽ không chính xác hình mở khóa <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa máy tính bảng bằng tài khoản email.\n\n Hãy thử lại sau <xliff:g id="NUMBER_2">%3$d</xliff:g> giây."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Bạn đã vẽ không chính xác hình mở khóa <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa điện thoại bằng tài khoản email.\n\n Hãy thử lại sau <xliff:g id="NUMBER_2">%3$d</xliff:g> giây."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-zh-rCN/strings.xml b/packages/SystemUI/res-product/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..7109c99
--- /dev/null
+++ b/packages/SystemUI/res-product/values-zh-rCN/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"平板电脑中没有 SIM 卡。"</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"手机中没有 SIM 卡。"</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN 码不匹配"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"您尝试解锁平板电脑后失败的次数已达 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,平板电脑将会被重置,而这将删除其中的所有数据。"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"您尝试解锁手机后失败的次数已达 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,手机将会被重置,而这将删除其中的所有数据。"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"您尝试解锁平板电脑后失败的次数已达 <xliff:g id="NUMBER">%d</xliff:g> 次。这部平板电脑将会被重置,而这将删除其中的所有数据。"</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"您尝试解锁手机后失败的次数已达 <xliff:g id="NUMBER">%d</xliff:g> 次。这部手机将会被重置,而这将删除其中的所有数据。"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"您尝试解锁平板电脑后失败的次数已达 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统将移除此用户,而这将删除所有的用户数据。"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"您尝试解锁手机后失败的次数已达 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统将移除此用户,而这将删除所有的用户数据。"</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV 设备即将关闭;按一下相应的按钮即可让设备保持开启状态。"</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"设备即将关闭;按一下即可让设备保持开启状态。"</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"您尝试解锁平板电脑后失败的次数已达 <xliff:g id="NUMBER">%d</xliff:g> 次。系统将移除此工作资料,而这将删除所有的工作资料数据。"</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"您尝试解锁手机后失败的次数已达 <xliff:g id="NUMBER">%d</xliff:g> 次。系统将移除此工作资料,而这将删除所有的工作资料数据。"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"您已 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁平板电脑。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"您已 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁手机。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-zh-rHK/strings.xml b/packages/SystemUI/res-product/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..233b245
--- /dev/null
+++ b/packages/SystemUI/res-product/values-zh-rHK/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"平板電腦中沒有 SIM 卡。"</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"手機中沒有 SIM 卡。"</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN 碼不符"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統將重設此平板電腦,而平板電腦的所有資料亦會一併刪除。"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統將重設此手機,而手機的所有資料亦會一併刪除。"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統將重設此平板電腦,而平板電腦的所有資料亦會一併刪除。"</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統將重設此手機,而手機的所有資料亦會一併刪除。"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統將移除此使用者,而所有使用者資料亦會一併刪除。"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統將移除此使用者,而所有使用者資料亦會一併刪除。"</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV 裝置即將關閉,按下按鈕即可保持開啟。"</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"裝置即將關閉,輕按即可保持開啟。"</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統將移除此工作設定檔,而所有設定檔資料亦會一併刪除。"</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統將移除此工作設定檔,而所有設定檔資料亦會一併刪除。"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解鎖平板電腦。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解鎖手機。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-zh-rTW/strings.xml b/packages/SystemUI/res-product/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..87e7dc4
--- /dev/null
+++ b/packages/SystemUI/res-product/values-zh-rTW/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"平板電腦中沒有 SIM 卡。"</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"手機中沒有 SIM 卡。"</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"PIN 碼不符"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"你嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,系統會重設這台平板電腦,其中的所有資料也會一併遭到刪除。"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"你嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,系統會重設這支手機,其中的所有資料也會一併遭到刪除。"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"你嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統會重設這台平板電腦,其中的所有資料也會一併遭到刪除。"</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"你嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統會重設這支手機,其中的所有資料也會一併遭到刪除。"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"你嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,這位使用者將遭到移除,所有相關的使用者資料也會一併遭到刪除。"</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"你嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,這位使用者將遭到移除,所有相關的使用者資料也會一併遭到刪除。"</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV 裝置即將進入待機模式。如要讓裝置保持開啟狀態,請按下任一按鈕。"</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"裝置即將進入待機模式。如要讓裝置保持開啟狀態,請輕觸螢幕或按下按鈕。"</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"你嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。你的工作資料夾將遭到移除,所有設定檔資料也會一併遭到刪除。"</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"你嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。你的工作資料夾將遭到移除,所有設定檔資料也會一併遭到刪除。"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"你的解鎖圖案已畫錯 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,系統就會要求你透過電子郵件帳戶解鎖平板電腦。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"你的解鎖圖案已畫錯 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,系統就會要求你透過電子郵件帳戶解鎖手機。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values-zu/strings.xml b/packages/SystemUI/res-product/values-zu/strings.xml
new file mode 100644
index 0000000..2c8728b6
--- /dev/null
+++ b/packages/SystemUI/res-product/values-zu/strings.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for global_action_screenshot (2760267567509131654) -->
+    <string name="keyguard_missing_sim_message" product="tablet" msgid="3088787847082615459">"Alikho ikhadi le-SIM efonini."</string>
+    <string name="keyguard_missing_sim_message" product="default" msgid="5124049236681993063">"Alikho ikhadi le-SIM efonini."</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="1500814146841660886">"Iphinikhodi ayifani"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="2445671146665131857">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%2$d</xliff:g> engaphumelelanga, le thebulethi izosethwa kabusha, okuzosusa yonke idatha yayo."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4738318327984389472">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%2$d</xliff:g> engaphumelelanga, le foni izosethwa kabusha, okuzosusa yonke idatha yayo."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="6974065787881197466">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Le thebulethi izosethwa kabusha, okuzosusa yonke idatha yayo."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4645797157486540692">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Le foni izosethwa kabusha, okuzosusa yonke idatha yayo."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="2444432908572039632">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%2$d</xliff:g> engaphumelelanga, lo msebenzisi uzosuswa, okuzosusa yonke idatha yomsebenzisi."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="3230300995829296824">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%2$d</xliff:g> engaphumelelanga, lo msebenzisi uzosuswa, okuzosusa yonke idatha yomsebenzisi."</string>
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (9046628517316763961) -->
+    <skip/>
+    <!-- no translation found for cancel (1089011503403416730) -->
+    <!-- no translation found for kg_failed_attempts_now_erasing_user (3588779327358321092) -->
+    <skip/>
+    <!-- no translation found for accessibility_casting (8708751252897282313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (6114158710353725041) -->
+    <skip/>
+    <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
+    <!-- no translation found for kg_failed_attempts_almost_at_erase_profile (8345451368768804892) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_slow_charging (5148122851798085807) -->
+    <skip/>
+    <!-- no translation found for dock_alignment_not_charging (1002617659995575624) -->
+    <skip/>
+    <!-- no translation found for reset (8715144064608810383) -->
+    <skip/>
+    <!-- no translation found for notification_channel_alerts (3385787053375150046) -->
+    <skip/>
+    <!-- no translation found for app_info (5153758994129963243) -->
+    <skip/>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Idivayisi ye-Android TV maduze izovalwa, cindezela inkinobho ukuze uyigcine ivuliwe."</string>
+    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Idivayisi maduze izovalwa, cindezela ukuze uyigcine ivuliwe."</string>
+<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="9063715142119087685">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Iphrofayela yomsebenzi izosuswa, okuzosusa yonke idatha yephrofayela."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="105463960684230996">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Iphrofayela yomsebenzi izosuswa, okuzosusa yonke idatha yephrofayela."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="5123792377735688284">"Udwebe ngokungalungile iphethini yakho yokuvula ngezikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphumelelanga kaningi engu-<xliff:g id="NUMBER_1">%2$d</xliff:g>, uzocelwa ukuthi uvule ithebulethi yakho usebenzisa i-akhawunti ye-imeyili.\n\nZama futhi kumasekhondi angu-<xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="3307854957632348753">"Ukulayisha ungenisa iphathini yakho yokuvula ngendlela engalungile izikhathi ezi-<xliff:g id="NUMBER_0">%1$d</xliff:g> Emva kweminye imizamo engu-<xliff:g id="NUMBER_1">%2$d</xliff:g>, uzocelwa ukuvula ifoni yakho usebenzisa ukungena ngemvume ku-Google\n\n Zame futhi emumva kwengu- <xliff:g id="NUMBER_2">%3$d</xliff:g> imizuzwana."</string>
+</resources>
diff --git a/packages/SystemUI/res-product/values/strings.xml b/packages/SystemUI/res-product/values/strings.xml
new file mode 100644
index 0000000..54e5d41
--- /dev/null
+++ b/packages/SystemUI/res-product/values/strings.xml
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Indication when device is slow charging due to misalignment on the dock. [CHAR LIMIT=60] -->
+    <string name="dock_alignment_slow_charging" product="default">Realign phone for faster charging</string>
+
+    <!-- Indication when device is not charging due to bad placement on the dock. [CHAR LIMIT=60] -->
+    <string name="dock_alignment_not_charging" product="default">Realign phone to charge wirelessly</string>
+
+    <!-- Message of the overlay warning the user to interact with the device or it will go to sleep. [CHAR LIMIT=NONE] -->
+    <string name="inattentive_sleep_warning_message" product="tv">The Android TV device will soon turn off; press a button to keep it on.</string>
+    <!-- Message of the overlay warning the user to interact with the device or it will go to sleep. [CHAR LIMIT=NONE] -->
+    <string name="inattentive_sleep_warning_message" product="default">The device will soon turn off; press to keep it on.</string>
+
+    <!-- Shown when there is no SIM card. -->
+    <string name="keyguard_missing_sim_message" product="tablet">No SIM card in tablet.</string>
+    <!-- Shown when there is no SIM card. -->
+    <string name="keyguard_missing_sim_message" product="default">No SIM card in phone.</string>
+
+    <!-- String shown in PUK screen when PIN codes don't match -->
+    <string name="kg_invalid_confirm_pin_hint" product="default">PIN codes does not match</string>
+
+    <!-- Message shown when user is almost at the limit of password attempts where the device will be wiped. [CHAR LIMIT=none] -->
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet">
+       You have incorrectly attempted to unlock the tablet <xliff:g id="number">%1$d</xliff:g> times.
+       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
+       this tablet will be reset, which will delete all its data.
+    </string>
+    <!-- Message shown when user is almost at the limit of password attempts where the device will be wiped. [CHAR LIMIT=none] -->
+    <string name="kg_failed_attempts_almost_at_wipe" product="default">
+       You have incorrectly attempted to unlock the phone <xliff:g id="number">%1$d</xliff:g> times.
+       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
+       this phone will be reset, which will delete all its data.
+    </string>
+    <!-- Message shown in dialog when user has exceeded the maximum attempts and the device will now be wiped [CHAR LIMIT=none] -->
+    <string name="kg_failed_attempts_now_wiping" product="tablet">
+       You have incorrectly attempted to unlock the tablet <xliff:g id="number">%d</xliff:g> times.
+       This tablet will be reset, which will delete all its data.
+    </string>
+    <!-- Message shown in dialog when user has exceeded the maximum attempts and the device will now be wiped [CHAR LIMIT=none] -->
+    <string name="kg_failed_attempts_now_wiping" product="default">
+       You have incorrectly attempted to unlock the phone <xliff:g id="number">%d</xliff:g> times.
+       This phone will be reset, which will delete all its data.
+    </string>
+
+    <!-- Message shown when user is almost at the limit of password attempts where the user will be removed. [CHAR LIMIT=none] -->
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet">
+       You have incorrectly attempted to unlock the tablet <xliff:g id="number">%1$d</xliff:g> times.
+       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
+       this user will be removed, which will delete all user data.
+    </string>
+    <!-- Message shown when user is almost at the limit of password attempts where the user will be removed. [CHAR LIMIT=none] -->
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default">
+       You have incorrectly attempted to unlock the phone <xliff:g id="number">%1$d</xliff:g> times.
+       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
+       this user will be removed, which will delete all user data.
+    </string>
+    <!-- Message shown in dialog when user has exceeded the maximum attempts and the user will be removed. [CHAR LIMIT=none] -->
+    <string name="kg_failed_attempts_now_erasing_user" product="tablet">
+       You have incorrectly attempted to unlock the tablet <xliff:g id="number">%d</xliff:g> times.
+       This user will be removed, which will delete all user data.
+    </string>
+    <!-- Message shown in dialog when user has exceeded the maximum attempts and the user will be removed. [CHAR LIMIT=none] -->
+    <string name="kg_failed_attempts_now_erasing_user" product="default">
+       You have incorrectly attempted to unlock the phone <xliff:g id="number">%d</xliff:g> times.
+       This user will be removed, which will delete all user data.
+    </string>
+
+    <!-- Message shown when user is almost at the limit of password attempts where the profile will be removed. [CHAR LIMIT=none] -->
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet">
+       You have incorrectly attempted to unlock the tablet <xliff:g id="number">%1$d</xliff:g> times.
+       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
+       the work profile will be removed, which will delete all profile data.
+    </string>
+    <!-- Message shown when user is almost at the limit of password attempts where the profile will be removed. [CHAR LIMIT=none] -->
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default">
+       You have incorrectly attempted to unlock the phone <xliff:g id="number">%1$d</xliff:g> times.
+       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
+       the work profile will be removed, which will delete all profile data.
+    </string>
+    <!-- Message shown in dialog when user has exceeded the maximum attempts and the profile will be removed. [CHAR LIMIT=none] -->
+    <string name="kg_failed_attempts_now_erasing_profile" product="tablet">
+       You have incorrectly attempted to unlock the tablet <xliff:g id="number">%d</xliff:g> times.
+       The work profile will be removed, which will delete all profile data.
+    </string>
+    <!-- Message shown in dialog when user has exceeded the maximum attempts and the profile will be removed. [CHAR LIMIT=none] -->
+    <string name="kg_failed_attempts_now_erasing_profile" product="default">
+       You have incorrectly attempted to unlock the phone <xliff:g id="number">%d</xliff:g> times.
+       The work profile will be removed, which will delete all profile data.
+    </string>
+
+    <!-- Message shown in dialog when user is almost at the limit where they will be
+    locked out and may have to enter an alternate username/password to unlock the phone -->
+    <string name="kg_failed_attempts_almost_at_login" product="tablet">
+       You have incorrectly drawn your unlock pattern <xliff:g id="number">%1$d</xliff:g> times.
+       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
+       you will be asked to unlock your tablet using an email account.\n\n
+       Try again in <xliff:g id="number">%3$d</xliff:g> seconds.
+    </string>
+    <!-- Message shown in dialog when user is almost at the limit where they will be
+    locked out and may have to enter an alternate username/password to unlock the phone -->
+    <string name="kg_failed_attempts_almost_at_login" product="default">
+       You have incorrectly drawn your unlock pattern <xliff:g id="number">%1$d</xliff:g> times.
+       After <xliff:g id="number">%2$d</xliff:g> more unsuccessful attempts,
+       you will be asked to unlock your phone using an email account.\n\n
+       Try again in <xliff:g id="number">%3$d</xliff:g> seconds.
+    </string>
+
+</resources>
diff --git a/packages/SystemUI/res/drawable-xhdpi/tv_card_gradient_protection.png b/packages/SystemUI/res/drawable-xhdpi/tv_card_gradient_protection.png
deleted file mode 100644
index 135dabb..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/tv_card_gradient_protection.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/circle_red.xml b/packages/SystemUI/res/drawable/circle_red.xml
deleted file mode 100644
index fd3c125..0000000
--- a/packages/SystemUI/res/drawable/circle_red.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2019 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-       android:shape="oval">
-    <solid android:color="@color/red"/>
-</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/privacy_chip_bg.xml b/packages/SystemUI/res/drawable/privacy_chip_bg.xml
deleted file mode 100644
index b7b21fa..0000000
--- a/packages/SystemUI/res/drawable/privacy_chip_bg.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     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.
--->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="#242424" /> <!-- 14% of white -->
-    <padding android:paddingTop="@dimen/ongoing_appops_chip_bg_padding"
-        android:paddingBottom="@dimen/ongoing_appops_chip_bg_padding" />
-    <corners android:radius="@dimen/ongoing_appops_chip_bg_corner_radius" />
-</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_bg_item_app_info.xml b/packages/SystemUI/res/drawable/tv_bg_item_app_info.xml
deleted file mode 100644
index 1bbb8c3..0000000
--- a/packages/SystemUI/res/drawable/tv_bg_item_app_info.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2019 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-       android:shape="rectangle">
-    <corners android:radius="24dp"/>
-    <solid android:color="@color/tv_audio_recording_bar_chip_background"/>
-</shape>
diff --git a/packages/SystemUI/res/drawable/tv_circle_dark.xml b/packages/SystemUI/res/drawable/tv_circle_dark.xml
new file mode 100644
index 0000000..d1ba8e7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_circle_dark.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+
+  <solid
+      android:color="@color/tv_audio_recording_indicator_background" />
+
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_circle_white_translucent.xml b/packages/SystemUI/res/drawable/tv_circle_white_translucent.xml
new file mode 100644
index 0000000..55d21de
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_circle_white_translucent.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+
+  <solid
+      android:color="@color/tv_audio_recording_indicator_pulse" />
+
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_gradient_protection.xml b/packages/SystemUI/res/drawable/tv_gradient_protection.xml
deleted file mode 100644
index ee5cbc7..0000000
--- a/packages/SystemUI/res/drawable/tv_gradient_protection.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2019 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<!-- gradient protection for cards -->
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-        android:src="@drawable/tv_card_gradient_protection"
-        android:tileMode="repeat"
-/>
diff --git a/packages/SystemUI/res/drawable/tv_ic_mic_white.xml b/packages/SystemUI/res/drawable/tv_ic_mic_white.xml
index 1bea8a1..d887113 100644
--- a/packages/SystemUI/res/drawable/tv_ic_mic_white.xml
+++ b/packages/SystemUI/res/drawable/tv_ic_mic_white.xml
@@ -1,25 +1,27 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2019 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
+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.
+-->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:viewportWidth="44"
-        android:viewportHeight="44"
-        android:width="44dp"
-        android:height="44dp">
-    <path
-        android:pathData="M22 25.6666667C25.0433333 25.6666667 27.4816667 23.21 27.4816667 20.1666667L27.5 9.16666667C27.5 6.12333333 25.0433333 3.66666667 22 3.66666667C18.9566667 3.66666667 16.5 6.12333333 16.5 9.16666667L16.5 20.1666667C16.5 23.21 18.9566667 25.6666667 22 25.6666667ZM31.7166667 20.1666667C31.7166667 25.6666667 27.06 29.5166667 22 29.5166667C16.94 29.5166667 12.2833333 25.6666667 12.2833333 20.1666667L9.16666667 20.1666667C9.16666667 26.4183333 14.1533333 31.5883333 20.1666667 32.4866667L20.1666667 38.5L23.8333333 38.5L23.8333333 32.4866667C29.8466667 31.6066667 34.8333333 26.4366667 34.8333333 20.1666667L31.7166667 20.1666667Z"
-        android:fillColor="@android:color/white" />
+    android:width="32dp"
+    android:height="32dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+  <path
+      android:fillColor="#FFFFFFFF"
+      android:pathData="M12,14c1.66,0 3,-1.34 3,-3V5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6C9,12.66 10.34,14 12,14zM11,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v6c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V5z"/>
+  <path
+      android:fillColor="#FFFFFFFF"
+      android:pathData="M17,11c0,2.76 -2.24,5 -5,5s-5,-2.24 -5,-5H5c0,3.53 2.61,6.43 6,6.92V21h2v-3.08c3.39,-0.49 6,-3.39 6,-6.92H17z"/>
 </vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_rect_dark_left_rounded.xml b/packages/SystemUI/res/drawable/tv_rect_dark_left_rounded.xml
new file mode 100644
index 0000000..9b48a70
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_rect_dark_left_rounded.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+
+  <corners
+      android:bottomLeftRadius="8dp"
+      android:topLeftRadius="8dp" />
+  <solid android:color="@color/tv_audio_recording_indicator_background" />
+
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_rect_dark_right_rounded.xml b/packages/SystemUI/res/drawable/tv_rect_dark_right_rounded.xml
new file mode 100644
index 0000000..0334875
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_rect_dark_right_rounded.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+
+  <corners
+      android:bottomRightRadius="8dp"
+      android:topRightRadius="8dp" />
+  <solid android:color="@color/tv_audio_recording_indicator_background" />
+
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_ring_white.xml b/packages/SystemUI/res/drawable/tv_ring_white.xml
new file mode 100644
index 0000000..0f7cc10
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_ring_white.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+
+  <stroke
+      android:width="1dp"
+      android:color="@android:color/white" />
+
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/bubble_menu_view.xml b/packages/SystemUI/res/layout/bubble_menu_view.xml
new file mode 100644
index 0000000..24608d3
--- /dev/null
+++ b/packages/SystemUI/res/layout/bubble_menu_view.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<com.android.systemui.bubbles.BubbleMenuView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    android:background="#66000000"
+    android:visibility="gone"
+    android:id="@+id/bubble_menu_container">
+
+    <FrameLayout
+        android:layout_height="@dimen/individual_bubble_size"
+        android:layout_width="wrap_content"
+        android:background="#FFFFFF"
+        android:id="@+id/bubble_menu_view">
+
+        <ImageView
+            android:id="@*android:id/icon"
+            android:layout_width="@dimen/global_actions_grid_item_icon_width"
+            android:layout_height="@dimen/global_actions_grid_item_icon_height"
+            android:layout_marginTop="@dimen/global_actions_grid_item_icon_top_margin"
+            android:layout_marginBottom="@dimen/global_actions_grid_item_icon_bottom_margin"
+            android:layout_marginLeft="@dimen/global_actions_grid_item_icon_side_margin"
+            android:layout_marginRight="@dimen/global_actions_grid_item_icon_side_margin"
+            android:scaleType="centerInside"
+            android:tint="@color/global_actions_text"
+        />
+    </FrameLayout>
+</com.android.systemui.bubbles.BubbleMenuView>
diff --git a/packages/SystemUI/res/layout/bubble_view.xml b/packages/SystemUI/res/layout/bubble_view.xml
index e2dea45..78f7cff 100644
--- a/packages/SystemUI/res/layout/bubble_view.xml
+++ b/packages/SystemUI/res/layout/bubble_view.xml
@@ -14,16 +14,8 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-<com.android.systemui.bubbles.BubbleView
+<com.android.systemui.bubbles.BadgedImageView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_height="wrap_content"
-    android:layout_width="wrap_content"
-    android:id="@+id/bubble_view">
-
-    <com.android.systemui.bubbles.BadgedImageView
-        android:id="@+id/bubble_image"
-        android:layout_width="@dimen/individual_bubble_size"
-        android:layout_height="@dimen/individual_bubble_size"
-        android:clipToPadding="false"/>
-
-</com.android.systemui.bubbles.BubbleView>
+    android:id="@+id/bubble_view"
+    android:layout_width="@dimen/individual_bubble_size"
+    android:layout_height="@dimen/individual_bubble_size"/>
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 1bfc4c0..b90a371 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -24,7 +24,25 @@
     android:outlineProvider="none"
     android:elevation="5dp" > <!-- Put it above the status bar header -->
 
-    <include layout="@layout/keyguard_indication_area_overlay" />
+    <LinearLayout
+        android:id="@+id/keyguard_indication_area"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="@dimen/keyguard_indication_margin_bottom"
+        android:layout_gravity="bottom|center_horizontal"
+        android:orientation="vertical">
+
+        <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
+            android:id="@+id/keyguard_indication_text"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:paddingStart="@dimen/keyguard_indication_text_padding"
+            android:paddingEnd="@dimen/keyguard_indication_text_padding"
+            android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
+            android:accessibilityLiveRegion="polite"/>
+
+    </LinearLayout>
 
     <FrameLayout
         android:id="@+id/preview_container"
diff --git a/packages/SystemUI/res/layout/keyguard_indication_area_overlay.xml b/packages/SystemUI/res/layout/keyguard_indication_area_overlay.xml
deleted file mode 100644
index cc30a68..0000000
--- a/packages/SystemUI/res/layout/keyguard_indication_area_overlay.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/keyguard_indication_area"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:layout_marginBottom="@dimen/keyguard_indication_margin_bottom"
-    android:layout_gravity="bottom|center_horizontal"
-    android:orientation="vertical">
-
-  <include layout="@layout/keyguard_indication_text_view" />
-
-</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyguard_indication_text_view.xml b/packages/SystemUI/res/layout/keyguard_indication_text_view.xml
deleted file mode 100644
index 9376b1f..0000000
--- a/packages/SystemUI/res/layout/keyguard_indication_text_view.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-    <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
-        android:id="@+id/keyguard_indication_text"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="center"
-        android:paddingStart="@dimen/keyguard_indication_text_padding"
-        android:paddingEnd="@dimen/keyguard_indication_text_padding"
-        android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
-        android:accessibilityLiveRegion="polite"/>
-</merge>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
deleted file mode 100644
index dce9ce1..0000000
--- a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     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.
--->
-
-
-<com.android.systemui.privacy.OngoingPrivacyChip
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/privacy_chip"
-    android:layout_height="match_parent"
-    android:layout_width="wrap_content"
-    android:layout_gravity="center_vertical|end"
-    android:gravity="center_vertical"
-    android:orientation="horizontal"
-    android:focusable="true" >
-
-        <FrameLayout
-            android:id="@+id/background"
-            android:layout_height="@dimen/ongoing_appops_chip_height"
-            android:minWidth="48dp"
-            android:layout_width="wrap_content" >
-                <LinearLayout
-                    android:id="@+id/icons_container"
-                    android:layout_height="match_parent"
-                    android:layout_width="wrap_content"
-                    android:gravity="center_vertical"
-                    />
-          </FrameLayout>
-</com.android.systemui.privacy.OngoingPrivacyChip>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/ongoing_privacy_text_item.xml b/packages/SystemUI/res/layout/ongoing_privacy_text_item.xml
deleted file mode 100644
index 5595b13..0000000
--- a/packages/SystemUI/res/layout/ongoing_privacy_text_item.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     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.
--->
-
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:textDirection="locale"
-    android:textAppearance="@style/TextAppearance.QS.DetailItemPrimary"
-/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_customize_panel_content.xml b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
index 09f512f..7cce1ba 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel_content.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
@@ -52,7 +52,7 @@
             android:scrollIndicators="top"
             android:scrollbars="vertical"
             android:scrollbarStyle="outsideOverlay"
-            android:importantForAccessibility="no" />
+            android:importantForAccessibility="auto" />
     </com.android.keyguard.AlphaOptimizedLinearLayout>
 
     <View
diff --git a/packages/SystemUI/res/layout/qs_detail_header.xml b/packages/SystemUI/res/layout/qs_detail_header.xml
index a1f0ee7..da80633 100644
--- a/packages/SystemUI/res/layout/qs_detail_header.xml
+++ b/packages/SystemUI/res/layout/qs_detail_header.xml
@@ -53,12 +53,12 @@
             android:src="@drawable/ic_settings"
             android:visibility="gone"/>
 
-        <Switch
-            android:id="@android:id/toggle"
+        <ViewStub
+            android:id="@+id/toggle_stub"
+            android:inflatedId="@+id/toggle"
+            android:layout="@layout/qs_detail_switch"
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:clickable="false"
-            android:textAppearance="@style/TextAppearance.QS.DetailHeader" />
+            android:layout_height="wrap_content"/>
 
     </LinearLayout>
 
diff --git a/packages/SystemUI/res/layout/qs_detail_switch.xml b/packages/SystemUI/res/layout/qs_detail_switch.xml
new file mode 100644
index 0000000..abb2497
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_detail_switch.xml
@@ -0,0 +1,23 @@
+<!--
+  ~ 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.
+  -->
+
+<Switch
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/toggle"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:clickable="false"
+    android:textAppearance="@style/TextAppearance.QS.DetailHeader" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_media_panel_options.xml b/packages/SystemUI/res/layout/qs_media_panel_options.xml
new file mode 100644
index 0000000..0669357
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_media_panel_options.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/qs_media_controls_options"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="horizontal"
+    android:gravity="center"
+    android:layout_gravity="center"
+    android:padding="10dp"
+    >
+    <ImageButton
+        android:id="@+id/remove"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:src="@android:drawable/ic_menu_delete"
+        android:padding="8dp"
+    />
+    <ImageButton
+        android:id="@+id/cancel"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:src="@android:drawable/ic_menu_revert"
+        android:padding="8dp"
+    />
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
index cd9f780..8676767 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
@@ -14,7 +14,7 @@
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 -->
-<LinearLayout
+<FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:id="@+id/quick_status_bar_system_icons"
@@ -28,13 +28,6 @@
     android:paddingStart="@dimen/status_bar_padding_start"
     android:paddingEnd="@dimen/status_bar_padding_end" >
 
-    <LinearLayout
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="1"
-        android:orientation="horizontal"
-        android:gravity="center_vertical|start" >
-
     <com.android.systemui.statusbar.policy.Clock
         android:id="@+id/clock"
         android:layout_width="wrap_content"
@@ -46,23 +39,5 @@
         android:singleLine="true"
         android:textAppearance="@style/TextAppearance.StatusBar.Clock"
         systemui:showDark="false" />
-    </LinearLayout>
 
-    <android.widget.Space
-        android:id="@+id/space"
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_gravity="center_vertical|center_horizontal"
-        android:visibility="gone" />
-
-    <LinearLayout
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="1"
-        android:orientation="horizontal"
-        android:gravity="center_vertical|end" >
-
-    <include layout="@layout/ongoing_privacy_chip" />
-
-    </LinearLayout>
-</LinearLayout>
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml b/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml
new file mode 100644
index 0000000..f04226e
--- /dev/null
+++ b/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:orientation="horizontal"
+              android:padding="32dp">
+
+    <FrameLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+
+        <LinearLayout
+            android:id="@+id/icon_texts_container"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal">
+
+            <FrameLayout
+                android:layout_width="90dp"
+                android:layout_height="94dp">
+
+                <View
+                    android:id="@+id/icon_container_bg"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:background="@drawable/tv_rect_dark_left_rounded"/>
+
+                <FrameLayout
+                    android:id="@+id/icon_mic"
+                    android:layout_width="70dp"
+                    android:layout_height="70dp"
+                    android:layout_marginLeft="12dp"
+                    android:layout_marginTop="12dp"
+                    android:layout_marginRight="8dp"
+                    android:layout_marginBottom="12dp">
+
+                    <View
+                        android:layout_width="54dp"
+                        android:layout_height="54dp"
+                        android:layout_gravity="center"
+                        android:background="@drawable/tv_circle_dark"/>
+
+                    <ImageView
+                        android:id="@+id/pulsating_circle"
+                        android:layout_width="54dp"
+                        android:layout_height="54dp"
+                        android:layout_gravity="center"
+                        android:background="@drawable/tv_circle_white_translucent"/>
+
+                    <ImageView
+                        android:layout_width="54dp"
+                        android:layout_height="54dp"
+                        android:layout_gravity="center"
+                        android:src="@drawable/tv_ring_white"/>
+
+                    <ImageView
+                        android:layout_width="32dp"
+                        android:layout_height="32dp"
+                        android:layout_gravity="center"
+                        android:background="@drawable/tv_ic_mic_white"/>
+                </FrameLayout>
+
+            </FrameLayout>
+
+            <LinearLayout
+                android:id="@+id/texts_container"
+                android:layout_width="wrap_content"
+                android:layout_height="94dp"
+                android:background="@color/tv_audio_recording_indicator_background"
+                android:gravity="center_vertical"
+                android:orientation="vertical"
+                android:visibility="visible">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/mic_active"
+                    android:textColor="@android:color/white"
+                    android:fontFamily="sans-serif"
+                    android:textSize="20dp"/>
+
+                <TextView
+                    android:id="@+id/text"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:singleLine="true"
+                    android:text="SomeApplication accessed your microphone"
+                    android:textColor="@android:color/white"
+                    android:fontFamily="sans-serif"
+                    android:textSize="16dp"/>
+
+            </LinearLayout>
+
+        </LinearLayout>
+
+    </FrameLayout>
+
+    <View
+        android:id="@+id/bg_right"
+        android:layout_width="24dp"
+        android:layout_height="94dp"
+        android:background="@drawable/tv_rect_dark_right_rounded"
+        android:visibility="visible"/>
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/tv_item_app_info.xml b/packages/SystemUI/res/layout/tv_item_app_info.xml
deleted file mode 100644
index b40589e..0000000
--- a/packages/SystemUI/res/layout/tv_item_app_info.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2019 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:orientation="horizontal"
-              android:layout_width="wrap_content"
-              android:layout_height="48dp"
-              android:layout_marginLeft="8dp"
-              android:paddingHorizontal="12dp"
-              android:gravity="center_vertical"
-              android:background="@drawable/tv_bg_item_app_info">
-
-    <ImageView
-        android:id="@+id/icon"
-        android:layout_width="24dp"
-        android:layout_height="24dp"
-        android:layout_marginRight="8dp"/>
-
-    <TextView
-        android:id="@+id/title"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:textColor="@color/tv_audio_recording_bar_text"
-        android:fontFamily="sans-serif"
-        android:textSize="14sp"/>
-
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/tv_status_bar_audio_recording.xml b/packages/SystemUI/res/layout/tv_status_bar_audio_recording.xml
deleted file mode 100644
index b9dffbb..0000000
--- a/packages/SystemUI/res/layout/tv_status_bar_audio_recording.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2019 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="wrap_content"
-              android:layout_gravity="bottom"
-              android:orientation="vertical">
-
-    <!-- Gradient Protector -->
-    <View
-        android:layout_width="match_parent"
-        android:layout_height="102.5dp"
-        android:background="@drawable/tv_gradient_protection"/>
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="72dp"
-        android:background="@color/tv_audio_recording_bar_background"
-        android:gravity="center_vertical"
-        android:orientation="horizontal">
-
-        <ImageView
-            android:layout_width="48dp"
-            android:layout_height="48dp"
-            android:layout_marginLeft="42dp"
-            android:layout_marginVertical="12dp"
-            android:padding="8dp"
-            android:background="@drawable/circle_red"
-            android:scaleType="centerInside"
-            android:src="@drawable/tv_ic_mic_white"/>
-
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="24dp"
-            android:text="Audio recording by"
-            android:textColor="@color/tv_audio_recording_bar_text"
-            android:fontFamily="sans-serif"
-            android:textSize="14sp"/>
-
-        <LinearLayout
-            android:id="@+id/container"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"/>
-
-    </LinearLayout>
-
-</LinearLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index ef2d061..8f64aab 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Stelselnavigasie is opgedateer. Gaan na Instellings toe om veranderinge te maak."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gaan na Instellings toe om stelselnavigasie op te dateer"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Bystandmodus"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Die Android TV-toestel gaan binnekort afskakel; druk \'n knoppie om dit aan te hou."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Die toestel gaan binnekort afskakel; druk om dit aan te hou."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index d39f399..d73c0ed 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"የስርዓት ዳሰሳ ተዘምኗል። ለውጦችን ለማድረግ ወደ ቅንብሮች ይሂዱ።"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"የስርዓት ዳሰሳን ለማዘመን ወደ ቅንብሮች ይሂዱ"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ተጠባባቂ"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"የAndroid TV መሣሪያው በቅርቡ ይጠፋል፣ እንደበራ ለማቆየት ይጫኑ።"</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"መሣሪያው በቅርቡ ይጠፋል፤ እንደበራ ለማቆየት ይጫኑ።"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 3fe4684..68fe91c 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -978,6 +978,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"تم تحديث التنقل داخل النظام. لإجراء التغييرات، يُرجى الانتقال إلى \"الإعدادات\"."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"الانتقال إلى \"الإعدادات\" لتعديل التنقل داخل النظام"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"وضع الاستعداد"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"‏سيتم إيقاف جهاز Android TV قريبًا، اضغط على أحد الأزرار لمواصلة تشغيله."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"سيتم إيقاف الجهاز قريبًا، اضغط لمواصلة تشغيله."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index c711b4d..b55f419 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -960,6 +960,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ছিষ্টেম নেভিগেশ্বন আপডে’ট কৰা হ’ল। সলনি কৰিবলৈ ছেটিংসমূহ-লৈ যাওক।"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ছিষ্টেম নেভিগেশ্বন আপডে’ট কৰিবলৈ ছেটিংসমূহ-লৈ যাওক"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ষ্টেণ্ডবাই"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ডিভাইচটো অতি সোনকালে অফ হ\'ব, এইটো অন ৰাখিবলৈ যিকোনো এটা বুটাম টিপক।"</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"এই ডিভাইচটো অতি সোনকালে অফ হ\'ব, এইটো অন ৰাখিবলৈ টিপক।"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index c90b67c..95da981 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Sistem naviqasiyası yeniləndi. Dəyişiklik etmək üçün Ayarlara daxil olun."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Sistem naviqasiyasını yeniləmək üçün Ayarlara keçin"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Gözləmə rejimi"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV cihazı tezliklə sönəcək; aktiv saxlamaq üçün düyməyə basın."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Cihaz tezliklə sönəcək; aktiv saxlamaq üçün basın."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index f0f72b5..7b909cf 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -963,6 +963,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigacija sistema je ažurirana. Da biste uneli izmene, idite u Podešavanja."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Idite u Podešavanja da biste ažurirali navigaciju sistema"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje pripravnosti"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV će se uskoro isključiti. Pritisnite dugme da bi ostao uključen."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Uređaj će se uskoro isključiti. Pritisnite da bi ostao uključen."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index ee82d76..412fcb7 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -970,6 +970,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Навігацыя ў сістэме абноўлена. Каб унесці змяненні, перайдзіце ў Налады."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Перайдзіце ў Налады, каб абнавіць параметры навігацыі ў сістэме"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Рэжым чакання"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Прылада Android TV неўзабаве выключыцца. Каб пакінуць яе ўключанай, націсніце кнопку."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Прылада неўзабаве выключыцца. Націсніце, каб пакінуць яе ўключанай."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index b624dce..e9bf3c7 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Режимът за навигиране в системата е актуализиран. За да извършите промени, отворете настройките."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Отворете настройките, за да актуализирате режима за навигиране в системата"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Режим на готовност"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Устройството с Android TV скоро ще се изключи. Натиснете бутон, за да остане включено."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Устройството скоро ще се изключи. Натиснете, за да остане включено."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 9dcdc59..60b23d7 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -960,6 +960,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"সিস্টেম নেভিগেশন আপডেট হয়েছে। পরিবর্তন করার জন্য সেটিংসে যান।"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"সিস্টেম নেভিগেশন আপডেট করতে সেটিংসে যান"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"স্ট্যান্ডবাই"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ডিভাইস শীঘ্রই বন্ধ হয়ে যাবে, চালু রাখতে বোতাম প্রেস করুন।"</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ডিভাইস শীঘ্রই বন্ধ হয়ে যাবে, চালু রাখতে প্রেস করুন।"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 7774ed6..40f2d7c 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -965,6 +965,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigiranje sistemom je ažurirano. Da izvršite promjene, idite u Postavke."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Idite u Postavke da ažurirate navigiranje sistemom"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje mirovanja"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV uređaj će se uskoro isključiti. Pritisnite dugme da ostane uključen."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Uređaj će se uskoro isključiti. Pritisnite da ostane uključen."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 589eeed..8e64a2e 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"S\'ha actualitzat el sistema de navegació. Per fer canvis, ves a Configuració."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ves a Configuració per actualitzar el sistema de navegació"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"El dispositiu Android TV s\'apagarà aviat; prem un botó per mantenir-lo encès."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"El dispositiu s\'apagarà aviat; prem per mantenir-lo encès."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index dcefc84..2843bcd 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -968,6 +968,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systémová navigace byla aktualizována. Chcete-li provést změny, přejděte do Nastavení."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Přejděte do Nastavení a aktualizujte systémovou navigaci"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Pohotovostní režim"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Zařízení Android TV se brzy vypne, stisknutím tlačítka ho ponecháte zapnuté."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Zařízení se brzy vypne, stisknutím ho ponecháte zapnuté."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index ba38784..da62c70 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systemnavigationen blev opdateret. Gå til Indstillinger for at foretage ændringer."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gå til Indstillinger for at opdatere systemnavigationen"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV-enheden slukker snart. Tryk på en knap for at holde den tændt."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Enheden slukker snart. Tryk for at holde den tændt."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 70b4f08..7e54703 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -962,6 +962,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systemsteuerungseinstellungen wurden angepasst. Änderungen kannst du in den Einstellungen vornehmen."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gehe zu den Einstellungen, um die Systemsteuerung anzupassen"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Das Android TV-Gerät wird demnächst abgeschaltet. Drücke eine Taste, damit es eingeschaltet bleibt."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Das Gerät wird demnächst abgeschaltet. Drücke beispielsweise eine Taste oder berühre den Bildschirm, damit es eingeschaltet bleibt."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 3c7105b..ab7f1e5 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Η πλοήγηση συστήματος ενημερώθηκε. Για να κάνετε αλλαγές, μεταβείτε στις Ρυθμίσεις."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Μεταβείτε στις Ρυθμίσεις για να ενημερώσετε την πλοήγηση συστήματος"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Κατάσταση αναμονής"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Η συσκευή Android TV σύντομα θα απενεργοποιηθεί. Πατήστε ένα κουμπί για να την κρατήσετε ενεργοποιημένη."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Η συσκευή σύντομα θα απενεργοποιηθεί. Πατήστε για να την κρατήσετε ενεργοποιημένη."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index e6a7d6c..35d4b4f 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"System navigation updated. To make changes, go to Settings."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Go to Settings to update system navigation"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"The Android TV device will soon turn off; press a button to keep it on."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"The device will soon turn off; press to keep it on."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 858de04..9ac53cd 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"System navigation updated. To make changes, go to Settings."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Go to Settings to update system navigation"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"The Android TV device will soon turn off; press a button to keep it on."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"The device will soon turn off; press to keep it on."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index e6a7d6c..35d4b4f 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"System navigation updated. To make changes, go to Settings."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Go to Settings to update system navigation"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"The Android TV device will soon turn off; press a button to keep it on."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"The device will soon turn off; press to keep it on."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index e6a7d6c..35d4b4f 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"System navigation updated. To make changes, go to Settings."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Go to Settings to update system navigation"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"The Android TV device will soon turn off; press a button to keep it on."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"The device will soon turn off; press to keep it on."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index a6abc8c..f7c937b 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -953,6 +953,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‏‏‏‎‎‎‎‏‎‏‏‏‏‏‎‎‎‏‏‎‎‏‏‏‏‎‏‏‏‎‏‏‎‎‎‎‎‏‎‎‎‎‏‏‎‏‎‎‎‎‎‎‎‎‎System navigation updated. To make changes, go to Settings.‎‏‎‎‏‎"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‏‎‏‎‎‎‏‏‏‏‏‎‎‎‏‎‏‏‎‎‎‎‎Go to Settings to update system navigation‎‏‎‎‏‎"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‎‎‎‎‎‏‏‏‎‏‏‎‏‏‏‎‏‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‏‎‏‎‎‏‏‎‏‏‏‎‎‏‎‏‎Standby‎‏‎‎‏‎"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‎‎‎‏‎‏‎‎‎‏‎‏‎‎‎‏‏‎‎‎‎‎‎‏‎‎‎‏‎‎‎‎‏‏‏‏‎‎‎‎‎‎‏‏‏‎‎‎‎‎‎‏‎‎The Android TV device will soon turn off; press a button to keep it on.‎‏‎‎‏‎"</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‎‏‎‏‎‏‏‏‎‏‏‎‏‏‏‏‎‏‎‏‎‎‏‎‎‏‎‎‎‎‏‎‎‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎‏‏‎‏‏‎The device will soon turn off; press to keep it on.‎‏‎‎‏‎"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index db6ccb7..1787643 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Se actualizó el sistema de navegación. Para hacer cambios, ve a Configuración."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ve a Configuración para actualizar la navegación del sistema"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Pronto se apagará el dispositivo Android TV; presiona un botón para mantenerlo encendido."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Pronto se apagará el dispositivo; presiona para mantenerlo encendido."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index ef52829..9a9f051 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Se ha actualizado la navegación del sistema. Para hacer cambios, ve a Ajustes."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ve a Ajustes para actualizar la navegación del sistema"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"El dispositivo Android TV pronto se apagará; pulsa un botón para evitarlo."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"El dispositivo pronto se apagará si no interactúas con él."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 57eed43..31bffa34 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Süsteemis navigeerimine on värskendatud. Muutmiseks avage jaotis Seaded."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Süsteemi navigeerimise värskendamiseks avage jaotis Seaded"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Ooterežiim"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV seade lülitub varsti välja; selle aktiivsena hoidmiseks vajutage nuppu."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Seade lülitub värsti välja; selle aktiivsena hoidmiseks vajutage nuppu."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 9ffe463..fa24388 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Eguneratu da sistemaren nabigazioa. Aldaketak egiteko, joan Ezarpenak atalera."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Sistemaren nabigazioa eguneratzeko, joan Ezarpenak atalera"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Egonean"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV gailua laster itzaliko da; sakatu botoi bat piztuta mantentzeko."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Gailua laster itzaliko da; sakatu piztuta mantentzeko."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index ea56748..4ce5b27 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"پیمایش سیستم به‌روزرسانی شد. برای انجام تغییرات به «تنظیمات» بروید."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"برای به‌روزرسانی پیمایش سیستم، به «تنظیمات» بروید"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"آماده‌به‌کار"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"‏دستگاه Android TV به‌زودی خاموش می‌شود، برای روشن نگه‌داشتن آن، دکمه‌ای را فشار دهید."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"دستگاه به‌زودی خاموش می‌شود، برای روشن نگه‌داشتن آن فشار دهید."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 32f2eec..8912db8 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Järjestelmän navigointitapa vaihdettu. Voit muuttaa sitä asetuksista."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Vaihda järjestelmän navigointitapaa asetuksista"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Virransäästötila"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ‑laite sammuu pian. Pidä se päällä painamalla painiketta."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Laite sammuu pian. Pidä se päällä painamalla jotakin."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index a144ddd..2bf724c 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"La navigation système a été mise à jour. Pour apporter des modifications, accédez au menu Paramètres."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Accédez au menu Paramètres pour mettre à jour la navigation système"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Veille"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"L\'appareil Android TV va bientôt s\'éteindre. Appuyez sur un bouton pour le laisser allumé."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"L\'appareil va bientôt s\'éteindre. Interagissez avec lui pour le laisser allumé."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index b126413..d2614de 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigation système mise à jour. Pour apporter des modifications, accédez aux paramètres."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Accédez aux paramètres pour mettre à jour la navigation système"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Mode Veille imminent"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"L\'appareil Android TV va bientôt passer en mode Veille. Appuyez sur un bouton pour qu\'il reste allumé."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"L\'appareil va bientôt passer en mode Veille. Appuyez dessus pour qu\'il reste allumé."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 88bfa05..a7a5726 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Actualizouse a navegación do sistema. Para facer cambios, vai a Configuración."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Para actualizar a navegación do sistema, vai a Configuración"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Modo de espera"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Pronto se apagará o dispositivo Android TV. Preme un botón para mantelo acendido."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Pronto se apagará o dispositivo. Tócao para mantelo acendido."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 6f46b84..69c50e1 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -960,6 +960,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"સિસ્ટમ નૅવિગેશન અપડેટ કર્યું. ફેરફારો કરવા માટે, સેટિંગ પર જાઓ."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"સિસ્ટમ નૅવિગેશનને અપડેટ કરવા માટે સેટિંગ પર જાઓ"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"સ્ટૅન્ડબાય"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android ટીવી ડિવાઇસ ટૂંક સમયમાં બંધ થશે; તેને ચાલુ રાખવા માટે બટન દબાવો."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ડિવાઇસ ટૂંક સમયમાં બંધ થશે; તેને ચાલુ રાખવા માટે દબાવો."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 1a5ce8e..3fc7870 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"सिस्टम नेविगेशन अपडेट हो गया. बदलाव करने के लिए \'सेटिंग\' पर जाएं."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"सिस्टम नेविगेशन अपडेट करने के लिए \'सेटिंग\' में जाएं"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्टैंडबाई"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV डिवाइस जल्द ही बंद हो जाएगा. इसे चालू रखने के लिए किसी बटन को दबाएं."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"डिवाइस जल्द ही बंद हो जाएगा. इसे चालू रखने के लिए स्क्रीन पर टैप करें या किसी बटन को दबाएं."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index e270f0f..f19bdf5 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -963,6 +963,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Ažurirana je navigacija sustavom. Možete je promijeniti u Postavkama."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Navigaciju sustavom možete ažurirati u Postavkama"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje mirovanja"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Uređaj Android TV uskoro će se isključiti. Pritisnite gumb da bi ostao uključen."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Uređaj će se uskoro isključiti. Pritisnite da bi ostao uključen."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 5ff99c9..8624670 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"A rendszer-navigáció módja megváltozott. Módosításához nyissa meg a Beállításokat."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"A rendszer-navigációs lehetőségeket a Beállításokban módosíthatja"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Készenléti mód"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Az Android TV eszköz hamarosan kikapcsol. Nyomja meg valamelyik gombot, hogy bekapcsolva tarthassa."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Az eszköz hamarosan kikapcsol. Nyomja meg, hogy bekapcsolva tarthassa."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index cf5ba2e..c02199e 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Համակարգի նավիգացիան թարմացվեց: Փոփոխություններ անելու համար անցեք կարգավորումներ:"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Թարմացրեք համակարգի նավիգացիան կարգավորումներում"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Սպասման ռեժիմ"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV սարքը շուտով կանջատվի: Սեղմեք որևէ կոճակ՝ միացրած թողնելու համար:"</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Սարքը շուտով կանջատվի: Սեղմեք՝ միացրած թողնելու համար:"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index bb62498..99fa845 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigasi sistem diupdate. Untuk melakukan perubahan, buka Setelan."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Buka Setelan untuk mengupdate navigasi sistem"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Siaga"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Perangkat Android TV akan segera dinonaktifkan; tekan tombol untuk terus menyalakannya."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Perangkat akan segera dinonaktifkan, tekan untuk terus menyalakannya."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index d0deac3..cd23616 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Kerfisstjórnun uppfærð. Þú getur breytt þessu í stillingunum."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Farðu í stillingar til að uppfæra kerfisstjórnun"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Biðstaða"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV tækið slekkur á sér fljótlega. Ýttu á takka til að það slokkni ekki á því."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Tækið slekkur á sér fljótlega. Ýttu á takka til að það slokkni ekki á því."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 6e370ac..9429c04 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigazione del sistema aggiornata. Per apportare modifiche, usa le Impostazioni."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Usa le Impostazioni per aggiornare la navigazione del sistema"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"A breve il dispositivo Android TV si spegnerà. Premi un pulsante per tenerlo acceso."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"A breve il dispositivo si spegnerà. Premi per tenerlo acceso."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index de0ebab..b2da88a 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -968,6 +968,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"הניווט במערכת עודכן. אפשר לערוך שינויים דרך ההגדרות."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"יש לעבור להגדרות כדי לעדכן את הניווט במערכת"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"המתנה"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"‏מכשיר Android TV ייכבה בקרוב. יש ללחוץ על לחצן כלשהו כדי שהוא ימשיך לפעול."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"המכשיר ייכבה בקרוב, יש ללחוץ כדי שהוא ימשיך לפעול."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 4703f5e..94dce86 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"システム ナビゲーションを更新しました。変更するには [設定] に移動してください。"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"システム ナビゲーションを更新するには [設定] に移動してください"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"スタンバイ"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV デバイスはまもなく OFF になります。ON 状態を維持するには、ボタンを押してください。"</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"このデバイスはまもなく OFF になります。ON 状態を維持するには、ボタンを押してください。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 30c34ba..d1e37a4 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"სისტემური ნავიგაცია განახლდა. ცვლილებების შესატანად გადადით პარამეტრებზე."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"სისტემური ნავიგაციის გასაახლებლად გადადით პარამეტრებზე"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"მოლოდინის რეჟიმი"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV მოწყობილობა მალე გამოირთვება, დააჭირეთ ღილაკს, რომ ჩართული დარჩეს."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"მოწყობილობა მალე გამოირთვება, დააჭირეთ, რომ ჩართული დარჩეს."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index cb4b393..c77a075 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Жүйе навигациясы жаңартылды. Өзгерту енгізу үшін \"Параметрлер\" бөліміне өтіңіз."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Жүйе навигациясын жаңарту үшін \"Параметрлер\" бөліміне өтіңіз."</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Күту режимі"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV құрылғысы жақын арада өшеді. Оны қосулы қалдыру үшін басыңыз."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Құрылғы жақын арада өшеді. Оны қосулы қалдыру үшін басыңыз."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 0d9337b..0cb6910 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"បានធ្វើ​បច្ចុប្បន្នភាព​ការរុករកក្នុង​ប្រព័ន្ធ។ ដើម្បីធ្វើការផ្លាស់ប្ដូរ សូមចូលទៅ​កាន់ការកំណត់។"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ចូល​ទៅកាន់​ការកំណត់ ដើម្បី​ធ្វើបច្ចុប្បន្នភាព​ការរុករក​ក្នុង​ប្រព័ន្ធ"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ផ្អាក​ដំណើរការ"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"ឧបករណ៍ Android TV នឹង​បិទ​ក្នុងពេល​ឆាប់ៗនេះ សូមចុច​ប៊ូតុង​ដើម្បី​បន្ត​បើក​ឧបករណ៍។"</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ឧបករណ៍​នឹង​បិទ​ក្នុងពេល​ឆាប់ៗនេះ សូមចុច​ដើម្បី​បន្ត​បើក​ឧបករណ៍។"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 3fbe942..c736240 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ಸಿಸ್ಟಂ ನ್ಯಾವಿಗೇಷನ ಅಪ್‌ಡೇಟ್ ಮಾಡಲಾಗಿದೆ ಬದಲಾವಣೆಗಳನ್ನು ಮಾಡಲು, ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಗೆ ಹೋಗಿ."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ಸಿಸ್ಟಂ ನ್ಯಾವಿಗೇಷನ್ ಅಪ್‌ಡೇಟ್ ಮಾಡಲು ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಗೆ ಹೋಗಿ"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ಸ್ಟ್ಯಾಂಡ್‌ಬೈ"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"ಈ Android TV ಸಾಧನವು ಶೀಘ್ರವೇ ಆಫ್ ಆಗುತ್ತದೆ; ಇದನ್ನು ಆನ್‌ನಲ್ಲಿಡಲು ಬಟನ್ ಅನ್ನು ಒತ್ತಿರಿ."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ಈ ಸಾಧನವು ಶೀಘ್ರವೇ ಆಫ್ ಆಗುತ್ತದೆ; ಇದನ್ನು ಆನ್‌ನಲ್ಲಿಡಲು ಒತ್ತಿರಿ."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 7923c6f..a60f736 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"시스템 탐색이 업데이트되었습니다. 변경하려면 설정으로 이동하세요."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"설정으로 이동하여 시스템 탐색을 업데이트하세요."</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"대기"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV가 곧 꺼집니다. 계속 켜 두려면 버튼을 누르세요."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"기기가 곧 꺼집니다. 계속 켜 두려면 누르세요."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index ba029f1..80aa6a1 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Тутум чабыттоосу жаңыртылды. Өзгөртүү үчүн, Жөндөөлөргө өтүңүз."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Тутум чабыттоосун жаңыртуу үчүн Жөндөөлөргө өтүңүз"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Көшүү режими"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV түзмөгү жакында өчүрүлөт, аны күйүк боюнча калтыруу үчүн баскычты басыңыз."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Түзмөк жакында өчүрүлөт, күйүк боюнча калтыруу үчүн басып коюңуз."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 4376cc5..8b3be64 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ອັບເດດການນຳທາງລະບົບແລ້ວ. ເພື່ອປ່ຽນແປງ, ກະລຸນາໄປທີ່ການຕັ້ງຄ່າ."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ໄປທີ່ການຕັ້ງຄ່າເພື່ອອັບເດດການນຳທາງລະບົບ"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ສະແຕນບາຍ"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"ອຸປະກອນ Android TV ຈະປິດໃນອີກບໍ່ດົນ, ກົດປຸ່ມໃດໜຶ່ງເພື່ອເປີດມັນໄວ້ຕໍ່."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ອຸປະກອນຈະປິດໃນອີກບໍ່ດົນ, ກົດເພື່ອເປີດມັນໄວ້ຕໍ່."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 2534a3b..c7282cd 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -968,6 +968,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Sistemos naršymo funkcijos atnaujintos. Jei norite pakeisti, eikite į skiltį „Nustatymai“."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Eikite į skiltį „Nustatymai“, kad atnaujintumėte sistemos naršymo funkcijas"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Budėjimo laikas"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"„Android TV“ įrenginys netrukus išsijungs. Paspauskite mygtuką, kad jis liktų įjungtas."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Įrenginys netrukus išsijungs. Paspauskite, kad jis liktų įjungtas."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 9604dc2..e99462b 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -963,6 +963,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Sistēmas navigācija ir atjaunināta. Lai veiktu izmaiņas, atveriet iestatījumus."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Atveriet iestatījumus, lai atjauninātu sistēmas navigāciju"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Gaidstāve"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ierīce drīz izslēgsies. Nospiediet pogu, lai tā paliktu ieslēgta."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Ierīce drīz izslēgsies. Nospiediet, lai tā paliktu ieslēgta."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index f9c5c4a..a607f75 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Навигацијата на системот е ажурирана. За да извршите промени, одете во „Поставки“."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Одете во „Поставки“ за да ја ажурирате навигацијата на системот"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Подготвеност"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Уредот со Android TV наскоро ќе се исклучи, притиснете копче за да остане вклучен."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Уредот наскоро ќе се исклучи, притиснете за да остане вклучен."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index fd3f16c..53ce5ab 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -960,6 +960,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"സിസ്‌റ്റം നാവിഗേഷൻ അപ്‌ഡേറ്റ് ചെയ്‌തു. മാറ്റങ്ങൾ വരുത്താൻ ക്രമീകരണത്തിലേക്ക് പോവുക."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"സിസ്‌റ്റം നാവിഗേഷൻ അപ്‌ഡേറ്റ് ചെയ്യാൻ ക്രമീകരണത്തിലേക്ക് പോവുക"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"സ്‌റ്റാൻഡ്‌ബൈ"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android ടിവി ഉടൻ ഓഫാകും, ഓണാക്കി നിർത്താൻ ഒരു ബട്ടൺ അമർത്തുക."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ഉപകരണം ഉടൻ ഓഫാകും, ഓണാക്കി നിർത്താൻ അമർത്തുക."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 0939c72..75af9cd 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Системийн навигацыг шинэчиллээ. Өөрчлөхийн тулд Тохиргоо руу очно уу."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Системийн навигацыг шинэчлэхийн тулд Тохиргоо руу очно уу"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Зогсолтын горим"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Андройд ТВ төхөөрөмж удахгүй унтрах тул асаалттай хэвээр байлгахын тулд товчлуур дээр дарна уу."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Төхөөрөмж удахгүй унтрах тул асаалттай хэвээр байлгахын тулд дарна уу."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 5326e37..089df33 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"सिस्टम नेव्हिगेशन अपडेट केले. बदल करण्यासाठी, सेटिंग्जवर जा."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"सिस्टम नेव्हिगेशन अपडेट करण्यासाठी सेटिंग्जवर जा"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्टँडबाय"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV डिव्हाइस लवकरच बंद होणार आहे; सुरू ठेवण्यासाठी बटण दाबा."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"डिव्हाइस लवकरच बंद होणार आहे; सुरू ठेवण्यासाठी स्क्रीनवर किंवा बटण दाबा."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 25d73c0..3073c9f 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigasi sistem dikemas kini. Untuk membuat perubahan, pergi ke Tetapan."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Pergi ke Tetapan untuk mengemas kini navigasi sistem"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Tunggu sedia"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Peranti Android TV akan mati tidak lama lagi; tekan butang untuk memastikan peranti terus hidup."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Peranti akan mati tidak lama lagi; tekan untuk memastikan peranti terus hidup."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index beca4c4..9fcb86e 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"စနစ်လမ်းညွှန်ခြင်း အပ်ဒိတ်လုပ်ပြီးပါပြီ။ အပြောင်းအလဲများ ပြုလုပ်ရန် \'ဆက်တင်များ\' သို့သွားပါ။"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"စနစ်လမ်းညွှန်ခြင်း အပ်ဒိတ်လုပ်ရန် \'ဆက်တင်များ\' သို့သွားပါ"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"အသင့်အနေအထား"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV စက်သည် မကြာမီ ပိတ်သွားပါမည်၊ ဆက်ဖွင့်ထားရန် ခလုတ်တစ်ခုနှိပ်ပါ။"</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"စက်သည် မကြာမီ ပိတ်သွားပါမည်၊ ဆက်ဖွင့်ထားပါ။"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index a07451d..9a9854b 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systemnavigeringen er oppdatert. For å gjøre endringer, gå til Innstillinger."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gå til Innstillinger for å oppdatere systemnavigeringen"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Ventemodus"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV-enheten slås snart av. Trykk på en knapp for å holde den på."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Enheten slås snart av. Trykk for å holde den på."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 39e612a..fa1fa56 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"प्रणालीको नेभिगेसन अद्यावधिक गरियो। परिवर्तन गर्न सेटिङमा जानुहोस्।"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"प्रणालीको नेभिगेसन अद्यावधिक गर्न सेटिङमा जानुहोस्"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्ट्यान्डबाई"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV यन्त्र चाँडै निष्क्रिय हुने छ; सक्रिय राख्न कुनै बटन थिच्नुहोस्।"</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"यो यन्त्र चाँडै निष्क्रिय हुने छ; सक्रिय राख्न थिच्नुहोस्।"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index a1b7c29..9aa9f1e 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systeemnavigatie geüpdatet. Als je wijzigingen wilt aanbrengen, ga je naar Instellingen."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ga naar Instellingen om de systeemnavigatie te updaten"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stand-by"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Het Android TV-apparaat wordt binnenkort uitgeschakeld. Druk op een knop om het ingeschakeld te houden."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Het apparaat wordt binnenkort uitgeschakeld. Druk om het ingeschakeld te houden."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 5a9d136..4d467fe 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -960,6 +960,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ସିଷ୍ଟମ୍ ନାଭିଗେସନ୍ ଅପ୍‌ଡେଟ୍ ହୋଇଛି। ପରିବର୍ତ୍ତନ କରିବା ପାଇଁ, ସେଟିଂସ୍‌କୁ ଯାଆନ୍ତୁ।"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ସିଷ୍ଟମ୍ ନାଭିଗେସନ୍ ଅପ୍‌ଡେଟ୍ କରିବା ପାଇଁ ସେଟିଂସ୍‍କୁ ଯାଆନ୍ତୁ"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ଷ୍ଟାଣ୍ଡବାଏ"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android ଟିଭି ଡିଭାଇସ୍ ଶୀଘ୍ର ବନ୍ଦ ହୋଇଯିବ; ଏହା ଚାଲୁ ରଖିବା ପାଇଁ ଏକ ବଟନ୍ ଦବାନ୍ତୁ।"</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ଡିଭାଇସ୍ ଶୀଘ୍ର ବନ୍ଦ ହୋଇଯିବ; ଚାଲୁ ରଖିବା ପାଇଁ ଦବାନ୍ତୁ।"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 84052d7..cce1df3 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -960,6 +960,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ਸਿਸਟਮ ਨੈਵੀਗੇਸ਼ਨ ਅੱਪਡੇਟ ਹੋ ਗਿਆ। ਤਬਦੀਲੀਆਂ ਕਰਨ ਲਈ, ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ।"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ਸਿਸਟਮ ਨੈਵੀਗੇਸ਼ਨ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਲਈ ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ਸਟੈਂਡਬਾਈ"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ਡੀਵਾਈਸ ਜਲਦ ਹੀ ਬੰਦ ਹੋ ਜਾਵੇਗਾ; ਇਸਨੂੰ ਚਾਲੂ ਰੱਖਣ ਲਈ ਕੋਈ ਬਟਨ ਦਬਾਓ।"</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"ਡੀਵਾਈਸ ਜਲਦ ਹੀ ਬੰਦ ਹੋ ਜਾਵੇਗਾ, ਇਸਨੂੰ ਚਾਲੂ ਰੱਖਣ ਲਈ ਦਬਾਓ।"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 4e7b0de..0a9c174 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -968,6 +968,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Nawigacja w systemie została zaktualizowana. Aby wprowadzić zmiany, otwórz Ustawienia."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Otwórz Ustawienia, by zaktualizować nawigację w systemie"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Tryb gotowości"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Urządzenie z Androidem TV za chwilę się wyłączy. Naciśnij przycisk, by pozostało włączone."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Urządzenie za chwilę się wyłączy. Naciśnij, by pozostało włączone."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 79dff12..9459e81 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navegação no sistema atualizada. Se quiser alterá-la, acesse as configurações."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Acesse as configurações para atualizar a navegação no sistema"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Em espera"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"O dispositivo Android TV entrará no modo de espera em breve. Pressione um botão para mantê-lo ativado."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"O dispositivo entrará no modo de espera em breve. Pressione para mantê-lo ativado."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index ab1fc96..b235bda 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"A navegação no sistema foi atualizada. Para efetuar alterações, aceda às Definições."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Aceda às Definições para atualizar a navegação no sistema."</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Modo de espera"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"O dispositivo Android TV irá desligar-se brevemente. Prima um botão para o manter ligado."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"O dispositivo irá desligar-se brevemente. Prima para o manter ligado."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 79dff12..9459e81 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navegação no sistema atualizada. Se quiser alterá-la, acesse as configurações."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Acesse as configurações para atualizar a navegação no sistema"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Em espera"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"O dispositivo Android TV entrará no modo de espera em breve. Pressione um botão para mantê-lo ativado."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"O dispositivo entrará no modo de espera em breve. Pressione para mantê-lo ativado."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index c2803aa..ea82ec3 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -963,6 +963,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigarea în sistem a fost actualizată. Pentru a face modificări, accesați Setările."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Accesați Setările pentru a actualiza navigarea în sistem"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Dispozitivul Android TV se va opri în curând. Apăsați un buton pentru a-l menține pornit."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Dispozitivul se va opri în curând. Apăsați pentru a-l menține pornit."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 9d0b2a9..fddb735 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -968,6 +968,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Параметры навигации в системе обновлены. Чтобы изменить их, перейдите в настройки."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Чтобы обновить параметры навигации в системе, перейдите в настройки."</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Переход в режим ожидания"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Устройство Android TV скоро выключится. Чтобы этого не произошло, нажмите любую кнопку."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Устройство скоро выключится. Чтобы этого не произошло, нажмите любую кнопку или коснитесь экрана."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 1b4db04..c28b189 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"පද්ධති සංචලනය යාවත්කාලීන කළා. වෙනස්කම් සිදු කිරීමට, සැකසීම් වෙත යන්න."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"පද්ධති සංචලනය යාවත්කාලීන කිරීමට සැකසීම් වෙත යන්න"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"පොරොත්තු"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV උපාංගය ඉක්මනින් ක්‍රියා විරහිත වනු ඇත; එය දිගටම ක්‍රියාත්මක කර තැබීමට බොත්තමක් ඔබන්න."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"උපාංගය ඉක්මනින් ක්‍රියා විරහිත වනු ඇත; එය දිගටම ක්‍රියාත්මක කර තැබීමට ඔබන්න."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 9cf97c9..ca929a0 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -968,6 +968,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigácia v systéme bola aktualizovaná. Ak chcete vykonať zmeny, prejdite do Nastavení."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Prejdite do Nastavení a aktualizujte navigáciu v systéme"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Pohotovostný režim"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Zariadenie Android TV sa čoskoro vypne. Ak ho chcete ponechať zapnuté, stlačte ľubovoľné tlačidlo."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Zariadenie sa čoskoro vypne. Ak ho chcete ponechať zapnuté, stlačte ľubovoľné tlačidlo."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 690e297..5b65bbc 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -968,6 +968,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Krmarjenje po sistemu je posodobljeno. Če želite opraviti spremembe, odprite nastavitve."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Če želite posodobiti krmarjenje po sistemu, odprite nastavitve"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje pripravljenosti"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Naprava Android TV se bo kmalu izklopila. Če tega ne želite, pritisnite poljuben gumb."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Naprava se bo kmalu izklopila. Če tega ne želite, pritisnite poljuben gumb."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 4ef95c5..b1be1fd 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigimi i sistemit u përditësua. Për të bërë ndryshime, shko te \"Cilësimet\"."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Shko te \"Cilësimet\" për të përditësuar navigimin e sistemit"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Në gatishmëri"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Pajisja Android TV do të fiket së shpejti. Shtyp një buton për ta mbajtur të ndezur."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Pajisja do të fiket së shpejti. Shtype për ta mbajtur të ndezur."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 19bcca8..26c6220 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -963,6 +963,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Навигација система је ажурирана. Да бисте унели измене, идите у Подешавања."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Идите у Подешавања да бисте ажурирали навигацију система"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Стање приправности"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV ће се ускоро искључити. Притисните дугме да би остао укључен."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Уређај ће се ускоро искључити. Притисните да би остао укључен."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 1177000..4f32f03 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systemnavigeringen har uppdaterats. Öppna inställningarna om du vill ändra något."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Öppna inställningarna och uppdatera systemnavigeringen"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Viloläge"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV-enheten stängs snart av. Tryck på en knapp för att behålla den på."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Enheten stängs snart av. Tryck för att behålla den på."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index bf85374..921bdd9 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Umesasisha usogezaji kwenye mfumo. Ili ufanye mabadiliko, nenda kwenye Mipangilio."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Nenda kwenye mipangilio ili usasishe usogezaji kwenye mfumo"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Hali tuli"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Kifaa cha Android TV kitazima hivi karibuni; bonyeza kitufe ili kisizime."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Kifaa kitazima hivi karibuni; bonyeza ili kisizime."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 0990b7f..5ca715b 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"சிஸ்டம் நேவிகேஷன் மாற்றப்பட்டது. மாற்றங்களைச் செய்ய ‘அமைப்புகளுக்குச்’ செல்லவும்."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"சிஸ்டம் நேவிகேஷனை மாற்ற ’அமைப்புகளுக்குச்’ செல்லவும்"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"இயக்க நேரம்"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV விரைவில் ஆஃப் ஆகலாம். இதைத் தொடர்ந்து ஆனில் வைக்க ஒரு பட்டனைத் தட்டவும்."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"இந்தச் சாதனம் விரைவில் ஆஃப் ஆகலாம், இதைத் தொடர்ந்து ஆனில் வைக்கத் தட்டவும்."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 21e915c..07fef971 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"సిస్టమ్ నావిగేషన్ అప్‌డేట్ చేయబడింది. మార్పులు చేయడానికి, సెట్టింగ్‌లకు వెళ్లండి."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"సిస్టమ్ నావిగేషన్‌ను అప్‌డేట్ చేయడానికి సెట్టింగ్‌లకు వెళ్లండి"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"స్టాండ్‌బై"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV పరికరం త్వరలో ఆఫ్ అయిపోతుంది; దాన్ని ఆన్‌లో ఉంచడానికి బటన్‌ను నొక్కండి."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"పరికరం త్వరలో ఆఫ్ అయిపోతుంది; దీన్ని ఆన్‌లో ఉంచడానికి నొక్కండి."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml
new file mode 100644
index 0000000..27db294
--- /dev/null
+++ b/packages/SystemUI/res/values-television/config.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- SystemUI Services: The classes of the stuff to start. -->
+    <string-array name="config_systemUIServiceComponents" translatable="false">
+        <item>com.android.systemui.volume.VolumeUI</item>
+        <item>com.android.systemui.stackdivider.Divider</item>
+        <item>com.android.systemui.statusbar.tv.TvStatusBar</item>
+        <item>com.android.systemui.usb.StorageNotification</item>
+        <item>com.android.systemui.power.PowerUI</item>
+        <item>com.android.systemui.media.RingtonePlayer</item>
+        <item>com.android.systemui.keyboard.KeyboardUI</item>
+        <item>com.android.systemui.pip.PipUI</item>
+        <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
+        <item>@string/config_systemUIVendorServiceComponent</item>
+        <item>com.android.systemui.SliceBroadcastRelayHandler</item>
+        <item>com.android.systemui.SizeCompatModeActivityController</item>
+        <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
+    </string-array>
+</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 45cfe92..14b7d74 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"อัปเดตการไปยังส่วนต่างๆ ของระบบแล้ว หากต้องการเปลี่ยนแปลง ให้ไปที่การตั้งค่า"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ไปที่การตั้งค่าเพื่ออัปเดตการไปยังส่วนต่างๆ ของระบบ"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"สแตนด์บาย"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"อุปกรณ์ Android TV จะปิดเครื่องในอีกไม่ช้า กดปุ่มเพื่อเปิดอุปกรณ์ต่อไป"</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"อุปกรณ์จะปิดเครื่องในอีกไม่ช้า กดเพื่อเปิดอุปกรณ์ต่อไป"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index bb150fc..3821262 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Na-update na ang pag-navigate ng system. Para gumawa ng mga pagbabago, pumunta sa Mga Setting."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Pumunta sa Mga Setting para i-update ang pag-navigate sa system"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Naka-standby"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Mao-off na ang Android TV device; pumindot ng button para panatilihin itong naka-on."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Mao-off na ang device; pumindot para panatilihin itong naka-on."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 5a0ede0..3dddbf5 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Sistemde gezinme yöntemi güncellendi. Değişiklik yapmak için Ayarlar\'a gidin."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Sistemde gezinme yöntemini güncellemek için Ayarlar\'a gidin"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Beklemeye alınıyor"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV cihazı kısa süre içinde kapanacak. Cihazınızı açık tutmak için bir düğmeye basın."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Cihaz kısa süre içinde kapanacak. Cihazı açık tutmak için düğmeye basın."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index eddc403..a3e9e62 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -968,6 +968,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Навігацію в системі оновлено. Щоб внести зміни, перейдіть у налаштування."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Перейдіть у налаштування, щоб оновити навігацію в системі"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Режим очікування"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Незабаром пристрій Android TV буде вимкнено. Натисніть кнопку, щоб цього не сталося."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Незабаром пристрій буде вимкнено. Натисніть, щоб цього не сталося."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 3962d4f..e30b9ae 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"سسٹم نیویگیشن اپ ڈیٹ کیا گیا۔ تبدیلیاں کرنے کے لیے، ترتیبات پر جائیں۔"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"سسٹم نیویگیشن اپ ڈیٹ کرنے کے لیے ترتیبات پر جائیں"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"اسٹینڈ بائی"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"‏Android TV آلہ جلد ہی بند ہوجائے گا آن رکھنے کے ليے بٹن دبائیں۔"</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"آلہ جلد ہی بند ہوجائے گا اسے آن رکھنے کے ليے دبائیں۔"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 2f84839..ec8639b 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Tizim navigatsiyasi yangilandi. Buni Sozlamalar orqali oʻzgartirishingiz mumkin."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Tizim navigatsiyasini yangilash uchun Sozlamalarni oching"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Kutib turing"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV qurilmasi oʻchish arafasida, yoniq qolishi uchun istalgan tugmani bosing."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Qurilma oʻchish arafasida, yoniq qolishi uchun istalgan tugmani bosing."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index f966c2e..9291563 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -960,6 +960,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Đã cập nhật chế độ di chuyển trên hệ thống. Để thay đổi, hãy chuyển đến phần Cài đặt."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Chuyển đến phần Cài đặt để cập nhật chế độ di chuyển trên hệ thống"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Chế độ chờ"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Thiết bị Android TV sẽ sớm tắt. Hãy nhấn vào một nút để thiết bị vẫn bật."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Thiết bị sẽ sớm tắt. Hãy nhấn vào một nút để thiết bị vẫn bật."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 64cf56e..55db2b5 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"系统导航已更新。要进行更改,请转到“设置”。"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"转到“设置”即可更新系统导航"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待机"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV 设备即将关闭;按一下相应的按钮即可让设备保持开启状态。"</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"设备即将关闭;按一下即可让设备保持开启状态。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index a49bc64..8a28aef 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"系統導覽已更新。如需變更,請前往「設定」。"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"前往「設定」更新系統導覽"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待機"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV 裝置即將關閉,按下按鈕即可保持開啟。"</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"裝置即將關閉,輕按即可保持開啟。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 2f468d0..79f336d 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"系統操作機制已更新。如要進行變更,請前往「設定」。"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"請前往「設定」更新系統操作機制"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待機"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Android TV 裝置即將進入待機模式。如要讓裝置保持開啟狀態,請按下任一按鈕。"</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"裝置即將進入待機模式。如要讓裝置保持開啟狀態,請輕觸螢幕或按下按鈕。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 2ee89db..bc3fcc0 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -958,6 +958,4 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Ukuzulazula kwesistimu kubuyekeziwe. Ukuze wenze ushintsho, hamba kokuthi Izilungiselelo."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Hamba kuzilungiselelo ukuze ubuyekeze ukuzulazula kwesistimu"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Ilindile"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6017523991455860482">"Idivayisi ye-Android TV maduze izovalwa, cindezela inkinobho ukuze uyigcine ivuliwe."</string>
-    <string name="inattentive_sleep_warning_message" product="default" msgid="4866963937818527643">"Idivayisi maduze izovalwa, cindezela ukuze uyigcine ivuliwe."</string>
 </resources>
diff --git a/packages/SystemUI/res/values/arrays_tv.xml b/packages/SystemUI/res/values/arrays_tv.xml
index 1fe6141..95716c8 100644
--- a/packages/SystemUI/res/values/arrays_tv.xml
+++ b/packages/SystemUI/res/values/arrays_tv.xml
@@ -36,5 +36,6 @@
 
     <string-array name="audio_recording_disclosure_exempt_apps" translatable="false">
       <item>com.google.android.katniss</item>
+      <item>com.google.android.apps.mediashell</item>
     </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values/colors_tv.xml b/packages/SystemUI/res/values/colors_tv.xml
index db22542..53cd971 100644
--- a/packages/SystemUI/res/values/colors_tv.xml
+++ b/packages/SystemUI/res/values/colors_tv.xml
@@ -22,13 +22,9 @@
     <color name="recents_tv_dismiss_text_color">#7FEEEEEE</color>
     <color name="recents_tv_text_shadow_color">#7F000000</color>
 
-
-    <!-- Text color used in audio recording bar: G50 -->
-    <color name="tv_audio_recording_bar_text">#FFF8F9FA</color>
-    <!-- Background color for a chip in audio recording bar: G800 -->
-    <color name="tv_audio_recording_bar_chip_background">#FF3C4043</color>
-    <!-- Audio recording bar background color: G900 -->
-    <color name="tv_audio_recording_bar_background">#FF202124</color>
+    <!-- Background color for audio recording indicator (G800) -->
+    <color name="tv_audio_recording_indicator_background">#FF3C4043</color>
+    <color name="tv_audio_recording_indicator_pulse">#4DFFFFFF</color>
 
     <color name="red">#FFCC0000</color>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 86ef031..e896c16 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -281,7 +281,6 @@
         <item>com.android.systemui.statusbar.phone.StatusBar</item>
         <item>com.android.systemui.usb.StorageNotification</item>
         <item>com.android.systemui.power.PowerUI</item>
-        <item>com.android.systemui.power.InattentiveSleepWarningController</item>
         <item>com.android.systemui.media.RingtonePlayer</item>
         <item>com.android.systemui.keyboard.KeyboardUI</item>
         <item>com.android.systemui.pip.PipUI</item>
@@ -463,8 +462,6 @@
         <item>com.android.systemui</item>
     </string-array>
 
-    <integer name="ongoing_appops_dialog_max_apps">5</integer>
-
     <!-- Launcher package name for overlaying icons. -->
     <string name="launcher_overlayable_package" translatable="false">com.android.launcher3</string>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f7b92b5..c948116 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1067,47 +1067,6 @@
 
     <!-- How much into a DisplayCutout's bounds we can go, on each side -->
     <dimen name="display_cutout_margin_consumption">0px</dimen>
-
-    <!-- Padding below Ongoing App Ops dialog title -->
-    <dimen name="ongoing_appops_dialog_sep">16dp</dimen>
-    <!--Padding around text items in Ongoing App Ops dialog -->
-    <dimen name="ongoing_appops_dialog_text_padding">16dp</dimen>
-    <!-- Height and width of App Opp icons in Ongoing App Ops dialog -->
-    <dimen name="ongoing_appops_dialog_icon_size">24dp</dimen>
-    <!-- Left margin of App Opp icons in Ongoing App Ops dialog -->
-    <dimen name="ongoing_appops_dialog_icon_margin">12dp</dimen>
-    <!-- Height and width of Application icons in Ongoing App Ops dialog -->
-    <dimen name="ongoing_appops_dialog_app_icon_size">32dp</dimen>
-    <!-- Height and width of Plus sign in Ongoing App Ops dialog -->
-    <dimen name="ongoing_appops_dialog_app_plus_size">24dp</dimen>
-    <!-- Height of line in Ongoing App Ops dialog-->
-    <dimen name="ongoing_appops_dialog_line_height">48dp</dimen>
-    <!-- Side margin of title in Ongoing App Ops dialog -->
-    <dimen name="ongoing_appops_dialog_title_margin_sides">24dp</dimen>
-    <!-- Bottom margin of items in Ongoing App Ops dialog -->
-    <dimen name="ongoing_appops_dialog_items_bottom_margin">24dp</dimen>
-    <!-- Top and bottom margin of title in Ongoing App Ops dialog -->
-    <dimen name="ongoing_appops_dialog_title_margin_top_bottom">18dp</dimen>
-    <!-- Text size for Ongoing App Ops dialog title -->
-    <dimen name="ongoing_appops_dialog_title_size">20sp</dimen>
-    <!-- Text size for Ongoing App Ops dialog items -->
-    <dimen name="ongoing_appops_dialog_item_size">16sp</dimen>
-    <!-- Height of the Ongoing App Ops chip -->
-    <dimen name="ongoing_appops_chip_height">32dp</dimen>
-    <!-- Padding between background of Ongoing App Ops chip and content -->
-    <dimen name="ongoing_appops_chip_bg_padding">8dp</dimen>
-    <!-- Side padding between background of Ongoing App Ops chip and content -->
-    <dimen name="ongoing_appops_chip_side_padding">8dp</dimen>
-    <!-- Margin between icons of Ongoing App Ops chip when QQS-->
-    <dimen name="ongoing_appops_chip_icon_margin_collapsed">0dp</dimen>
-    <!-- Margin between icons of Ongoing App Ops chip when QS-->
-    <dimen name="ongoing_appops_chip_icon_margin_expanded">2dp</dimen>
-    <!-- Icon size of Ongoing App Ops chip -->
-    <dimen name="ongoing_appops_chip_icon_size">@dimen/status_bar_icon_drawing_size</dimen>
-    <!-- Radius of Ongoing App Ops chip corners -->
-    <dimen name="ongoing_appops_chip_bg_corner_radius">16dp</dimen>
-
-
     <!-- How much each bubble is elevated. -->
     <dimen name="bubble_elevation">1dp</dimen>
     <!-- How much the bubble flyout text container is elevated. -->
@@ -1179,4 +1138,5 @@
     <dimen name="qs_media_height">150dp</dimen>
     <dimen name="qs_media_width">350dp</dimen>
     <dimen name="qs_media_padding">8dp</dimen>
+    <dimen name="qs_media_corner_radius">10dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 99da058..1053750 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -990,12 +990,6 @@
     <!-- Message shown when face authentication fails and the pin pad is visible. [CHAR LIMIT=60] -->
     <string name="keyguard_retry">Swipe up to try again</string>
 
-    <!-- Indication when device is slow charging due to misalignment on the dock. [CHAR LIMIT=60] -->
-    <string name="dock_alignment_slow_charging" product="default">Realign phone for faster charging</string>
-
-    <!-- Indication when device is not charging due to bad placement on the dock. [CHAR LIMIT=60] -->
-    <string name="dock_alignment_not_charging" product="default">Realign phone to charge wirelessly</string>
-
     <!-- Text on keyguard screen and in Quick Settings footer indicating that the device is enterprise-managed by a Device Owner [CHAR LIMIT=60] -->
     <string name="do_disclosure_generic">This device is managed by your organization</string>
 
@@ -2444,27 +2438,6 @@
          app for debugging. Will not be seen by users. [CHAR LIMIT=20] -->
     <string name="heap_dump_tile_name">Dump SysUI Heap</string>
 
-    <!-- Content description for ongoing privacy chip. Use with a single app [CHAR LIMIT=NONE]-->
-    <string name="ongoing_privacy_chip_content_single_app"><xliff:g id="app" example="Example App">%1$s</xliff:g> is using your <xliff:g id="types_list" example="camera, location">%2$s</xliff:g>.</string>
-
-    <!-- Content description for ongoing privacy chip. Use with multiple apps [CHAR LIMIT=NONE]-->
-    <string name="ongoing_privacy_chip_content_multiple_apps">Applications are using your <xliff:g id="types_list" example="camera, location">%s</xliff:g>.</string>
-
-    <!-- Separator for types. Include spaces before and after if needed [CHAR LIMIT=10] -->
-    <string name="ongoing_privacy_dialog_separator">,\u0020</string>
-
-    <!-- Separator for types, before last type. Include spaces before and after if needed [CHAR LIMIT=10] -->
-    <string name="ongoing_privacy_dialog_last_separator">\u0020and\u0020</string>
-
-    <!-- Text for camera app op [CHAR LIMIT=20]-->
-    <string name="privacy_type_camera">camera</string>
-
-    <!-- Text for location app op [CHAR LIMIT=20]-->
-    <string name="privacy_type_location">location</string>
-
-    <!-- Text for microphone app op [CHAR LIMIT=20]-->
-    <string name="privacy_type_microphone">microphone</string>
-
     <!-- Text for the quick setting tile for sensor privacy [CHAR LIMIT=30] -->
     <string name="sensor_privacy_mode">Sensors off</string>
 
@@ -2519,9 +2492,4 @@
 
     <!-- Title of the overlay warning the user to interact with the device or it will go to sleep. [CHAR LIMIT=25] -->
     <string name="inattentive_sleep_warning_title">Standby</string>
-    <!-- Message of the overlay warning the user to interact with the device or it will go to sleep. [CHAR LIMIT=NONE] -->
-    <string name="inattentive_sleep_warning_message" product="tv">The Android TV device will soon turn off; press a button to keep it on.</string>
-    <!-- Message of the overlay warning the user to interact with the device or it will go to sleep. [CHAR LIMIT=NONE] -->
-    <string name="inattentive_sleep_warning_message" product="default">The device will soon turn off; press to keep it on.</string>
-
 </resources>
diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml
index a9bdb71..6d61ff9 100644
--- a/packages/SystemUI/res/values/strings_tv.xml
+++ b/packages/SystemUI/res/values/strings_tv.xml
@@ -31,4 +31,8 @@
     <string name="pip_close">Close PIP</string>
     <!-- Button to move picture-in-picture (PIP) screen to the fullscreen in PIP menu [CHAR LIMIT=30] -->
     <string name="pip_fullscreen">Full screen</string>
+
+    <!-- Title and subtitle for AudioRecordingIndicator -->
+    <string name="mic_active">Microphone Active</string>
+    <string name="app_accessed_mic">%1$s accessed your microphone</string>
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 96fbcbb..926d016 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -227,18 +227,6 @@
         <item name="android:textColor">@color/dark_mode_qs_icon_color_single_tone</item>
     </style>
 
-    <style name="TextAppearance.AppOpsDialog" />
-
-    <style name="TextAppearance.AppOpsDialog.Title">
-        <item name="android:textSize">@dimen/ongoing_appops_dialog_title_size</item>
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
-    </style>
-
-    <style name="TextAppearance.AppOpsDialog.Item">
-        <item name="android:textSize">@dimen/ongoing_appops_dialog_item_size</item>
-        <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
-    </style>
-
     <style name="TextAppearance.DeviceManagementDialog">
         <item name="android:textColor">?android:attr/textColorPrimary</item>
     </style>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java
index fe5a57a..8c0ffb8 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java
@@ -83,16 +83,16 @@
     }
 
     @Override
-    public void onSaveReentrySnapFraction(ComponentName componentName, Rect bounds) {
+    public void onSaveReentryBounds(ComponentName componentName, Rect bounds) {
         for (PinnedStackListener listener : mListeners) {
-            listener.onSaveReentrySnapFraction(componentName, bounds);
+            listener.onSaveReentryBounds(componentName, bounds);
         }
     }
 
     @Override
-    public void onResetReentrySnapFraction(ComponentName componentName) {
+    public void onResetReentryBounds(ComponentName componentName) {
         for (PinnedStackListener listener : mListeners) {
-            listener.onResetReentrySnapFraction(componentName);
+            listener.onResetReentryBounds(componentName);
         }
     }
 
@@ -140,9 +140,9 @@
 
         public void onActionsChanged(ParceledListSlice actions) {}
 
-        public void onSaveReentrySnapFraction(ComponentName componentName, Rect bounds) {}
+        public void onSaveReentryBounds(ComponentName componentName, Rect bounds) {}
 
-        public void onResetReentrySnapFraction(ComponentName componentName) {}
+        public void onResetReentryBounds(ComponentName componentName) {}
 
         public void onDisplayInfoChanged(DisplayInfo displayInfo) {}
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskDescriptionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskDescriptionCompat.java
index eaf8d9b..35952f5 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskDescriptionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskDescriptionCompat.java
@@ -17,6 +17,7 @@
 package com.android.systemui.shared.system;
 
 import android.app.ActivityManager;
+import android.graphics.Bitmap;
 
 public class TaskDescriptionCompat {
 
@@ -37,4 +38,12 @@
                 ? mTaskDescription.getBackgroundColor()
                 : 0;
     }
+
+    public static Bitmap getIcon(ActivityManager.TaskDescription desc, int userId) {
+        if (desc.getInMemoryIcon() != null) {
+            return desc.getInMemoryIcon();
+        }
+        return ActivityManager.TaskDescription.loadTaskDescriptionIcon(
+                desc.getIconFilename(), userId);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 1d4b9ef..9bba2aa 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -151,7 +151,6 @@
     private static final int MSG_DPM_STATE_CHANGED = 309;
     private static final int MSG_USER_SWITCHING = 310;
     private static final int MSG_KEYGUARD_RESET = 312;
-    private static final int MSG_BOOT_COMPLETED = 313;
     private static final int MSG_USER_SWITCH_COMPLETE = 314;
     private static final int MSG_USER_INFO_CHANGED = 317;
     private static final int MSG_REPORT_EMERGENCY_CALL_ACTION = 318;
@@ -234,7 +233,6 @@
     private boolean mGoingToSleep;
     private boolean mBouncer;
     private boolean mAuthInterruptActive;
-    private boolean mBootCompleted;
     private boolean mNeedsSlowUnlockTransition;
     private boolean mHasLockscreenWallpaper;
     private boolean mAssistantVisible;
@@ -1075,8 +1073,6 @@
                 mHandler.sendMessage(mHandler.obtainMessage(MSG_PHONE_STATE_CHANGED, state));
             } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
                 mHandler.sendEmptyMessage(MSG_AIRPLANE_MODE_CHANGED);
-            } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
-                dispatchBootCompleted();
             } else if (TelephonyIntents.ACTION_SERVICE_STATE_CHANGED.equals(action)) {
                 ServiceState serviceState = ServiceState.newFromBundle(intent.getExtras());
                 int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
@@ -1550,9 +1546,6 @@
                     case MSG_KEYGUARD_BOUNCER_CHANGED:
                         handleKeyguardBouncerChanged(msg.arg1);
                         break;
-                    case MSG_BOOT_COMPLETED:
-                        handleBootCompleted();
-                        break;
                     case MSG_USER_INFO_CHANGED:
                         handleUserInfoChanged(msg.arg1);
                         break;
@@ -1648,11 +1641,6 @@
         filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
         broadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, mHandler);
 
-        final IntentFilter bootCompleteFilter = new IntentFilter();
-        bootCompleteFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
-        bootCompleteFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
-        broadcastDispatcher.registerReceiver(mBroadcastReceiver, bootCompleteFilter, mHandler);
-
         final IntentFilter allUserFilter = new IntentFilter();
         allUserFilter.addAction(Intent.ACTION_USER_INFO_CHANGED);
         allUserFilter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
@@ -2103,39 +2091,6 @@
     }
 
     /**
-     * This is exposed since {@link Intent#ACTION_BOOT_COMPLETED} is not sticky. If
-     * keyguard crashes sometime after boot, then it will never receive this
-     * broadcast and hence not handle the event. This method is ultimately called by
-     * PhoneWindowManager in this case.
-     */
-    public void dispatchBootCompleted() {
-        mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
-    }
-
-    /**
-     * Handle {@link #MSG_BOOT_COMPLETED}
-     */
-    private void handleBootCompleted() {
-        checkIsHandlerThread();
-        if (mBootCompleted) return;
-        mBootCompleted = true;
-        for (int i = 0; i < mCallbacks.size(); i++) {
-            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-            if (cb != null) {
-                cb.onBootCompleted();
-            }
-        }
-    }
-
-    /**
-     * We need to store this state in the KeyguardUpdateMonitor since this class will not be
-     * destroyed.
-     */
-    public boolean hasBootCompleted() {
-        return mBootCompleted;
-    }
-
-    /**
      * Handle {@link #MSG_DEVICE_PROVISIONED}
      */
     private void handleDeviceProvisioned() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index b4b83d6..04502f0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -148,14 +148,6 @@
     public void onUserUnlocked() { }
 
     /**
-     * Called when boot completed.
-     *
-     * Note, this callback will only be received if boot complete occurs after registering with
-     * KeyguardUpdateMonitor.
-     */
-    public void onBootCompleted() { }
-
-    /**
      * Called when the emergency call button is pressed.
      */
     public void onEmergencyCallAction() { }
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index c55b0d9..6821265 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -56,7 +56,6 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.power.EnhancedEstimates;
 import com.android.systemui.power.PowerUI;
-import com.android.systemui.privacy.PrivacyItemController;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.shared.plugins.PluginManager;
@@ -298,7 +297,6 @@
     @Inject Lazy<SensorPrivacyManager> mSensorPrivacyManager;
     @Inject Lazy<AutoHideController> mAutoHideController;
     @Inject Lazy<ForegroundServiceNotificationListener> mForegroundServiceNotificationListener;
-    @Inject Lazy<PrivacyItemController> mPrivacyItemController;
     @Inject @BgLooper Lazy<Looper> mBgLooper;
     @Inject @BgHandler Lazy<Handler> mBgHandler;
     @Inject @MainLooper Lazy<Looper> mMainLooper;
@@ -497,7 +495,6 @@
         mProviders.put(ForegroundServiceNotificationListener.class,
                 mForegroundServiceNotificationListener::get);
         mProviders.put(ClockManager.class, mClockManager::get);
-        mProviders.put(PrivacyItemController.class, mPrivacyItemController::get);
         mProviders.put(ActivityManagerWrapper.class, mActivityManagerWrapper::get);
         mProviders.put(DevicePolicyManagerWrapper.class, mDevicePolicyManagerWrapper::get);
         mProviders.put(PackageManagerWrapper.class, mPackageManagerWrapper::get);
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
index c1a23c8..41dd5bbf 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
@@ -37,7 +37,7 @@
  */
 @Singleton
 public class ForegroundServiceController {
-    private static final int[] APP_OPS = new int[] {AppOpsManager.OP_CAMERA,
+    public static final int[] APP_OPS = new int[] {AppOpsManager.OP_CAMERA,
             AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
             AppOpsManager.OP_RECORD_AUDIO,
             AppOpsManager.OP_COARSE_LOCATION,
@@ -139,6 +139,8 @@
             }
         }
 
+        // TODO: (b/145659174) remove when moving to NewNotifPipeline. Replaced by
+        //  ForegroundCoordinator
         // Update appOp if there's an associated pending or visible notification:
         final String foregroundKey = getStandardLayoutKey(userId, packageName);
         if (foregroundKey != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
index b983966..8105faa 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
@@ -27,6 +27,8 @@
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifCollectionListener;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 import javax.inject.Inject;
@@ -46,9 +48,13 @@
     @Inject
     public ForegroundServiceNotificationListener(Context context,
             ForegroundServiceController foregroundServiceController,
-            NotificationEntryManager notificationEntryManager) {
+            NotificationEntryManager notificationEntryManager,
+            NotifCollection notifCollection) {
         mContext = context;
         mForegroundServiceController = foregroundServiceController;
+
+        // TODO: (b/145659174) remove mEntryManager when moving to NewNotifPipeline. Replaced by
+        //  ForegroundCoordinator
         mEntryManager = notificationEntryManager;
         mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
             @Override
@@ -69,8 +75,24 @@
                 removeNotification(entry.getSbn());
             }
         });
-
         mEntryManager.addNotificationLifetimeExtender(new ForegroundServiceLifetimeExtender());
+
+        notifCollection.addCollectionListener(new NotifCollectionListener() {
+            @Override
+            public void onEntryAdded(NotificationEntry entry) {
+                addNotification(entry, entry.getImportance());
+            }
+
+            @Override
+            public void onEntryUpdated(NotificationEntry entry) {
+                updateNotification(entry, entry.getImportance());
+            }
+
+            @Override
+            public void onEntryRemoved(NotificationEntry entry, int reason, boolean removedByUser) {
+                removeNotification(entry.getSbn());
+            }
+        });
     }
 
     /**
@@ -152,6 +174,8 @@
                 true /* create if not found */);
     }
 
+    // TODO: (b/145659174) remove when moving to NewNotifPipeline. Replaced by
+    //  ForegroundCoordinator
     private void tagForeground(NotificationEntry entry) {
         final StatusBarNotification sbn = entry.getSbn();
         ArraySet<Integer> activeOps = mForegroundServiceController.getAppOps(
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServicesUserState.java b/packages/SystemUI/src/com/android/systemui/ForegroundServicesUserState.java
index a8ae654..2ef46dc 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServicesUserState.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServicesUserState.java
@@ -24,7 +24,7 @@
 /**
  * Struct to track relevant packages and notifications for a userid's foreground services.
  */
-class ForegroundServicesUserState {
+public class ForegroundServicesUserState {
     // shelf life of foreground services before they go bad
     private static final long FG_SERVICE_GRACE_MILLIS = 5000;
 
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
index 9793d72..8e49d58 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
@@ -33,6 +33,7 @@
 import androidx.slice.Clock;
 
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
+import com.android.systemui.BootCompleteCache;
 import com.android.systemui.assist.AssistHandleBehaviorController.BehaviorController;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
@@ -83,7 +84,6 @@
 
     private static final String[] DEFAULT_HOME_CHANGE_ACTIONS = new String[] {
             PackageManagerWrapper.ACTION_PREFERRED_ACTIVITY_CHANGED,
-            Intent.ACTION_BOOT_COMPLETED,
             Intent.ACTION_PACKAGE_ADDED,
             Intent.ACTION_PACKAGE_CHANGED,
             Intent.ACTION_PACKAGE_REMOVED
@@ -150,6 +150,15 @@
             mDefaultHome = getCurrentDefaultHome();
         }
     };
+
+    private final BootCompleteCache.BootCompleteListener mBootCompleteListener =
+            new BootCompleteCache.BootCompleteListener() {
+        @Override
+        public void onBootComplete() {
+            mDefaultHome = getCurrentDefaultHome();
+        }
+    };
+
     private final IntentFilter mDefaultHomeIntentFilter;
     private final Runnable mResetConsecutiveTaskSwitches = this::resetConsecutiveTaskSwitches;
 
@@ -163,6 +172,7 @@
     private final Lazy<WakefulnessLifecycle> mWakefulnessLifecycle;
     private final Lazy<PackageManagerWrapper> mPackageManagerWrapper;
     private final Lazy<BroadcastDispatcher> mBroadcastDispatcher;
+    private final Lazy<BootCompleteCache> mBootCompleteCache;
 
     private boolean mOnLockscreen;
     private boolean mIsDozing;
@@ -196,7 +206,8 @@
             Lazy<SysUiState> sysUiFlagContainer,
             Lazy<WakefulnessLifecycle> wakefulnessLifecycle,
             Lazy<PackageManagerWrapper> packageManagerWrapper,
-            Lazy<BroadcastDispatcher> broadcastDispatcher) {
+            Lazy<BroadcastDispatcher> broadcastDispatcher,
+            Lazy<BootCompleteCache> bootCompleteCache) {
         mClock = clock;
         mHandler = handler;
         mDeviceConfigHelper = deviceConfigHelper;
@@ -211,6 +222,7 @@
             mDefaultHomeIntentFilter.addAction(action);
         }
         mBroadcastDispatcher = broadcastDispatcher;
+        mBootCompleteCache = bootCompleteCache;
     }
 
     @Override
@@ -218,6 +230,7 @@
         mContext = context;
         mAssistHandleCallbacks = callbacks;
         mConsecutiveTaskSwitches = 0;
+        mBootCompleteCache.get().addListener(mBootCompleteListener);
         mDefaultHome = getCurrentDefaultHome();
         mBroadcastDispatcher.get()
                 .registerReceiver(mDefaultHomeBroadcastReceiver, mDefaultHomeIntentFilter);
@@ -250,6 +263,7 @@
         mAssistHandleCallbacks = null;
         if (mContext != null) {
             mBroadcastDispatcher.get().unregisterReceiver(mDefaultHomeBroadcastReceiver);
+            mBootCompleteCache.get().removeListener(mBootCompleteListener);
             Settings.Secure.putLong(mContext.getContentResolver(), LEARNING_TIME_ELAPSED_KEY, 0);
             Settings.Secure.putInt(mContext.getContentResolver(), LEARNING_EVENT_COUNT_KEY, 0);
             Settings.Secure.putLong(mContext.getContentResolver(), LEARNED_HINT_LAST_SHOWN_KEY, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleService.kt b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleService.kt
new file mode 100644
index 0000000..9ceafc6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleService.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.systemui.assist
+
+import android.app.Service
+import android.content.Intent
+import android.os.IBinder
+import dagger.Lazy
+import javax.inject.Inject
+
+class AssistHandleService @Inject constructor(private val assistManager: Lazy<AssistManager>)
+    : Service() {
+
+    private val binder = object : IAssistHandleService.Stub() {
+        override fun requestAssistHandles() {
+            assistManager.get().requestAssistHandles()
+        }
+    }
+
+    override fun onBind(intent: Intent?): IBinder? {
+        return binder
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistModule.java b/packages/SystemUI/src/com/android/systemui/assist/AssistModule.java
index 6f5a17d..96939b01 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistModule.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistModule.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.assist;
 
+import android.app.Service;
 import android.content.Context;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -33,8 +34,11 @@
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import dagger.Binds;
 import dagger.Module;
 import dagger.Provides;
+import dagger.multibindings.ClassKey;
+import dagger.multibindings.IntoMap;
 
 /** Module for dagger injections related to the Assistant. */
 @Module
@@ -87,4 +91,9 @@
     static Clock provideSystemClock() {
         return SystemClock::uptimeMillis;
     }
+
+    @Binds
+    @IntoMap
+    @ClassKey(AssistHandleService.class)
+    abstract Service bindAssistHandleService(AssistHandleService assistHandleService);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/assist/IAssistHandleService.aidl b/packages/SystemUI/src/com/android/systemui/assist/IAssistHandleService.aidl
new file mode 100644
index 0000000..ef07d9d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/assist/IAssistHandleService.aidl
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.assist;
+
+/** Interface implemented by AssisthandleService and called by on-device intelligence. */
+interface IAssistHandleService {
+
+    /** Request that the Assistant Handles be shown. */
+    oneway void requestAssistHandles();
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
index 8cccffa..9de6854 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
@@ -27,6 +27,7 @@
 
 import androidx.annotation.Nullable;
 
+import com.android.systemui.BootCompleteCache;
 import com.android.systemui.Dependency;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -62,7 +63,6 @@
 
     private static final String[] DEFAULT_HOME_CHANGE_ACTIONS = new String[] {
             PackageManagerWrapper.ACTION_PREFERRED_ACTIVITY_CHANGED,
-            Intent.ACTION_BOOT_COMPLETED,
             Intent.ACTION_PACKAGE_ADDED,
             Intent.ACTION_PACKAGE_CHANGED,
             Intent.ACTION_PACKAGE_REMOVED
@@ -77,13 +77,14 @@
 
     @Inject
     PhoneStateMonitor(Context context, BroadcastDispatcher broadcastDispatcher,
-            Optional<Lazy<StatusBar>> statusBarOptionalLazy) {
+            Optional<Lazy<StatusBar>> statusBarOptionalLazy, BootCompleteCache bootCompleteCache) {
         mContext = context;
         mStatusBarOptionalLazy = statusBarOptionalLazy;
         mStatusBarStateController = Dependency.get(StatusBarStateController.class);
 
         ActivityManagerWrapper activityManagerWrapper = ActivityManagerWrapper.getInstance();
         mDefaultHome = getCurrentDefaultHome();
+        bootCompleteCache.addListener(() -> mDefaultHome = getCurrentDefaultHome());
         IntentFilter intentFilter = new IntentFilter();
         for (String action : DEFAULT_HOME_CHANGE_ACTIONS) {
             intentFilter.addAction(action);
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
index 776189b7..5cc70bc 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
@@ -46,7 +46,7 @@
 private const val MSG_REMOVE_RECEIVER = 1
 private const val MSG_REMOVE_RECEIVER_FOR_USER = 2
 private const val TAG = "BroadcastDispatcher"
-private const val DEBUG = false
+private const val DEBUG = true
 
 /**
  * SystemUI master Broadcast Dispatcher.
@@ -56,7 +56,7 @@
  * a given broadcast.
  *
  * Use only for IntentFilters with actions and optionally categories. It does not support,
- * permissions, schemes, data types or data authorities.
+ * permissions, schemes, data types, data authorities or priority different than 0.
  * Cannot be used for getting sticky broadcasts.
  */
 @Singleton
@@ -104,6 +104,7 @@
         if (filter.countDataPaths() != 0) sb.append("Filter cannot contain DataPaths. ")
         if (filter.countDataSchemes() != 0) sb.append("Filter cannot contain DataSchemes. ")
         if (filter.countDataTypes() != 0) sb.append("Filter cannot contain DataTypes. ")
+        if (filter.priority != 0) sb.append("Filter cannot modify priority. ")
         if (!TextUtils.isEmpty(sb)) throw IllegalArgumentException(sb.toString())
     }
 
@@ -146,7 +147,13 @@
             when (msg.what) {
                 MSG_ADD_RECEIVER -> {
                     val data = msg.obj as ReceiverData
-                    val userId = data.user.identifier
+                    // If the receiver asked to be registered under the current user, we register
+                    // under the actual current user.
+                    val userId = if (data.user.identifier == UserHandle.USER_CURRENT) {
+                        context.userId
+                    } else {
+                        data.user.identifier
+                    }
                     if (userId < UserHandle.USER_ALL) {
                         if (DEBUG) Log.w(TAG, "Register receiver for invalid user: $userId")
                         return
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java
index c0053d1..a6a3ce0 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java
@@ -15,35 +15,61 @@
  */
 package com.android.systemui.bubbles;
 
+import android.annotation.Nullable;
+import android.app.Notification;
 import android.content.Context;
-import android.content.res.TypedArray;
+import android.content.pm.LauncherApps;
 import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
 import android.graphics.Path;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
 import android.util.AttributeSet;
+import android.util.PathParser;
 import android.widget.ImageView;
 
 import com.android.internal.graphics.ColorUtils;
+import com.android.launcher3.icons.BitmapInfo;
 import com.android.launcher3.icons.DotRenderer;
+import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 
 /**
- * View that circle crops its contents and supports displaying a coloured dot on a top corner.
+ * View that displays an adaptive icon with an app-badge and a dot.
+ *
+ * Dot = a small colored circle that indicates whether this bubble has an unread update.
+ * Badge = the icon associated with the app that created this bubble, this will show work profile
+ * badge if appropriate.
  */
 public class BadgedImageView extends ImageView {
 
-    private Rect mTempBounds = new Rect();
+    /** Same value as Launcher3 dot code */
+    private static final float WHITE_SCRIM_ALPHA = 0.54f;
+    /** Same as value in Launcher3 IconShape */
+    private static final int DEFAULT_PATH_SIZE = 100;
 
+    static final int DOT_STATE_DEFAULT = 0;
+    static final int DOT_STATE_SUPPRESSED_FOR_FLYOUT = 1;
+    static final int DOT_STATE_ANIMATING = 2;
+
+    // Flyout gets shown before the dot
+    private int mCurrentDotState = DOT_STATE_SUPPRESSED_FOR_FLYOUT;
+
+    private Bubble mBubble;
+    private BubbleIconFactory mBubbleIconFactory;
+
+    private int mIconBitmapSize;
     private DotRenderer mDotRenderer;
     private DotRenderer.DrawParams mDrawParams;
-    private int mIconBitmapSize;
-    private int mDotColor;
-    private float mDotScale = 0f;
-    private boolean mShowDot;
     private boolean mOnLeft;
 
-    /** Same as value in Launcher3 IconShape */
-    static final int DEFAULT_PATH_SIZE = 100;
+    private int mDotColor;
+    private float mDotScale = 0f;
+    private boolean mDotDrawn;
+
+    private Rect mTempBounds = new Rect();
 
     public BadgedImageView(Context context) {
         this(context, null);
@@ -63,17 +89,19 @@
         mIconBitmapSize = getResources().getDimensionPixelSize(R.dimen.bubble_icon_bitmap_size);
         mDrawParams = new DotRenderer.DrawParams();
 
-        TypedArray ta = context.obtainStyledAttributes(
-                new int[]{android.R.attr.colorBackgroundFloating});
-        ta.recycle();
+        Path iconPath = PathParser.createPathFromPathData(
+                getResources().getString(com.android.internal.R.string.config_icon_mask));
+        mDotRenderer = new DotRenderer(mIconBitmapSize, iconPath, DEFAULT_PATH_SIZE);
     }
 
     @Override
     public void onDraw(Canvas canvas) {
         super.onDraw(canvas);
-        if (!mShowDot) {
+        if (isDotHidden()) {
+            mDotDrawn = false;
             return;
         }
+        mDotDrawn = mDotScale > 0.1f;
         getDrawingRect(mTempBounds);
 
         mDrawParams.color = mDotColor;
@@ -81,16 +109,29 @@
         mDrawParams.leftAlign = mOnLeft;
         mDrawParams.scale = mDotScale;
 
-        if (mDotRenderer == null) {
-            Path circlePath = new Path();
-            float radius = DEFAULT_PATH_SIZE * 0.5f;
-            circlePath.addCircle(radius /* x */, radius /* y */, radius, Path.Direction.CW);
-            mDotRenderer = new DotRenderer(mIconBitmapSize, circlePath, DEFAULT_PATH_SIZE);
-        }
         mDotRenderer.draw(canvas, mDrawParams);
     }
 
     /**
+     * Sets the dot state, does not animate changes.
+     */
+    void setDotState(int state) {
+        mCurrentDotState = state;
+        if (state == DOT_STATE_SUPPRESSED_FOR_FLYOUT || state == DOT_STATE_DEFAULT) {
+            mDotScale = mBubble.showDot() ? 1f : 0f;
+            invalidate();
+        }
+    }
+
+    /**
+     * Whether the dot should be hidden based on current dot state.
+     */
+    private boolean isDotHidden() {
+        return (mCurrentDotState == DOT_STATE_DEFAULT && !mBubble.showDot())
+                || mCurrentDotState == DOT_STATE_SUPPRESSED_FOR_FLYOUT;
+    }
+
+    /**
      * Set whether the dot should appear on left or right side of the view.
      */
     void setDotOnLeft(boolean onLeft) {
@@ -98,29 +139,10 @@
         invalidate();
     }
 
-    boolean getDotOnLeft() {
-        return mOnLeft;
-    }
-
-    /**
-     * Set whether the dot should show or not.
-     */
-    void setShowDot(boolean showDot) {
-        mShowDot = showDot;
-        invalidate();
-    }
-
-    /**
-     * @return whether the dot is being displayed.
-     */
-    boolean isShowingDot() {
-        return mShowDot;
-    }
-
     /**
      * The colour to use for the dot.
      */
-    public void setDotColor(int color) {
+    void setDotColor(int color) {
         mDotColor = ColorUtils.setAlphaComponent(color, 255 /* alpha */);
         invalidate();
     }
@@ -128,7 +150,7 @@
     /**
      * @param iconPath The new icon path to use when calculating dot position.
      */
-    public void drawDot(Path iconPath) {
+    void drawDot(Path iconPath) {
         mDotRenderer = new DotRenderer(mIconBitmapSize, iconPath, DEFAULT_PATH_SIZE);
         invalidate();
     }
@@ -142,6 +164,13 @@
     }
 
     /**
+     * Whether decorations (badges or dots) are on the left.
+     */
+    boolean getDotOnLeft() {
+        return mOnLeft;
+    }
+
+    /**
      * Return dot position relative to bubble view container bounds.
      */
     float[] getDotCenter() {
@@ -149,11 +178,146 @@
         if (mOnLeft) {
             dotPosition = mDotRenderer.getLeftDotPosition();
         } else {
-            dotPosition =  mDotRenderer.getRightDotPosition();
+            dotPosition = mDotRenderer.getRightDotPosition();
         }
         getDrawingRect(mTempBounds);
         float dotCenterX = mTempBounds.width() * dotPosition[0];
         float dotCenterY = mTempBounds.height() * dotPosition[1];
         return new float[]{dotCenterX, dotCenterY};
     }
+
+    /**
+     * Populates this view with a bubble.
+     * <p>
+     * This should only be called when a new bubble is being set on the view, updates to the
+     * current bubble should use {@link #update(Bubble)}.
+     *
+     * @param bubble the bubble to display in this view.
+     */
+    public void setBubble(Bubble bubble) {
+        mBubble = bubble;
+    }
+
+    /**
+     * @param factory Factory for creating normalized bubble icons.
+     */
+    public void setBubbleIconFactory(BubbleIconFactory factory) {
+        mBubbleIconFactory = factory;
+    }
+
+    /**
+     * The key for the {@link Bubble} associated with this view, if one exists.
+     */
+    @Nullable
+    public String getKey() {
+        return (mBubble != null) ? mBubble.getKey() : null;
+    }
+
+    /**
+     * Updates the UI based on the bubble, updates badge and animates messages as needed.
+     */
+    public void update(Bubble bubble) {
+        mBubble = bubble;
+        setDotState(DOT_STATE_SUPPRESSED_FOR_FLYOUT);
+        updateViews();
+    }
+
+    int getDotColor() {
+        return mDotColor;
+    }
+
+    /** Sets the position of the 'new' dot, animating it out and back in if requested. */
+    void setDotPosition(boolean onLeft, boolean animate) {
+        if (animate && onLeft != getDotOnLeft() && !isDotHidden()) {
+            animateDot(false /* showDot */, () -> {
+                setDotOnLeft(onLeft);
+                animateDot(true /* showDot */, null);
+            });
+        } else {
+            setDotOnLeft(onLeft);
+        }
+    }
+
+    boolean getDotPositionOnLeft() {
+        return getDotOnLeft();
+    }
+
+    /** Changes the dot's visibility to match the bubble view's state. */
+    void animateDot() {
+        if (mCurrentDotState == DOT_STATE_DEFAULT) {
+            animateDot(mBubble.showDot(), null);
+        }
+    }
+
+    /**
+     * Animates the dot to show or hide.
+     */
+    private void animateDot(boolean showDot, Runnable after) {
+        if (mDotDrawn == showDot) {
+            // State is consistent, do nothing.
+            return;
+        }
+
+        setDotState(DOT_STATE_ANIMATING);
+
+        // Do NOT wait until after animation ends to setShowDot
+        // to avoid overriding more recent showDot states.
+        clearAnimation();
+        animate().setDuration(200)
+                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+                .setUpdateListener((valueAnimator) -> {
+                    float fraction = valueAnimator.getAnimatedFraction();
+                    fraction = showDot ? fraction : 1f - fraction;
+                    setDotScale(fraction);
+                }).withEndAction(() -> {
+                    setDotScale(showDot ? 1f : 0f);
+                    setDotState(DOT_STATE_DEFAULT);
+                    if (after != null) {
+                        after.run();
+                    }
+                }).start();
+    }
+
+    void updateViews() {
+        if (mBubble == null || mBubbleIconFactory == null) {
+            return;
+        }
+
+        Drawable bubbleDrawable = getBubbleDrawable(mContext);
+        BitmapInfo badgeBitmapInfo = mBubbleIconFactory.getBadgedBitmap(mBubble);
+        BitmapInfo bubbleBitmapInfo = mBubbleIconFactory.getBubbleBitmap(bubbleDrawable,
+                badgeBitmapInfo);
+        setImageBitmap(bubbleBitmapInfo.icon);
+
+        // Update badge.
+        mDotColor = ColorUtils.blendARGB(badgeBitmapInfo.color, Color.WHITE, WHITE_SCRIM_ALPHA);
+        setDotColor(mDotColor);
+
+        // Update dot.
+        Path iconPath = PathParser.createPathFromPathData(
+                getResources().getString(com.android.internal.R.string.config_icon_mask));
+        Matrix matrix = new Matrix();
+        float scale = mBubbleIconFactory.getNormalizer().getScale(bubbleDrawable,
+                null /* outBounds */, null /* path */, null /* outMaskShape */);
+        float radius = BadgedImageView.DEFAULT_PATH_SIZE / 2f;
+        matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */,
+                radius /* pivot y */);
+        iconPath.transform(matrix);
+        drawDot(iconPath);
+
+        animateDot();
+    }
+
+    Drawable getBubbleDrawable(Context context) {
+        if (mBubble.getShortcutInfo() != null && mBubble.usingShortcutInfo()) {
+            LauncherApps launcherApps =
+                    (LauncherApps) getContext().getSystemService(Context.LAUNCHER_APPS_SERVICE);
+            int density = getContext().getResources().getConfiguration().densityDpi;
+            return launcherApps.getShortcutIconDrawable(mBubble.getShortcutInfo(), density);
+        } else {
+            Notification.BubbleMetadata metadata = mBubble.getEntry().getBubbleMetadata();
+            Icon ic = metadata.getIcon();
+            return ic.loadDrawable(context);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index c6b9090..7934e10 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -27,9 +27,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager;
+import android.content.pm.ShortcutInfo;
 import android.content.res.Resources;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.Bundle;
 import android.os.Parcelable;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -57,10 +61,12 @@
     private final String mGroupId;
     private String mAppName;
     private Drawable mUserBadgedAppIcon;
+    private ShortcutInfo mShortcutInfo;
 
     private boolean mInflated;
-    private BubbleView mIconView;
+    private BadgedImageView mIconView;
     private BubbleExpandedView mExpandedView;
+    private BubbleIconFactory mBubbleIconFactory;
 
     private long mLastUpdated;
     private long mLastAccessed;
@@ -94,6 +100,14 @@
         mLastUpdated = e.getSbn().getPostTime();
         mGroupId = groupId(e);
 
+        String shortcutId = e.getSbn().getNotification().getShortcutId();
+        if (BubbleExperimentConfig.useShortcutInfoToBubble(context)
+                && shortcutId != null) {
+            mShortcutInfo = BubbleExperimentConfig.getShortcutInfo(context,
+                    e.getSbn().getPackageName(),
+                    e.getSbn().getUser(), shortcutId);
+        }
+
         PackageManager pm = context.getPackageManager();
         ApplicationInfo info;
         try {
@@ -133,21 +147,34 @@
         return mAppName;
     }
 
-    public Drawable getUserBadgedAppIcon() {
+    Drawable getUserBadgedAppIcon() {
         return mUserBadgedAppIcon;
     }
 
+    @Nullable
+    public ShortcutInfo getShortcutInfo() {
+        return mShortcutInfo;
+    }
+
+    /**
+     * Whether shortcut information should be used to populate the bubble.
+     * <p>
+     * To populate the activity use {@link LauncherApps#startShortcut(ShortcutInfo, Rect, Bundle)}.
+     * To populate the icon use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}.
+     */
+    public boolean usingShortcutInfo() {
+        return BubbleExperimentConfig.isShortcutIntent(getBubbleIntent());
+    }
+
+    void setBubbleIconFactory(BubbleIconFactory factory) {
+        mBubbleIconFactory = factory;
+    }
+
     boolean isInflated() {
         return mInflated;
     }
 
-    void updateDotVisibility() {
-        if (mIconView != null) {
-            mIconView.updateDotVisibility(true /* animate */);
-        }
-    }
-
-    BubbleView getIconView() {
+    BadgedImageView getIconView() {
         return mIconView;
     }
 
@@ -165,13 +192,14 @@
         if (mInflated) {
             return;
         }
-        mIconView = (BubbleView) inflater.inflate(
+        mIconView = (BadgedImageView) inflater.inflate(
                 R.layout.bubble_view, stackView, false /* attachToRoot */);
+        mIconView.setBubbleIconFactory(mBubbleIconFactory);
         mIconView.setBubble(this);
 
         mExpandedView = (BubbleExpandedView) inflater.inflate(
                 R.layout.bubble_expanded_view, stackView, false /* attachToRoot */);
-        mExpandedView.setBubble(this, stackView, mAppName);
+        mExpandedView.setBubble(this, stackView);
 
         mInflated = true;
     }
@@ -232,15 +260,15 @@
      */
     void markAsAccessedAt(long lastAccessedMillis) {
         mLastAccessed = lastAccessedMillis;
-        setShowInShadeWhenBubble(false);
-        setShowBubbleDot(false);
+        setShowInShade(false);
+        setShowDot(false /* show */, true /* animate */);
     }
 
     /**
      * Whether this notification should be shown in the shade when it is also displayed as a
      * bubble.
      */
-    boolean showInShadeWhenBubble() {
+    boolean showInShade() {
         return !mEntry.isRowDismissed() && !shouldSuppressNotification()
                 && (!mEntry.isClearable() || mShowInShadeWhenBubble);
     }
@@ -249,29 +277,37 @@
      * Sets whether this notification should be shown in the shade when it is also displayed as a
      * bubble.
      */
-    void setShowInShadeWhenBubble(boolean showInShade) {
+    void setShowInShade(boolean showInShade) {
         mShowInShadeWhenBubble = showInShade;
     }
 
     /**
      * Sets whether the bubble for this notification should show a dot indicating updated content.
      */
-    void setShowBubbleDot(boolean showDot) {
+    void setShowDot(boolean showDot, boolean animate) {
         mShowBubbleUpdateDot = showDot;
+        if (animate && mIconView != null) {
+            mIconView.animateDot();
+        } else if (mIconView != null) {
+            mIconView.invalidate();
+        }
     }
 
     /**
      * Whether the bubble for this notification should show a dot indicating updated content.
      */
-    boolean showBubbleDot() {
-        return mShowBubbleUpdateDot && !mEntry.shouldSuppressNotificationDot();
+    boolean showDot() {
+        return mShowBubbleUpdateDot
+                && !mEntry.shouldSuppressNotificationDot()
+                && !shouldSuppressNotification();
     }
 
     /**
      * Whether the flyout for the bubble should be shown.
      */
-    boolean showFlyoutForBubble() {
+    boolean showFlyout() {
         return !mSuppressFlyout && !mEntry.shouldSuppressPeek()
+                && !shouldSuppressNotification()
                 && !mEntry.shouldSuppressNotificationList();
     }
 
@@ -293,20 +329,6 @@
         return (flags & Notification.FLAG_FOREGROUND_SERVICE) != 0;
     }
 
-    /**
-     * Whether this bubble was explicitly created by the user via a SysUI affordance.
-     */
-    boolean isUserCreated() {
-        return mIsUserCreated;
-    }
-
-    /**
-     * Set whether this bubble was explicitly created by the user via a SysUI affordance.
-     */
-    void setUserCreated(boolean isUserCreated) {
-        mIsUserCreated = isUserCreated;
-    }
-
     float getDesiredHeight(Context context) {
         Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
         boolean useRes = data.getDesiredHeightResId() != 0;
@@ -331,7 +353,7 @@
     }
 
     @Nullable
-    PendingIntent getBubbleIntent(Context context) {
+    PendingIntent getBubbleIntent() {
         Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
         if (data != null) {
             return data.getIntent();
@@ -456,9 +478,9 @@
     public void dump(
             @NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
         pw.print("key: "); pw.println(mKey);
-        pw.print("  showInShade:   "); pw.println(showInShadeWhenBubble());
-        pw.print("  showDot:       "); pw.println(showBubbleDot());
-        pw.print("  showFlyout:    "); pw.println(showFlyoutForBubble());
+        pw.print("  showInShade:   "); pw.println(showInShade());
+        pw.print("  showDot:       "); pw.println(showDot());
+        pw.print("  showFlyout:    "); pw.println(showFlyout());
         pw.print("  desiredHeight: "); pw.println(getDesiredHeightString());
         pw.print("  suppressNotif: "); pw.println(shouldSuppressNotification());
         pw.print("  autoExpand:    "); pw.println(shouldAutoExpand());
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index db1185f..1938194 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -31,6 +31,7 @@
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 
 import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_CONTROLLER;
+import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_EXPERIMENTS;
 import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
 import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.systemui.statusbar.StatusBarState.SHADE;
@@ -43,13 +44,19 @@
 
 import android.annotation.UserIdInt;
 import android.app.ActivityManager.RunningTaskInfo;
+import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.app.RemoteInput;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.ShortcutManager;
 import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.net.Uri;
+import android.os.Handler;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.service.notification.NotificationListenerService.RankingMap;
@@ -68,6 +75,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.util.ScreenshotHelper;
 import com.android.systemui.R;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -85,6 +93,7 @@
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.RemoteInputUriController;
 import com.android.systemui.statusbar.policy.ZenModeController;
 
 import java.io.FileDescriptor;
@@ -92,7 +101,10 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.function.Consumer;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -136,6 +148,8 @@
     @Nullable private BubbleStackView.SurfaceSynchronizer mSurfaceSynchronizer;
     private final NotificationGroupManager mNotificationGroupManager;
     private final Lazy<ShadeController> mShadeController;
+    private final RemoteInputUriController mRemoteInputUriController;
+    private Handler mHandler = new Handler() {};
 
     private BubbleData mBubbleData;
     @Nullable private BubbleStackView mStackView;
@@ -145,10 +159,16 @@
     // Saves notification keys of active bubbles when users are switched.
     private final SparseSetArray<String> mSavedBubbleKeysPerUser;
 
+    // Saves notification keys of user created "fake" bubbles so that we can allow notifications
+    // like these to bubble by default. Doesn't persist across reboots, not a long-term solution.
+    private final HashSet<String> mUserCreatedBubbles;
+
     // Bubbles get added to the status bar view
     private final StatusBarWindowController mStatusBarWindowController;
     private final ZenModeController mZenModeController;
     private StatusBarStateListener mStatusBarStateListener;
+    private final ScreenshotHelper mScreenshotHelper;
+
 
     private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
     private IStatusBarService mBarService;
@@ -186,6 +206,16 @@
     }
 
     /**
+     * Listener for handling bubble screenshot events.
+     */
+    public interface BubbleScreenshotListener {
+        /**
+         * Called to trigger taking a screenshot and sending the result to a bubble.
+         */
+        void onBubbleScreenshot(Bubble bubble);
+    }
+
+    /**
      * Listens for the current state of the status bar and updates the visibility state
      * of bubbles as needed.
      */
@@ -220,10 +250,12 @@
             ZenModeController zenModeController,
             NotificationLockscreenUserManager notifUserManager,
             NotificationGroupManager groupManager,
-            NotificationEntryManager entryManager) {
+            NotificationEntryManager entryManager,
+            RemoteInputUriController remoteInputUriController) {
         this(context, statusBarWindowController, statusBarStateController, shadeController,
                 data, null /* synchronizer */, configurationController, interruptionStateProvider,
-                zenModeController, notifUserManager, groupManager, entryManager);
+                zenModeController, notifUserManager, groupManager, entryManager,
+                remoteInputUriController);
     }
 
     public BubbleController(Context context,
@@ -237,23 +269,25 @@
             ZenModeController zenModeController,
             NotificationLockscreenUserManager notifUserManager,
             NotificationGroupManager groupManager,
-            NotificationEntryManager entryManager) {
+            NotificationEntryManager entryManager,
+            RemoteInputUriController remoteInputUriController) {
         mContext = context;
         mNotificationInterruptionStateProvider = interruptionStateProvider;
         mNotifUserManager = notifUserManager;
         mZenModeController = zenModeController;
+        mRemoteInputUriController = remoteInputUriController;
         mZenModeController.addCallback(new ZenModeController.Callback() {
             @Override
             public void onZenChanged(int zen) {
-                if (mStackView != null) {
-                    mStackView.updateDots();
+                for (Bubble b : mBubbleData.getBubbles()) {
+                    b.setShowDot(b.showInShade(), true /* animate */);
                 }
             }
 
             @Override
             public void onConfigChanged(ZenModeConfig config) {
-                if (mStackView != null) {
-                    mStackView.updateDots();
+                for (Bubble b : mBubbleData.getBubbles()) {
+                    b.setShowDot(b.showInShade(), true /* animate */);
                 }
             }
         });
@@ -312,6 +346,10 @@
                     restoreBubbles(newUserId);
                     mCurrentUserId = newUserId;
                 });
+
+        mUserCreatedBubbles = new HashSet<>();
+
+        mScreenshotHelper = new ScreenshotHelper(context);
     }
 
     /**
@@ -329,6 +367,9 @@
             if (mExpandListener != null) {
                 mStackView.setExpandListener(mExpandListener);
             }
+            if (mBubbleScreenshotListener != null) {
+                mStackView.setBubbleScreenshotListener(mBubbleScreenshotListener);
+            }
         }
     }
 
@@ -457,7 +498,7 @@
      */
     public boolean isBubbleNotificationSuppressedFromShade(String key) {
         boolean isBubbleAndSuppressed = mBubbleData.hasBubbleWithKey(key)
-                && !mBubbleData.getBubbleWithKey(key).showInShadeWhenBubble();
+                && !mBubbleData.getBubbleWithKey(key).showInShade();
         NotificationEntry entry = mNotificationEntryManager.getActiveNotificationUnfiltered(key);
         String groupKey = entry != null ? entry.getSbn().getGroupKey() : null;
         boolean isSuppressedSummary = mBubbleData.isSummarySuppressed(groupKey);
@@ -535,10 +576,13 @@
      * @param entry the notification to show as a bubble.
      */
     public void onUserCreatedBubbleFromNotification(NotificationEntry entry) {
+        if (DEBUG_EXPERIMENTS || DEBUG_BUBBLE_CONTROLLER) {
+            Log.d(TAG, "onUserCreatedBubble: " + entry.getKey());
+        }
         mShadeController.get().collapsePanel(true);
         entry.setFlagBubble(true);
         updateBubble(entry, true /* suppressFlyout */, false /* showInShade */);
-        mBubbleData.getBubbleWithKey(entry.getKey()).setUserCreated(true);
+        mUserCreatedBubbles.add(entry.getKey());
     }
 
     /**
@@ -548,8 +592,19 @@
      * @param entry the notification to no longer show as a bubble.
      */
     public void onUserDemotedBubbleFromNotification(NotificationEntry entry) {
+        if (DEBUG_EXPERIMENTS || DEBUG_BUBBLE_CONTROLLER) {
+            Log.d(TAG, "onUserDemotedBubble: " + entry.getKey());
+        }
         entry.setFlagBubble(false);
         removeBubble(entry.getKey(), DISMISS_BLOCKED);
+        mUserCreatedBubbles.remove(entry.getKey());
+    }
+
+    /**
+     * Whether this bubble was explicitly created by the user via a SysUI affordance.
+     */
+    boolean isUserCreatedBubble(String key) {
+        return mUserCreatedBubbles.contains(key);
     }
 
     /**
@@ -608,15 +663,13 @@
                 Bubble bubble = mBubbleData.getBubbleWithKey(key);
                 boolean bubbleExtended = entry != null && entry.isBubble() && userRemovedNotif;
                 if (bubbleExtended) {
-                    bubble.setShowInShadeWhenBubble(false);
-                    bubble.setShowBubbleDot(false);
-                    if (mStackView != null) {
-                        mStackView.updateDotVisibility(entry.getKey());
-                    }
+                    bubble.setShowInShade(false);
+                    bubble.setShowDot(false /* show */, true /* animate */);
                     mNotificationEntryManager.updateNotifications(
                             "BubbleController.onNotificationRemoveRequested");
                     return true;
-                } else if (!userRemovedNotif && entry != null && !bubble.isUserCreated()) {
+                } else if (!userRemovedNotif && entry != null
+                        && !isUserCreatedBubble(bubble.getKey())) {
                     // This wasn't a user removal so we should remove the bubble as well
                     mBubbleData.notificationEntryRemoved(entry, DISMISS_NOTIF_CANCEL);
                     return false;
@@ -637,11 +690,8 @@
                 // As far as group manager is concerned, once a child is no longer shown
                 // in the shade, it is essentially removed.
                 mNotificationGroupManager.onEntryRemoved(bubbleChild.getEntry());
-                bubbleChild.setShowInShadeWhenBubble(false);
-                bubbleChild.setShowBubbleDot(false);
-                if (mStackView != null) {
-                    mStackView.updateDotVisibility(bubbleChild.getKey());
-                }
+                bubbleChild.setShowInShade(false);
+                bubbleChild.setShowDot(false /* show */, true /* animate */);
             }
             // And since all children are removed, remove the summary.
             mNotificationGroupManager.onEntryRemoved(summary);
@@ -676,26 +726,36 @@
     private final NotificationEntryListener mEntryListener = new NotificationEntryListener() {
         @Override
         public void onPendingEntryAdded(NotificationEntry entry) {
-            Bubble b = mBubbleData.getBubbleWithKey(entry.getKey());
-            BubbleExperimentConfig.adjustForExperiments(mContext, entry, b);
+            boolean previouslyUserCreated = mUserCreatedBubbles.contains(entry.getKey());
+            boolean wasAdjusted = BubbleExperimentConfig.adjustForExperiments(
+                    mContext, entry, previouslyUserCreated);
 
             if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
-                    && canLaunchInActivityView(mContext, entry)) {
+                    && (canLaunchInActivityView(mContext, entry) || wasAdjusted)) {
+                if (wasAdjusted && !previouslyUserCreated) {
+                    // Gotta treat the auto-bubbled / whitelisted packaged bubbles as usercreated
+                    mUserCreatedBubbles.add(entry.getKey());
+                }
                 updateBubble(entry);
             }
         }
 
         @Override
         public void onPreEntryUpdated(NotificationEntry entry) {
-            Bubble b = mBubbleData.getBubbleWithKey(entry.getKey());
-            BubbleExperimentConfig.adjustForExperiments(mContext, entry, b);
+            boolean previouslyUserCreated = mUserCreatedBubbles.contains(entry.getKey());
+            boolean wasAdjusted = BubbleExperimentConfig.adjustForExperiments(
+                    mContext, entry, previouslyUserCreated);
 
             boolean shouldBubble = mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
-                    && canLaunchInActivityView(mContext, entry);
+                    && (canLaunchInActivityView(mContext, entry) || wasAdjusted);
             if (!shouldBubble && mBubbleData.hasBubbleWithKey(entry.getKey())) {
                 // It was previously a bubble but no longer a bubble -- lets remove it
                 removeBubble(entry.getKey(), DISMISS_NO_LONGER_BUBBLE);
             } else if (shouldBubble) {
+                if (wasAdjusted && !previouslyUserCreated) {
+                    // Gotta treat the auto-bubbled / whitelisted packaged bubbles as usercreated
+                    mUserCreatedBubbles.add(entry.getKey());
+                }
                 updateBubble(entry);
             }
         }
@@ -742,7 +802,7 @@
                 // If the bubble is removed for user switching, leave the notification in place.
                 if (reason != DISMISS_USER_CHANGED) {
                     if (!mBubbleData.hasBubbleWithKey(bubble.getKey())
-                            && !bubble.showInShadeWhenBubble()) {
+                            && !bubble.showInShade()) {
                         // The bubble is gone & the notification is gone, time to actually remove it
                         mNotificationEntryManager.performRemoveNotification(
                                 bubble.getEntry().getSbn(), UNDEFINED_DISMISS_REASON);
@@ -999,11 +1059,6 @@
         PendingIntent intent = entry.getBubbleMetadata() != null
                 ? entry.getBubbleMetadata().getIntent()
                 : null;
-        return canLaunchIntentInActivityView(context, entry, intent);
-    }
-
-    static boolean canLaunchIntentInActivityView(Context context, NotificationEntry entry,
-            PendingIntent intent) {
         if (intent == null) {
             Log.w(TAG, "Unable to create bubble -- no intent: " + entry.getKey());
             return false;
@@ -1036,4 +1091,71 @@
             }
         }
     }
+
+    // TODO: Copied from RemoteInputView. Consolidate RemoteInput intent logic.
+    private Intent prepareRemoteInputFromData(String contentType, Uri data,
+            RemoteInput remoteInput, NotificationEntry entry) {
+        HashMap<String, Uri> results = new HashMap<>();
+        results.put(contentType, data);
+        mRemoteInputUriController.grantInlineReplyUriPermission(entry.getSbn(), data);
+        Intent fillInIntent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        RemoteInput.addDataResultToIntent(remoteInput, fillInIntent, results);
+
+        return fillInIntent;
+    }
+
+    // TODO: Copied from RemoteInputView. Consolidate RemoteInput intent logic.
+    private void sendRemoteInput(Intent intent, NotificationEntry entry,
+            PendingIntent pendingIntent) {
+        // Tell ShortcutManager that this package has been "activated".  ShortcutManager
+        // will reset the throttling for this package.
+        // Strictly speaking, the intent receiver may be different from the notification publisher,
+        // but that's an edge case, and also because we can't always know which package will receive
+        // an intent, so we just reset for the publisher.
+        mContext.getSystemService(ShortcutManager.class).onApplicationActive(
+                entry.getSbn().getPackageName(),
+                entry.getSbn().getUser().getIdentifier());
+
+        try {
+            pendingIntent.send(mContext, 0, intent);
+        } catch (PendingIntent.CanceledException e) {
+            Log.i(TAG, "Unable to send remote input result", e);
+        }
+    }
+
+    private void sendScreenshotToBubble(Bubble bubble) {
+        // delay allows the bubble menu to disappear before the screenshot
+        // done here because we already have a Handler to delay with.
+        // TODO: Hide bubble + menu UI from screenshots entirely instead of just delaying.
+        mHandler.postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                mScreenshotHelper.takeScreenshot(
+                        android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN,
+                        true /* hasStatus */,
+                        true /* hasNav */,
+                        mHandler,
+                        new Consumer<Uri>() {
+                            @Override
+                            public void accept(Uri uri) {
+                                if (uri != null) {
+                                    NotificationEntry entry = bubble.getEntry();
+                                    Pair<RemoteInput, Notification.Action> pair = entry.getSbn()
+                                            .getNotification().findRemoteInputActionPair(false);
+                                    RemoteInput remoteInput = pair.first;
+                                    Notification.Action action = pair.second;
+                                    Intent dataIntent = prepareRemoteInputFromData("image/png", uri,
+                                            remoteInput, entry);
+                                    sendRemoteInput(dataIntent, entry, action.actionIntent);
+                                    mBubbleData.setSelectedBubble(bubble);
+                                    mBubbleData.setExpanded(true);
+                                }
+                            }
+                        });
+            }
+        }, 200);
+    }
+
+    private final BubbleScreenshotListener mBubbleScreenshotListener =
+            bubble -> sendScreenshotToBubble(bubble);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index 2ca993b..034bff3 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -210,8 +210,8 @@
             setSelectedBubbleInternal(bubble);
         }
         boolean isBubbleExpandedAndSelected = mExpanded && mSelectedBubble == bubble;
-        bubble.setShowInShadeWhenBubble(!isBubbleExpandedAndSelected && showInShade);
-        bubble.setShowBubbleDot(!isBubbleExpandedAndSelected);
+        bubble.setShowInShade(!isBubbleExpandedAndSelected && showInShade);
+        bubble.setShowDot(!isBubbleExpandedAndSelected /* show */, true /* animate */);
         dispatchPendingChanges();
     }
 
@@ -303,9 +303,8 @@
         if (notif.getRanking().visuallyInterruptive()) {
             return true;
         }
-        final boolean suppressedFromShade = hasBubbleWithKey(notif.getKey())
-                && !getBubbleWithKey(notif.getKey()).showInShadeWhenBubble();
-        return suppressedFromShade;
+        return hasBubbleWithKey(notif.getKey())
+                && !getBubbleWithKey(notif.getKey()).showInShade();
     }
 
     private void doAdd(Bubble bubble) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java
index b702d06..a912ecc 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java
@@ -37,5 +37,6 @@
     static final boolean DEBUG_BUBBLE_DATA = false;
     static final boolean DEBUG_BUBBLE_STACK_VIEW = false;
     static final boolean DEBUG_BUBBLE_EXPANDED_VIEW = false;
+    static final boolean DEBUG_EXPERIMENTS = true;
 
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index e9c19d2..efc955d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -31,15 +31,12 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Color;
 import android.graphics.Insets;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
 import android.graphics.drawable.ShapeDrawable;
 import android.os.RemoteException;
 import android.service.notification.StatusBarNotification;
@@ -102,9 +99,7 @@
     private int mExpandedViewTouchSlop;
 
     private Bubble mBubble;
-    private PackageManager mPm;
     private String mAppName;
-    private Drawable mAppIcon;
 
     private BubbleController mBubbleController = Dependency.get(BubbleController.class);
     private WindowManager mWindowManager;
@@ -130,12 +125,17 @@
                             Log.d(TAG, "onActivityViewReady: calling startActivity, "
                                     + "bubble=" + getBubbleKey());
                         }
-                        Intent fillInIntent = new Intent();
-                        // Apply flags to make behaviour match documentLaunchMode=always.
-                        fillInIntent.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT);
-                        fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
                         try {
-                            mActivityView.startActivity(mBubbleIntent, fillInIntent, options);
+                            if (mBubble.usingShortcutInfo()) {
+                                mActivityView.startShortcutActivity(mBubble.getShortcutInfo(),
+                                        options, null /* sourceBounds */);
+                            } else {
+                                Intent fillInIntent = new Intent();
+                                // Apply flags to make behaviour match documentLaunchMode=always.
+                                fillInIntent.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT);
+                                fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
+                                mActivityView.startActivity(mBubbleIntent, fillInIntent, options);
+                            }
                         } catch (RuntimeException e) {
                             // If there's a runtime exception here then there's something
                             // wrong with the intent, we can't really recover / try to populate
@@ -184,12 +184,10 @@
                         + " mActivityViewStatus=" + mActivityViewStatus
                         + " bubble=" + getBubbleKey());
             }
-            if (mBubble != null && !mBubble.isUserCreated()) {
-                if (mBubble != null) {
-                    // Must post because this is called from a binder thread.
-                    post(() -> mBubbleController.removeBubble(mBubble.getKey(),
-                            BubbleController.DISMISS_TASK_FINISHED));
-                }
+            if (mBubble != null && !mBubbleController.isUserCreatedBubble(mBubble.getKey())) {
+                // Must post because this is called from a binder thread.
+                post(() -> mBubbleController.removeBubble(mBubble.getKey(),
+                        BubbleController.DISMISS_TASK_FINISHED));
             }
         }
     };
@@ -209,7 +207,6 @@
     public BubbleExpandedView(Context context, AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        mPm = context.getPackageManager();
         mDisplaySize = new Point();
         mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
         // Get the real size -- this includes screen decorations (notches, statusbar, navbar).
@@ -347,29 +344,14 @@
     /**
      * Sets the bubble used to populate this view.
      */
-    public void setBubble(Bubble bubble, BubbleStackView stackView, String appName) {
+    public void setBubble(Bubble bubble, BubbleStackView stackView) {
         if (DEBUG_BUBBLE_EXPANDED_VIEW) {
             Log.d(TAG, "setBubble: bubble=" + (bubble != null ? bubble.getKey() : "null"));
         }
-
         mStackView = stackView;
         mBubble = bubble;
-        mAppName = appName;
+        mAppName = bubble.getAppName();
 
-        try {
-            ApplicationInfo info = mPm.getApplicationInfo(
-                    bubble.getPackageName(),
-                    PackageManager.MATCH_UNINSTALLED_PACKAGES
-                            | PackageManager.MATCH_DISABLED_COMPONENTS
-                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
-                            | PackageManager.MATCH_DIRECT_BOOT_AWARE);
-            mAppIcon = mPm.getApplicationIcon(info);
-        } catch (PackageManager.NameNotFoundException e) {
-            // Do nothing.
-        }
-        if (mAppIcon == null) {
-            mAppIcon = mPm.getDefaultActivityIcon();
-        }
         applyThemeAttrs();
         showSettingsIcon();
         updateExpandedView();
@@ -415,7 +397,7 @@
                     + getBubbleKey());
         }
 
-        mBubbleIntent = mBubble.getBubbleIntent(mContext);
+        mBubbleIntent = mBubble.getBubbleIntent();
         if (mBubbleIntent != null) {
             setContentVisibility(false);
             mActivityView.setVisibility(VISIBLE);
@@ -621,7 +603,7 @@
                 action,
                 mStackView.getNormalizedXPosition(),
                 mStackView.getNormalizedYPosition(),
-                bubble.showInShadeWhenBubble(),
+                bubble.showInShade(),
                 bubble.isOngoing(),
                 false /* isAppForeground (unused) */);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
index b478a72..8299f22 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
@@ -16,32 +16,67 @@
 
 package com.android.systemui.bubbles;
 
+import static android.app.Notification.EXTRA_MESSAGES;
+import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC;
+import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_MANIFEST;
+import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED;
+
+import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_EXPERIMENTS;
+import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+
 import android.app.Notification;
 import android.app.PendingIntent;
+import android.app.Person;
 import android.content.Context;
+import android.content.Intent;
+import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutInfo;
 import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.os.UserHandle;
 import android.provider.Settings;
+import android.util.Log;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
 /**
  * Common class for experiments controlled via secure settings.
  */
 public class BubbleExperimentConfig {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleController" : TAG_BUBBLES;
+
+    private static final String SHORTCUT_DUMMY_INTENT = "bubble_experiment_shortcut_intent";
+    private static PendingIntent sDummyShortcutIntent;
+
+    private static final int BUBBLE_HEIGHT = 10000;
 
     private static final String ALLOW_ANY_NOTIF_TO_BUBBLE = "allow_any_notif_to_bubble";
     private static final boolean ALLOW_ANY_NOTIF_TO_BUBBLE_DEFAULT = false;
 
     private static final String ALLOW_MESSAGE_NOTIFS_TO_BUBBLE = "allow_message_notifs_to_bubble";
-    private static final boolean ALLOW_MESSAGE_NOTIFS_TO_BUBBLE_DEFAULT = false;
+    private static final boolean ALLOW_MESSAGE_NOTIFS_TO_BUBBLE_DEFAULT = true;
+
+    private static final String ALLOW_SHORTCUTS_TO_BUBBLE = "allow_shortcuts_to_bubble";
+    private static final boolean ALLOW_SHORTCUT_TO_BUBBLE_DEFAULT = false;
+
+    private static final String WHITELISTED_AUTO_BUBBLE_APPS = "whitelisted_auto_bubble_apps";
+
+    private static final String ALLOW_BUBBLE_MENU = "allow_bubble_screenshot_menu";
+    private static final boolean ALLOW_BUBBLE_MENU_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}
      * object will be created by the system and added to the notification.
-     *
-     * This does not produce a bubble, only adds the metadata. It should be used in conjunction
-     * with {@see #allowNotifBubbleMenu} which shows an affordance to bubble notification content.
+     * <p>
+     * This does not produce a bubble, only adds the metadata based on the notification info.
      */
     static boolean allowAnyNotifToBubble(Context context) {
         return Settings.Secure.getInt(context.getContentResolver(),
@@ -60,16 +95,59 @@
     }
 
     /**
+     * When true, if the notification is able to bubble via {@link #allowAnyNotifToBubble(Context)}
+     * or {@link #allowMessageNotifsToBubble(Context)} or via normal BubbleMetadata, then a new
+     * BubbleMetadata object is constructed based on the shortcut info.
+     * <p>
+     * This does not produce a bubble, only adds the metadata based on shortcut info.
+     */
+    static boolean useShortcutInfoToBubble(Context context) {
+        return Settings.Secure.getInt(context.getContentResolver(),
+                ALLOW_SHORTCUTS_TO_BUBBLE,
+                ALLOW_SHORTCUT_TO_BUBBLE_DEFAULT ? 1 : 0) != 0;
+    }
+
+    /**
+     * Returns whether the provided package is whitelisted to bubble.
+     */
+    static boolean isPackageWhitelistedToAutoBubble(Context context, String packageName) {
+        String unsplitList = Settings.Secure.getString(context.getContentResolver(),
+                WHITELISTED_AUTO_BUBBLE_APPS);
+        if (unsplitList != null) {
+            // We expect the list to be separated by commas and no white space (but we trim in case)
+            String[] packageList = unsplitList.split(",");
+            for (int i = 0; i < packageList.length; i++) {
+                if (packageList[i].trim().equals(packageName)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * When true, show a menu when a bubble is long-pressed, which will allow the user to take
+     * actions on that bubble.
+     */
+    static boolean allowBubbleScreenshotMenu(Context context) {
+        return Settings.Secure.getInt(context.getContentResolver(),
+                ALLOW_BUBBLE_MENU,
+                ALLOW_BUBBLE_MENU_DEFAULT ? 1 : 0) != 0;
+    }
+
+    /**
      * If {@link #allowAnyNotifToBubble(Context)} is true, this method creates and adds
      * {@link android.app.Notification.BubbleMetadata} to the notification entry as long as
      * the notification has necessary info for BubbleMetadata.
+     *
+     * @return whether an adjustment was made.
      */
-    static void adjustForExperiments(Context context, NotificationEntry entry,
-            Bubble previousBubble) {
-        if (entry.getBubbleMetadata() != null) {
-            // Has metadata, nothing to do.
-            return;
-        }
+    static boolean adjustForExperiments(Context context, NotificationEntry entry,
+            boolean previouslyUserCreated) {
+        Notification.BubbleMetadata metadata = null;
+        boolean addedMetadata = false;
+        boolean whiteListedToAutoBubble =
+                isPackageWhitelistedToAutoBubble(context, entry.getSbn().getPackageName());
 
         Notification notification = entry.getSbn().getNotification();
         boolean isMessage = Notification.MessagingStyle.class.equals(
@@ -77,22 +155,157 @@
         boolean bubbleNotifForExperiment = (isMessage && allowMessageNotifsToBubble(context))
                 || allowAnyNotifToBubble(context);
 
-        final PendingIntent intent = notification.contentIntent;
-        if (bubbleNotifForExperiment
-                && BubbleController.canLaunchIntentInActivityView(context, entry, intent)) {
-            final Icon smallIcon = entry.getSbn().getNotification().getSmallIcon();
-            Notification.BubbleMetadata.Builder metadata =
-                    new Notification.BubbleMetadata.Builder()
-                            .setDesiredHeight(10000)
-                            .setIcon(smallIcon)
-                            .setIntent(intent);
-            entry.setBubbleMetadata(metadata.build());
+        boolean useShortcutInfo = useShortcutInfoToBubble(context);
+        String shortcutId = entry.getSbn().getNotification().getShortcutId();
+
+        boolean hasMetadata = entry.getBubbleMetadata() != null;
+        if ((!hasMetadata && (previouslyUserCreated || bubbleNotifForExperiment))
+                || useShortcutInfo) {
+            if (DEBUG_EXPERIMENTS) {
+                Log.d(TAG, "Adjusting " + entry.getKey() + " for bubble experiment."
+                        + " allowMessages=" + allowMessageNotifsToBubble(context)
+                        + " isMessage=" + isMessage
+                        + " allowNotifs=" + allowAnyNotifToBubble(context)
+                        + " useShortcutInfo=" + useShortcutInfo
+                        + " previouslyUserCreated=" + previouslyUserCreated);
+            }
         }
 
-        if (previousBubble != null) {
-            // Update to a previously user-created bubble, set its flag now so the update goes
-            // to the bubble.
-            entry.setFlagBubble(true);
+        if (useShortcutInfo && shortcutId != null) {
+            // We don't actually get anything useful from ShortcutInfo so just check existence
+            ShortcutInfo info = getShortcutInfo(context, entry.getSbn().getPackageName(),
+                    entry.getSbn().getUser(), shortcutId);
+            if (info != null) {
+                metadata = createForShortcut(context, entry);
+            }
+
+            // Replace existing metadata with shortcut, or we're bubbling for experiment
+            boolean shouldBubble = entry.getBubbleMetadata() != null
+                    || bubbleNotifForExperiment
+                    || previouslyUserCreated;
+            if (shouldBubble && metadata != null) {
+                if (DEBUG_EXPERIMENTS) {
+                    Log.d(TAG, "Adding experimental shortcut bubble for: " + entry.getKey());
+                }
+                entry.setBubbleMetadata(metadata);
+                addedMetadata = true;
+            }
         }
+
+        // Didn't get metadata from a shortcut & we're bubbling for experiment
+        if (entry.getBubbleMetadata() == null
+                && (bubbleNotifForExperiment || previouslyUserCreated)) {
+            metadata = createFromNotif(context, entry);
+            if (metadata != null) {
+                if (DEBUG_EXPERIMENTS) {
+                    Log.d(TAG, "Adding experimental notification bubble for: " + entry.getKey());
+                }
+                entry.setBubbleMetadata(metadata);
+                addedMetadata = true;
+            }
+        }
+
+        boolean bubbleForWhitelist = whiteListedToAutoBubble && (addedMetadata || hasMetadata);
+        if ((previouslyUserCreated && addedMetadata) || bubbleForWhitelist) {
+            // Update to a previous bubble (or new autobubble), set its flag now.
+            if (DEBUG_EXPERIMENTS) {
+                Log.d(TAG, "Setting FLAG_BUBBLE for: " + entry.getKey());
+            }
+            entry.setFlagBubble(true);
+            return true;
+        }
+        return addedMetadata;
+    }
+
+    static Notification.BubbleMetadata createFromNotif(Context context, NotificationEntry entry) {
+        Notification notification = entry.getSbn().getNotification();
+        final PendingIntent intent = notification.contentIntent;
+        Icon icon = null;
+        // Use the icon of the person if available
+        List<Person> personList = getPeopleFromNotification(entry);
+        if (personList.size() > 0) {
+            icon = personList.get(0).getIcon();
+        }
+        if (icon == null) {
+            icon = notification.getLargeIcon() != null
+                    ? notification.getLargeIcon()
+                    : notification.getSmallIcon();
+        }
+        if (intent != null) {
+            return new Notification.BubbleMetadata.Builder()
+                    .setDesiredHeight(BUBBLE_HEIGHT)
+                    .setIcon(icon)
+                    .setIntent(intent)
+                    .build();
+        }
+        return null;
+    }
+
+    static Notification.BubbleMetadata createForShortcut(Context context, NotificationEntry entry) {
+        // ShortcutInfo does not return an icon, instead a Drawable, lets just use
+        // notification icon for BubbleMetadata.
+        Icon icon = entry.getSbn().getNotification().getSmallIcon();
+
+        // ShortcutInfo does not return the intent, lets make a fake but identifiable
+        // intent so we can still add bubbleMetadata
+        if (sDummyShortcutIntent == null) {
+            Intent i = new Intent(SHORTCUT_DUMMY_INTENT);
+            sDummyShortcutIntent = PendingIntent.getActivity(context, 0, i,
+                    PendingIntent.FLAG_UPDATE_CURRENT);
+        }
+        return new Notification.BubbleMetadata.Builder()
+                .setDesiredHeight(BUBBLE_HEIGHT)
+                .setIcon(icon)
+                .setIntent(sDummyShortcutIntent)
+                .build();
+    }
+
+    static ShortcutInfo getShortcutInfo(Context context, String packageName, UserHandle user,
+            String shortcutId) {
+        LauncherApps launcherAppService =
+                (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
+        LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery();
+        if (packageName != null) {
+            query.setPackage(packageName);
+        }
+        if (shortcutId != null) {
+            query.setShortcutIds(Arrays.asList(shortcutId));
+        }
+        query.setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST);
+        List<ShortcutInfo> shortcuts = launcherAppService.getShortcuts(query, user);
+        return shortcuts != null && shortcuts.size() > 0
+                ? shortcuts.get(0)
+                : null;
+    }
+
+    static boolean isShortcutIntent(PendingIntent intent) {
+        return intent.equals(sDummyShortcutIntent);
+    }
+
+    static List<Person> getPeopleFromNotification(NotificationEntry entry) {
+        Bundle extras = entry.getSbn().getNotification().extras;
+        ArrayList<Person> personList = new ArrayList<>();
+        if (extras == null) {
+            return personList;
+        }
+
+        List<Person> p = extras.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST);
+
+        if (p != null) {
+            personList.addAll(p);
+        }
+
+        if (Notification.MessagingStyle.class.equals(
+                entry.getSbn().getNotification().getNotificationStyle())) {
+            final Parcelable[] messages = extras.getParcelableArray(EXTRA_MESSAGES);
+            if (!ArrayUtils.isEmpty(messages)) {
+                for (Notification.MessagingStyle.Message message :
+                        Notification.MessagingStyle.Message
+                                .getMessagesFromBundleArray(messages)) {
+                    personList.add(message.getSenderPerson());
+                }
+            }
+        }
+        return personList;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
index 58f3f22..78e98eb 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
@@ -206,7 +206,7 @@
     void setupFlyoutStartingAsDot(
             CharSequence updateMessage, PointF stackPos, float parentWidth,
             boolean arrowPointingLeft, int dotColor, @Nullable Runnable onLayoutComplete,
-            @Nullable Runnable onHide, float[] dotCenter) {
+            @Nullable Runnable onHide, float[] dotCenter, boolean hideDot) {
         mArrowPointingLeft = arrowPointingLeft;
         mDotColor = dotColor;
         mOnHide = onHide;
@@ -242,12 +242,14 @@
 
             // Calculate the difference in size between the flyout and the 'dot' so that we can
             // transform into the dot later.
-            mFlyoutToDotWidthDelta = getWidth() - mNewDotSize;
-            mFlyoutToDotHeightDelta = getHeight() - mNewDotSize;
+            final float newDotSize = hideDot ? 0f : mNewDotSize;
+            mFlyoutToDotWidthDelta = getWidth() - newDotSize;
+            mFlyoutToDotHeightDelta = getHeight() - newDotSize;
 
             // Calculate the translation values needed to be in the correct 'new dot' position.
-            final float dotPositionX = stackPos.x + mDotCenter[0] - (mOriginalDotSize / 2f);
-            final float dotPositionY = stackPos.y + mDotCenter[1] - (mOriginalDotSize / 2f);
+            final float adjustmentForScaleAway = hideDot ? 0f : (mOriginalDotSize / 2f);
+            final float dotPositionX = stackPos.x + mDotCenter[0] - adjustmentForScaleAway;
+            final float dotPositionY = stackPos.y + mDotCenter[1] - adjustmentForScaleAway;
 
             final float distanceFromFlyoutLeftToDotCenterX = mRestingTranslationX - dotPositionX;
             final float distanceFromLayoutTopToDotCenterY = restingTranslationY - dotPositionY;
@@ -319,8 +321,7 @@
         // percentage.
         final float width = getWidth() - (mFlyoutToDotWidthDelta * mPercentTransitionedToDot);
         final float height = getHeight() - (mFlyoutToDotHeightDelta * mPercentTransitionedToDot);
-        final float interpolatedRadius = mNewDotRadius * mPercentTransitionedToDot
-                + mCornerRadius * (1 - mPercentTransitionedToDot);
+        final float interpolatedRadius = getInterpolatedRadius();
 
         // Translate the flyout background towards the collapsed 'dot' state.
         mBgTranslationX = mTranslationXWhenDot * mPercentTransitionedToDot;
@@ -387,8 +388,7 @@
         if (!mTriangleOutline.isEmpty()) {
             // Draw the rect into the outline as a path so we can merge the triangle path into it.
             final Path rectPath = new Path();
-            final float interpolatedRadius = mNewDotRadius * mPercentTransitionedToDot
-                    + mCornerRadius * (1 - mPercentTransitionedToDot);
+            final float interpolatedRadius = getInterpolatedRadius();
             rectPath.addRoundRect(mBgRect, interpolatedRadius,
                     interpolatedRadius, Path.Direction.CW);
             outline.setConvexPath(rectPath);
@@ -420,4 +420,9 @@
             outline.mPath.transform(outlineMatrix);
         }
     }
+
+    private float getInterpolatedRadius() {
+        return mNewDotRadius * mPercentTransitionedToDot
+                + mCornerRadius * (1 - mPercentTransitionedToDot);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
index a1c77c0..9ff033c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
@@ -16,8 +16,14 @@
 package com.android.systemui.bubbles;
 
 import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
 
 import com.android.launcher3.icons.BaseIconFactory;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.icons.ShadowGenerator;
 import com.android.systemui.R;
 
 /**
@@ -26,13 +32,37 @@
  * so there is no need to manage a pool across multiple threads.
  */
 public class BubbleIconFactory extends BaseIconFactory {
+
     protected BubbleIconFactory(Context context) {
         super(context, context.getResources().getConfiguration().densityDpi,
                 context.getResources().getDimensionPixelSize(R.dimen.individual_bubble_size));
     }
 
-    public int getBadgeSize() {
+    int getBadgeSize() {
         return mContext.getResources().getDimensionPixelSize(
                 com.android.launcher3.icons.R.dimen.profile_badge_size);
     }
+
+    BitmapInfo getBadgedBitmap(Bubble b) {
+        Bitmap userBadgedBitmap = createIconBitmap(
+                b.getUserBadgedAppIcon(), 1f, getBadgeSize());
+
+        Canvas c = new Canvas();
+        ShadowGenerator shadowGenerator = new ShadowGenerator(getBadgeSize());
+        c.setBitmap(userBadgedBitmap);
+        shadowGenerator.recreateIcon(Bitmap.createBitmap(userBadgedBitmap), c);
+        BitmapInfo bitmapInfo = createIconBitmap(userBadgedBitmap);
+        return bitmapInfo;
+    }
+
+    BitmapInfo getBubbleBitmap(Drawable bubble, BitmapInfo badge) {
+        BitmapInfo bubbleIconInfo = createBadgedIconBitmap(bubble,
+                null /* user */,
+                true /* shrinkNonAdaptiveIcons */);
+
+        badgeWithDrawable(bubbleIconInfo.icon,
+                new BitmapDrawable(mContext.getResources(), badge.icon));
+        return bubbleIconInfo;
+    }
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleMenuView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleMenuView.java
new file mode 100644
index 0000000..e8eb72e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleMenuView.java
@@ -0,0 +1,81 @@
+/*
+ * 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.systemui.bubbles;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+
+/**
+ * Menu which allows users to take actions on bubbles, ex. screenshots.
+ */
+public class BubbleMenuView extends FrameLayout {
+    private FrameLayout mMenu;
+    private boolean mShowing = false;
+
+    public BubbleMenuView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public BubbleMenuView(Context context) {
+        super(context);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mMenu = findViewById(R.id.bubble_menu_view);
+        ImageView icon = findViewById(com.android.internal.R.id.icon);
+        icon.setImageDrawable(mContext.getDrawable(com.android.internal.R.drawable.ic_screenshot));
+    }
+
+    /**
+     * Get the bubble menu view.
+     */
+    public View getMenuView() {
+        return mMenu;
+    }
+
+    /**
+     * Checks whether the bubble menu is currently displayed.
+     */
+    public boolean isShowing() {
+        return mShowing;
+    }
+
+    /**
+     * Show the bubble menu at the specified position on the screen.
+     */
+    public void show(float x, float y) {
+        mShowing = true;
+        this.setVisibility(VISIBLE);
+        mMenu.setTranslationX(x);
+        mMenu.setTranslationY(y);
+    }
+
+    /**
+     * Hide the bubble menu.
+     */
+    public void hide() {
+        mShowing = false;
+        this.setVisibility(GONE);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 4a1bbe4..29a4bb1 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -19,6 +19,8 @@
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
+import static com.android.systemui.bubbles.BadgedImageView.DOT_STATE_DEFAULT;
+import static com.android.systemui.bubbles.BadgedImageView.DOT_STATE_SUPPRESSED_FOR_FLYOUT;
 import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_STACK_VIEW;
 import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
 import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
@@ -108,6 +110,7 @@
     /** How long to wait, in milliseconds, before hiding the flyout. */
     @VisibleForTesting
     static final int FLYOUT_HIDE_AFTER = 5000;
+    private BubbleController.BubbleScreenshotListener mBubbleScreenshotListener;
 
     /**
      * Interface to synchronize {@link View} state and the screen.
@@ -161,6 +164,7 @@
     private ExpandedAnimationController mExpandedAnimationController;
 
     private FrameLayout mExpandedViewContainer;
+    @Nullable private BubbleMenuView mBubbleMenuView;
 
     private BubbleFlyoutView mFlyout;
     /** Runnable that fades out the flyout and then sets it to GONE. */
@@ -169,7 +173,7 @@
      * Callback to run after the flyout hides. Also called if a new flyout is shown before the
      * previous one animates out.
      */
-    private Runnable mFlyoutOnHide;
+    private Runnable mAfterFlyoutHidden;
 
     /** Layout change listener that moves the stack to the nearest valid position on rotation. */
     private OnLayoutChangeListener mOrientationChangedListener;
@@ -192,6 +196,7 @@
     private int mPointerHeight;
     private int mStatusBarHeight;
     private int mImeOffset;
+    private int mBubbleMenuOffset = 252;
     private BubbleIconFactory mBubbleIconFactory;
     private Bubble mExpandedBubble;
     private boolean mIsExpanded;
@@ -490,6 +495,9 @@
             mDesaturateAndDarkenPaint.setColorFilter(new ColorMatrixColorFilter(animatedMatrix));
             mDesaturateAndDarkenTargetView.setLayerPaint(mDesaturateAndDarkenPaint);
         });
+
+        mInflater.inflate(R.layout.bubble_menu_view, this);
+        mBubbleMenuView = findViewById(R.id.bubble_menu_container);
     }
 
     private void setUpFlyout() {
@@ -674,18 +682,6 @@
     }
 
     /**
-     * Updates the visibility of the 'dot' indicating an update on the bubble.
-     *
-     * @param key the {@link NotificationEntry#key} associated with the bubble.
-     */
-    public void updateDotVisibility(String key) {
-        Bubble b = mBubbleData.getBubbleWithKey(key);
-        if (b != null) {
-            b.updateDotVisibility();
-        }
-    }
-
-    /**
      * Sets the listener to notify when the bubble stack is expanded.
      */
     public void setExpandListener(BubbleController.BubbleExpandListener listener) {
@@ -693,6 +689,13 @@
     }
 
     /**
+     * Sets the screenshot listener.
+     */
+    public void setBubbleScreenshotListener(BubbleController.BubbleScreenshotListener listener) {
+        mBubbleScreenshotListener = listener;
+    }
+
+    /**
      * Whether the stack of bubbles is expanded or not.
      */
     public boolean isExpanded() {
@@ -707,9 +710,9 @@
     }
 
     /**
-     * The {@link BubbleView} that is expanded, null if one does not exist.
+     * The {@link BadgedImageView} that is expanded, null if one does not exist.
      */
-    BubbleView getExpandedBubbleView() {
+    BadgedImageView getExpandedBubbleView() {
         return mExpandedBubble != null ? mExpandedBubble.getIconView() : null;
     }
 
@@ -731,7 +734,7 @@
         Bubble bubbleToExpand = mBubbleData.getBubbleWithKey(key);
         if (bubbleToExpand != null) {
             setSelectedBubble(bubbleToExpand);
-            bubbleToExpand.setShowInShadeWhenBubble(false);
+            bubbleToExpand.setShowInShade(false);
             setExpanded(true);
         }
     }
@@ -746,8 +749,8 @@
             mStackOnLeftOrWillBe = mStackAnimationController.isStackOnLeftSide();
         }
 
+        bubble.setBubbleIconFactory(mBubbleIconFactory);
         bubble.inflate(mInflater, this);
-        bubble.getIconView().setBubbleIconFactory(mBubbleIconFactory);
         bubble.getIconView().updateViews();
 
         // Set the dot position to the opposite of the side the stack is resting on, since the stack
@@ -880,11 +883,17 @@
     public View getTargetView(MotionEvent event) {
         float x = event.getRawX();
         float y = event.getRawY();
+        if (mBubbleMenuView.isShowing()) {
+            if (isIntersecting(mBubbleMenuView.getMenuView(), x, y)) {
+                return mBubbleMenuView;
+            }
+            return null;
+        }
         if (mIsExpanded) {
             if (isIntersecting(mBubbleContainer, x, y)) {
                 // Could be tapping or dragging a bubble while expanded
                 for (int i = 0; i < mBubbleContainer.getChildCount(); i++) {
-                    BubbleView view = (BubbleView) mBubbleContainer.getChildAt(i);
+                    BadgedImageView view = (BadgedImageView) mBubbleContainer.getChildAt(i);
                     if (isIntersecting(view, x, y)) {
                         return view;
                     }
@@ -1028,9 +1037,9 @@
     }
 
     /** Return the BubbleView at the given index from the bubble container. */
-    public BubbleView getBubbleAt(int i) {
+    public BadgedImageView getBubbleAt(int i) {
         return mBubbleContainer.getChildCount() > i
-                ? (BubbleView) mBubbleContainer.getChildAt(i)
+                ? (BadgedImageView) mBubbleContainer.getChildAt(i)
                 : null;
     }
 
@@ -1084,6 +1093,7 @@
             return;
         }
 
+        hideBubbleMenu();
         mStackAnimationController.cancelStackPositionAnimations();
         mBubbleContainer.setActiveController(mStackAnimationController);
         hideFlyoutImmediate();
@@ -1382,16 +1392,6 @@
                         : 0f);
     }
 
-    /** Updates the dot visibility, this is used in response to a zen mode config change. */
-    void updateDots() {
-        int bubbsCount = mBubbleContainer.getChildCount();
-        for (int i = 0; i < bubbsCount; i++) {
-            BubbleView bv = (BubbleView) mBubbleContainer.getChildAt(i);
-            // If nothing changed the animation won't happen
-            bv.updateDotVisibility(true /* animate */);
-        }
-    }
-
     /**
      * Calculates the y position of the expanded view when it is expanded.
      */
@@ -1405,37 +1405,40 @@
     @VisibleForTesting
     void animateInFlyoutForBubble(Bubble bubble) {
         final CharSequence updateMessage = bubble.getUpdateMessage(getContext());
-        if (!bubble.showFlyoutForBubble()) {
-            // In case flyout was suppressed for this update, reset now.
-            bubble.setSuppressFlyout(false);
-            return;
-        }
+        final BadgedImageView bubbleView = bubble.getIconView();
         if (updateMessage == null
+                || !bubble.showFlyout()
                 || isExpanded()
                 || mIsExpansionAnimating
                 || mIsGestureInProgress
                 || mBubbleToExpandAfterFlyoutCollapse != null
-                || bubble.getIconView() == null) {
+                || bubbleView == null) {
+            if (bubbleView != null) {
+                bubbleView.setDotState(DOT_STATE_DEFAULT);
+            }
             // Skip the message if none exists, we're expanded or animating expansion, or we're
             // about to expand a bubble from the previous tapped flyout, or if bubble view is null.
             return;
         }
+
         mFlyoutDragDeltaX = 0f;
         clearFlyoutOnHide();
-        mFlyoutOnHide = () -> {
-            resetDot(bubble);
-            if (mBubbleToExpandAfterFlyoutCollapse == null) {
-                return;
+        mAfterFlyoutHidden = () -> {
+            // Null it out to ensure it runs once.
+            mAfterFlyoutHidden = null;
+
+            if (mBubbleToExpandAfterFlyoutCollapse != null) {
+                // User tapped on the flyout and we should expand
+                mBubbleData.setSelectedBubble(mBubbleToExpandAfterFlyoutCollapse);
+                mBubbleData.setExpanded(true);
+                mBubbleToExpandAfterFlyoutCollapse = null;
             }
-            mBubbleData.setSelectedBubble(mBubbleToExpandAfterFlyoutCollapse);
-            mBubbleData.setExpanded(true);
-            mBubbleToExpandAfterFlyoutCollapse = null;
+            bubbleView.setDotState(DOT_STATE_DEFAULT);
         };
         mFlyout.setVisibility(INVISIBLE);
 
-        // Temporarily suppress the dot while the flyout is visible.
-        bubble.getIconView().setSuppressDot(
-                true /* suppressDot */, false /* animate */);
+        // Don't show the dot when we're animating the flyout
+        bubbleView.setDotState(DOT_STATE_SUPPRESSED_FOR_FLYOUT);
 
         // Start flyout expansion. Post in case layout isn't complete and getWidth returns 0.
         post(() -> {
@@ -1461,8 +1464,9 @@
                     mStackAnimationController.isStackOnLeftSide(),
                     bubble.getIconView().getDotColor() /* dotColor */,
                     expandFlyoutAfterDelay /* onLayoutComplete */,
-                    mFlyoutOnHide,
-                    bubble.getIconView().getDotCenter());
+                    mAfterFlyoutHidden,
+                    bubble.getIconView().getDotCenter(),
+                    !bubble.showDot());
             mFlyout.bringToFront();
         });
         mFlyout.removeCallbacks(mHideFlyout);
@@ -1470,24 +1474,6 @@
         logBubbleEvent(bubble, StatsLog.BUBBLE_UICHANGED__ACTION__FLYOUT);
     }
 
-    private void resetDot(Bubble bubble) {
-        final boolean suppressDot = !bubble.showBubbleDot();
-        // If we're going to suppress the dot, make it visible first so it'll
-        // visibly animate away.
-
-        if (suppressDot) {
-            bubble.getIconView().setSuppressDot(
-                    false /* suppressDot */, false /* animate */);
-        }
-        // Reset dot suppression. If we're not suppressing due to DND, then
-        // stop suppressing it with no animation (since the flyout has
-        // transformed into the dot). If we are suppressing due to DND, animate
-        // it away.
-        bubble.getIconView().setSuppressDot(
-                suppressDot /* suppressDot */,
-                suppressDot /* animate */);
-    }
-
     /** Hide the flyout immediately and cancel any pending hide runnables. */
     private void hideFlyoutImmediate() {
         clearFlyoutOnHide();
@@ -1498,15 +1484,20 @@
 
     private void clearFlyoutOnHide() {
         mFlyout.removeCallbacks(mAnimateInFlyout);
-        if (mFlyoutOnHide == null) {
+        if (mAfterFlyoutHidden == null) {
             return;
         }
-        mFlyoutOnHide.run();
-        mFlyoutOnHide = null;
+        mAfterFlyoutHidden.run();
+        mAfterFlyoutHidden = null;
     }
 
     @Override
     public void getBoundsOnScreen(Rect outRect) {
+        // If the bubble menu is open, the entire screen should capture touch events.
+        if (mBubbleMenuView.isShowing()) {
+            outRect.set(0, 0, getWidth(), getHeight());
+            return;
+        }
         if (!mIsExpanded) {
             if (mBubbleContainer.getChildCount() > 0) {
                 mBubbleContainer.getChildAt(0).getBoundsOnScreen(outRect);
@@ -1599,8 +1590,7 @@
     private void updateBubbleZOrdersAndDotPosition(boolean animate) {
         int bubbleCount = mBubbleContainer.getChildCount();
         for (int i = 0; i < bubbleCount; i++) {
-            BubbleView bv = (BubbleView) mBubbleContainer.getChildAt(i);
-            bv.updateDotVisibility(true /* animate */);
+            BadgedImageView bv = (BadgedImageView) mBubbleContainer.getChildAt(i);
             bv.setZ((mMaxBubbles * mBubbleElevation) - i);
             // If the dot is on the left, and so is the stack, we need to change the dot position.
             if (bv.getDotPositionOnLeft() == mStackOnLeftOrWillBe) {
@@ -1705,7 +1695,7 @@
                     action,
                     getNormalizedXPosition(),
                     getNormalizedYPosition(),
-                    bubble.showInShadeWhenBubble(),
+                    bubble.showInShade(),
                     bubble.isOngoing(),
                     false /* isAppForeground (unused) */);
         }
@@ -1727,12 +1717,51 @@
         List<Bubble> bubbles = new ArrayList<>();
         for (int i = 0; i < mBubbleContainer.getChildCount(); i++) {
             View child = mBubbleContainer.getChildAt(i);
-            if (child instanceof BubbleView) {
-                String key = ((BubbleView) child).getKey();
+            if (child instanceof BadgedImageView) {
+                String key = ((BadgedImageView) child).getKey();
                 Bubble bubble = mBubbleData.getBubbleWithKey(key);
                 bubbles.add(bubble);
             }
         }
         return bubbles;
     }
+
+    /**
+     * Show the bubble menu, positioned relative to the stack.
+     */
+    public void showBubbleMenu() {
+        PointF currentPos = mStackAnimationController.getStackPosition();
+        float yPos = currentPos.y;
+        float xPos = currentPos.x;
+        if (mStackAnimationController.isStackOnLeftSide()) {
+            xPos += mBubbleSize;
+        } else {
+            //TODO: Use the width of the menu instead of this fixed offset. Offset used for now
+            // because menu width isn't correct the first time the menu is shown.
+            xPos -= mBubbleMenuOffset;
+        }
+
+        mBubbleMenuView.show(xPos, yPos);
+    }
+
+    /**
+     * Hide the bubble menu.
+     */
+    public void hideBubbleMenu() {
+        mBubbleMenuView.hide();
+    }
+
+    /**
+     * Determines whether the bubble menu is currently showing.
+     */
+    public boolean isShowingBubbleMenu() {
+        return mBubbleMenuView.isShowing();
+    }
+
+    /**
+     * Take a screenshot and send it to the specified bubble.
+     */
+    public void sendScreenshotToBubble(Bubble bubble) {
+        mBubbleScreenshotListener.onBubbleScreenshot(bubble);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
index 4240e06..b1d205c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
@@ -57,6 +57,7 @@
     private final PointF mViewPositionOnTouchDown = new PointF();
     private final BubbleStackView mStack;
     private final BubbleData mBubbleData;
+    private final Context mContext;
 
     private BubbleController mController = Dependency.get(BubbleController.class);
 
@@ -75,6 +76,7 @@
         mTouchSlopSquared = touchSlop * touchSlop;
         mBubbleData = bubbleData;
         mStack = stackView;
+        mContext = context;
     }
 
     @Override
@@ -91,15 +93,24 @@
         // anything, collapse the stack.
         if (action == MotionEvent.ACTION_OUTSIDE || mTouchedView == null) {
             mBubbleData.setExpanded(false);
+            mStack.hideBubbleMenu();
             resetForNextGesture();
             return false;
         }
 
-        if (!(mTouchedView instanceof BubbleView)
+        if (mTouchedView instanceof BubbleMenuView) {
+            mStack.hideBubbleMenu();
+            resetForNextGesture();
+            mStack.sendScreenshotToBubble(mBubbleData.getSelectedBubble());
+            return false;
+        }
+
+        if (!(mTouchedView instanceof BadgedImageView)
                 && !(mTouchedView instanceof BubbleStackView)
                 && !(mTouchedView instanceof BubbleFlyoutView)) {
             // Not touching anything touchable, but we shouldn't collapse (e.g. touching edge
             // of expanded view).
+            mStack.hideBubbleMenu();
             resetForNextGesture();
             return false;
         }
@@ -132,6 +143,10 @@
 
                 break;
             case MotionEvent.ACTION_MOVE:
+                // block all further touch inputs once the menu is open
+                if (mStack.isShowingBubbleMenu()) {
+                    return true;
+                }
                 trackMovement(event);
                 final float deltaX = rawX - mTouchDown.x;
                 final float deltaY = rawY - mTouchDown.y;
@@ -148,6 +163,13 @@
                     } else {
                         mStack.onBubbleDragged(mTouchedView, viewX, viewY);
                     }
+                } else {
+                    float touchTime = event.getEventTime() - event.getDownTime();
+                    if (touchTime > ViewConfiguration.getLongPressTimeout() && !mStack.isExpanded()
+                            && BubbleExperimentConfig.allowBubbleScreenshotMenu(mContext)) {
+                        mStack.showBubbleMenu();
+                        return true;
+                    }
                 }
 
                 final boolean currentlyInDismissTarget = mStack.isInDismissTarget(event);
@@ -171,6 +193,10 @@
                 break;
 
             case MotionEvent.ACTION_UP:
+                if (mStack.isShowingBubbleMenu()) {
+                    resetForNextGesture();
+                    return true;
+                }
                 trackMovement(event);
                 mVelocityTracker.computeCurrentVelocity(/* maxVelocity */ 1000);
                 final float velX = mVelocityTracker.getXVelocity();
@@ -187,7 +213,7 @@
                     mStack.onFlyoutDragFinished(rawX - mTouchDown.x /* deltaX */, velX);
                 } else if (shouldDismiss) {
                     final String individualBubbleKey =
-                            isStack ? null : ((BubbleView) mTouchedView).getKey();
+                            isStack ? null : ((BadgedImageView) mTouchedView).getKey();
                     mStack.magnetToStackIfNeededThenAnimateDismissal(mTouchedView, velX, velY,
                             () -> {
                                 if (isStack) {
@@ -214,7 +240,7 @@
                     // Toggle expansion
                     mBubbleData.setExpanded(!mBubbleData.isExpanded());
                 } else {
-                    final String key = ((BubbleView) mTouchedView).getKey();
+                    final String key = ((BadgedImageView) mTouchedView).getKey();
                     mBubbleData.setSelectedBubble(mBubbleData.getBubbleWithKey(key));
                 }
 
@@ -261,7 +287,6 @@
             mVelocityTracker.recycle();
             mVelocityTracker = null;
         }
-
         mTouchedView = null;
         mMovedEnough = false;
         mInDismissTarget = false;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
deleted file mode 100644
index 35657d3..0000000
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
+++ /dev/null
@@ -1,272 +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.bubbles;
-
-import android.annotation.Nullable;
-import android.app.Notification;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Matrix;
-import android.graphics.Path;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
-import android.util.AttributeSet;
-import android.util.PathParser;
-import android.widget.FrameLayout;
-
-import com.android.internal.graphics.ColorUtils;
-import com.android.launcher3.icons.BitmapInfo;
-import com.android.launcher3.icons.ColorExtractor;
-import com.android.launcher3.icons.ShadowGenerator;
-import com.android.systemui.Interpolators;
-import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-
-/**
- * A floating object on the screen that can post message updates.
- */
-public class BubbleView extends FrameLayout {
-
-    // Same value as Launcher3 badge code
-    private static final float WHITE_SCRIM_ALPHA = 0.54f;
-    private Context mContext;
-
-    private BadgedImageView mBadgedImageView;
-    private int mDotColor;
-    private ColorExtractor mColorExtractor;
-
-    // mBubbleIconFactory cannot be static because it depends on Context.
-    private BubbleIconFactory mBubbleIconFactory;
-
-    private boolean mSuppressDot;
-
-    private Bubble mBubble;
-
-    public BubbleView(Context context) {
-        this(context, null);
-    }
-
-    public BubbleView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public BubbleView(Context context, AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public BubbleView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-        mContext = context;
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mBadgedImageView = findViewById(R.id.bubble_image);
-        mColorExtractor = new ColorExtractor();
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-    }
-
-    /**
-     * Populates this view with a bubble.
-     * <p>
-     * This should only be called when a new bubble is being set on the view, updates to the
-     * current bubble should use {@link #update(Bubble)}.
-     *
-     * @param bubble the bubble to display in this view.
-     */
-    public void setBubble(Bubble bubble) {
-        mBubble = bubble;
-    }
-
-    /**
-     * @param factory Factory for creating normalized bubble icons.
-     */
-    public void setBubbleIconFactory(BubbleIconFactory factory) {
-        mBubbleIconFactory = factory;
-    }
-
-    /**
-     * The {@link NotificationEntry} associated with this view, if one exists.
-     */
-    @Nullable
-    public NotificationEntry getEntry() {
-        return mBubble != null ? mBubble.getEntry() : null;
-    }
-
-    /**
-     * The key for the {@link NotificationEntry} associated with this view, if one exists.
-     */
-    @Nullable
-    public String getKey() {
-        return (mBubble != null) ? mBubble.getKey() : null;
-    }
-
-    /**
-     * Updates the UI based on the bubble, updates badge and animates messages as needed.
-     */
-    public void update(Bubble bubble) {
-        mBubble = bubble;
-        updateViews();
-    }
-
-    /** Changes the dot's visibility to match the bubble view's state. */
-    void updateDotVisibility(boolean animate) {
-        updateDotVisibility(animate, null /* after */);
-    }
-
-    /**
-     * Sets whether or not to hide the dot even if we'd otherwise show it. This is used while the
-     * flyout is visible or animating, to hide the dot until the flyout visually transforms into it.
-     */
-    void setSuppressDot(boolean suppressDot, boolean animate) {
-        mSuppressDot = suppressDot;
-        updateDotVisibility(animate);
-    }
-
-    boolean isDotShowing() {
-        return mBubble.showBubbleDot() && !mSuppressDot;
-    }
-
-    int getDotColor() {
-        return mDotColor;
-    }
-
-    /** Sets the position of the 'new' dot, animating it out and back in if requested. */
-    void setDotPosition(boolean onLeft, boolean animate) {
-        if (animate && onLeft != mBadgedImageView.getDotOnLeft() && isDotShowing()) {
-            animateDot(false /* showDot */, () -> {
-                mBadgedImageView.setDotOnLeft(onLeft);
-                animateDot(true /* showDot */, null);
-            });
-        } else {
-            mBadgedImageView.setDotOnLeft(onLeft);
-        }
-    }
-
-    float[] getDotCenter() {
-        float[] unscaled = mBadgedImageView.getDotCenter();
-        return new float[]{unscaled[0], unscaled[1]};
-    }
-
-    boolean getDotPositionOnLeft() {
-        return mBadgedImageView.getDotOnLeft();
-    }
-
-    /**
-     * Changes the dot's visibility to match the bubble view's state, running the provided callback
-     * after animation if requested.
-     */
-    private void updateDotVisibility(boolean animate, Runnable after) {
-        final boolean showDot = isDotShowing();
-        if (animate) {
-            animateDot(showDot, after);
-        } else {
-            mBadgedImageView.setShowDot(showDot);
-            mBadgedImageView.setDotScale(showDot ? 1f : 0f);
-        }
-    }
-
-    /**
-     * Animates the badge to show or hide.
-     */
-    private void animateDot(boolean showDot, Runnable after) {
-        if (mBadgedImageView.isShowingDot() == showDot) {
-            return;
-        }
-        // Do NOT wait until after animation ends to setShowDot
-        // to avoid overriding more recent showDot states.
-        mBadgedImageView.setShowDot(showDot);
-        mBadgedImageView.clearAnimation();
-        mBadgedImageView.animate().setDuration(200)
-                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                .setUpdateListener((valueAnimator) -> {
-                    float fraction = valueAnimator.getAnimatedFraction();
-                    fraction = showDot ? fraction : 1f - fraction;
-                    mBadgedImageView.setDotScale(fraction);
-                }).withEndAction(() -> {
-            mBadgedImageView.setDotScale(showDot ? 1f : 0f);
-            if (after != null) {
-                after.run();
-            }
-        }).start();
-    }
-
-    void updateViews() {
-        if (mBubble == null || mBubbleIconFactory == null) {
-            return;
-        }
-
-        Drawable bubbleDrawable = getBubbleDrawable(mContext);
-        BitmapInfo badgeBitmapInfo = getBadgedBitmap();
-        BitmapInfo bubbleBitmapInfo = getBubbleBitmap(bubbleDrawable, badgeBitmapInfo);
-        mBadgedImageView.setImageBitmap(bubbleBitmapInfo.icon);
-
-        // Update badge.
-        mDotColor = ColorUtils.blendARGB(badgeBitmapInfo.color, Color.WHITE, WHITE_SCRIM_ALPHA);
-        mBadgedImageView.setDotColor(mDotColor);
-
-        // Update dot.
-        Path iconPath = PathParser.createPathFromPathData(
-                getResources().getString(com.android.internal.R.string.config_icon_mask));
-        Matrix matrix = new Matrix();
-        float scale = mBubbleIconFactory.getNormalizer().getScale(bubbleDrawable,
-                null /* outBounds */, null /* path */, null /* outMaskShape */);
-        float radius = BadgedImageView.DEFAULT_PATH_SIZE / 2f;
-        matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */,
-                radius /* pivot y */);
-        iconPath.transform(matrix);
-        mBadgedImageView.drawDot(iconPath);
-
-        animateDot(isDotShowing(), null /* after */);
-    }
-
-    Drawable getBubbleDrawable(Context context) {
-        Notification.BubbleMetadata metadata = getEntry().getBubbleMetadata();
-        Icon ic = metadata.getIcon();
-        return ic.loadDrawable(context);
-    }
-
-    BitmapInfo getBadgedBitmap() {
-        Bitmap userBadgedBitmap = mBubbleIconFactory.createIconBitmap(
-                mBubble.getUserBadgedAppIcon(), 1f, mBubbleIconFactory.getBadgeSize());
-
-        Canvas c = new Canvas();
-        ShadowGenerator shadowGenerator = new ShadowGenerator(mBubbleIconFactory.getBadgeSize());
-        c.setBitmap(userBadgedBitmap);
-        shadowGenerator.recreateIcon(Bitmap.createBitmap(userBadgedBitmap), c);
-        BitmapInfo bitmapInfo = mBubbleIconFactory.createIconBitmap(userBadgedBitmap);
-        return bitmapInfo;
-    }
-
-    BitmapInfo getBubbleBitmap(Drawable bubble, BitmapInfo badge) {
-        BitmapInfo bubbleIconInfo = mBubbleIconFactory.createBadgedIconBitmap(bubble,
-                null /* user */,
-                true /* shrinkNonAdaptiveIcons */);
-
-        mBubbleIconFactory.badgeWithDrawable(bubbleIconInfo.icon,
-                new BitmapDrawable(mContext.getResources(), badge.icon));
-        return bubbleIconInfo;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index 25986c5..3cf14d6 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -25,7 +25,6 @@
 import com.android.systemui.globalactions.GlobalActionsComponent;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.pip.PipUI;
-import com.android.systemui.power.InattentiveSleepWarningController;
 import com.android.systemui.power.PowerUI;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsModule;
@@ -103,13 +102,6 @@
     @ClassKey(PowerUI.class)
     public abstract SystemUI bindPowerUI(PowerUI sysui);
 
-    /** Inject into InattentiveSleepWarningController. */
-    @Binds
-    @IntoMap
-    @ClassKey(InattentiveSleepWarningController.class)
-    public abstract SystemUI bindInattentiveSleepWarningController(
-            InattentiveSleepWarningController sysui);
-
     /** Inject into Recents. */
     @Binds
     @IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 9bd729e..442313d 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -35,7 +35,9 @@
 import com.android.systemui.statusbar.notification.people.PeopleHubModule;
 import com.android.systemui.statusbar.phone.KeyguardLiftController;
 import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.StatusBarComponent;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.util.concurrency.ConcurrencyModule;
 import com.android.systemui.util.sensors.AsyncSensorManager;
 import com.android.systemui.util.time.SystemClock;
 import com.android.systemui.util.time.SystemClockImpl;
@@ -52,7 +54,9 @@
  * implementation.
  */
 @Module(includes = {AssistModule.class,
-                    PeopleHubModule.class})
+                    ConcurrencyModule.class,
+                    PeopleHubModule.class},
+        subcomponents = {StatusBarComponent.class})
 public abstract class SystemUIModule {
 
     @Binds
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
index e9265749..e50e0fe0 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
@@ -25,7 +25,6 @@
 import com.android.systemui.SystemUIAppComponentFactory;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.fragments.FragmentService;
-import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.util.InjectionInflationController;
 
@@ -73,12 +72,6 @@
     Dependency.DependencyInjector createDependency();
 
     /**
-     * Injects the StatusBar.
-     */
-    @Singleton
-    StatusBar.StatusBarInjector getStatusBarInjector();
-
-    /**
      * FragmentCreator generates all Fragments that need injection.
      */
     @Singleton
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Background.java b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Background.java
new file mode 100644
index 0000000..141c901
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Background.java
@@ -0,0 +1,30 @@
+/*
+ * 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.systemui.dagger.qualifiers;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface Background {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Main.java b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Main.java
new file mode 100644
index 0000000..7b09774
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Main.java
@@ -0,0 +1,30 @@
+/*
+ * 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.systemui.dagger.qualifiers;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface Main {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dock/DockManager.java b/packages/SystemUI/src/com/android/systemui/dock/DockManager.java
index c7637fb..b6f7cd0 100644
--- a/packages/SystemUI/src/com/android/systemui/dock/DockManager.java
+++ b/packages/SystemUI/src/com/android/systemui/dock/DockManager.java
@@ -35,6 +35,12 @@
     int STATE_DOCKED_HIDE = 2;
 
     /**
+     * Indicates there's no alignment info. This could happen when the device is unable to decide
+     * its alignment condition.
+     */
+    int ALIGN_STATE_UNKNOWN = -1;
+
+    /**
      * Indicates there's no alignment issue.
      */
     int ALIGN_STATE_GOOD = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index b5845947..63a7771 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -669,7 +669,10 @@
                         // Take an "interactive" bugreport.
                         MetricsLogger.action(mContext,
                                 MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE);
-                        ActivityManager.getService().requestInteractiveBugReport();
+                        if (!ActivityManager.getService().launchBugReportHandlerApp()) {
+                            Log.w(TAG, "Bugreport handler could not be launched");
+                            ActivityManager.getService().requestInteractiveBugReport();
+                        }
                     } catch (RemoteException e) {
                     }
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index d5f5a5a..53053fc 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -17,9 +17,11 @@
 import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 
+import android.annotation.Nullable;
+import android.annotation.StringRes;
 import android.app.Dialog;
-import android.app.KeyguardManager;
 import android.content.Context;
+import android.os.PowerManager;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
@@ -134,14 +136,22 @@
 
         int color = Utils.getColorAttrDefaultColor(mContext,
                 com.android.systemui.R.attr.wallpaperTextColor);
-        boolean onKeyguard = mContext.getSystemService(
-                KeyguardManager.class).isKeyguardLocked();
 
         ProgressBar bar = d.findViewById(R.id.progress);
         bar.getIndeterminateDrawable().setTint(color);
-        TextView message = d.findViewById(R.id.text1);
-        message.setTextColor(color);
-        if (isReboot) message.setText(R.string.reboot_to_reset_message);
+
+        TextView reasonView = d.findViewById(R.id.text1);
+        TextView messageView = d.findViewById(R.id.text2);
+
+        reasonView.setTextColor(color);
+        messageView.setTextColor(color);
+
+        messageView.setText(getRebootMessage(isReboot, reason));
+        String rebootReasonMessage = getReasonMessage(reason);
+        if (rebootReasonMessage != null) {
+            reasonView.setVisibility(View.VISIBLE);
+            reasonView.setText(rebootReasonMessage);
+        }
 
         GradientColors colors = Dependency.get(SysuiColorExtractor.class).getNeutralColors();
         background.setColor(colors.getMainColor(), false);
@@ -149,6 +159,30 @@
         d.show();
     }
 
+    @StringRes
+    private int getRebootMessage(boolean isReboot, @Nullable String reason) {
+        if (reason != null && reason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
+            return R.string.reboot_to_update_reboot;
+        } else if (reason != null && reason.equals(PowerManager.REBOOT_RECOVERY)) {
+            return R.string.reboot_to_reset_message;
+        } else if (isReboot) {
+            return R.string.reboot_to_reset_message;
+        } else {
+            return R.string.shutdown_progress;
+        }
+    }
+
+    @Nullable
+    private String getReasonMessage(@Nullable String reason) {
+        if (reason != null && reason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
+            return mContext.getString(R.string.reboot_to_update_title);
+        } else if (reason != null && reason.equals(PowerManager.REBOOT_RECOVERY)) {
+            return mContext.getString(R.string.reboot_to_reset_title);
+        } else {
+            return null;
+        }
+    }
+
     @Override
     public void disable(int displayId, int state1, int state2, boolean animate) {
         final boolean disabled = (state2 & DISABLE2_GLOBAL_ACTIONS) != 0;
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java
index 99c55f1..f815b5d 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java
@@ -79,12 +79,6 @@
         });
     }
 
-    private void animate() {
-        mAnimator.cancel();
-        mAnimator.setFloatValues(mReveal, mAwake ? MAX_REVEAL : MIN_REVEAL);
-        mAnimator.start();
-    }
-
     public float getReveal() {
         return mReveal;
     }
@@ -93,8 +87,8 @@
         if (DEBUG) {
             Log.d(TAG, "updateAwake: awake=" + awake + ", duration=" + duration);
         }
+        mAnimator.cancel();
         mAwake = awake;
-        mAnimator.setDuration(duration);
         if (duration == 0) {
             // We are transiting from home to aod or aod to home directly,
             // we don't need to do transition in these cases.
@@ -103,7 +97,9 @@
             mRevealListener.onRevealStateChanged();
             mRevealListener.onRevealEnd();
         } else {
-            animate();
+            mAnimator.setDuration(duration);
+            mAnimator.setFloatValues(mReveal, mAwake ? MAX_REVEAL : MIN_REVEAL);
+            mAnimator.start();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index f026e68..8d08b28 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2082,7 +2082,6 @@
 
     @Override
     public void onBootCompleted() {
-        mUpdateMonitor.dispatchBootCompleted();
         synchronized (this) {
             mBootCompleted = true;
             if (mBootSendUserPresent) {
diff --git a/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java b/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java
index f094cb9..0f71d22 100644
--- a/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java
@@ -47,7 +47,8 @@
     private final Object mDataLock = new Object();
     private final String mId;
     private final int mMaxLogs;
-    private boolean mEnabled;
+    protected boolean mEnabled;
+    protected boolean mLogToLogcatEnabled;
 
     @VisibleForTesting protected ArrayDeque<Event> mTimeline;
 
@@ -62,14 +63,18 @@
      */
     public SysuiLog(DumpController dumpController, String id, int maxDebugLogs, int maxLogs) {
         this(dumpController, id, sDebuggable ? maxDebugLogs : maxLogs,
-                SystemProperties.getBoolean(SYSPROP_ENABLED_PREFIX + id, DEFAULT_ENABLED));
+                SystemProperties.getBoolean(SYSPROP_ENABLED_PREFIX + id, DEFAULT_ENABLED),
+                SystemProperties.getBoolean(SYSPROP_LOGCAT_ENABLED_PREFIX + id,
+                        DEFAULT_LOGCAT_ENABLED));
     }
 
     @VisibleForTesting
-    protected SysuiLog(DumpController dumpController, String id, int maxLogs, boolean enabled) {
+    protected SysuiLog(DumpController dumpController, String id, int maxLogs, boolean enabled,
+            boolean logcatEnabled) {
         mId = id;
         mMaxLogs = maxLogs;
         mEnabled = enabled;
+        mLogToLogcatEnabled = logcatEnabled;
         mTimeline = mEnabled ? new ArrayDeque<>(mMaxLogs) : null;
         dumpController.registerDumpable(mId, this);
     }
@@ -96,7 +101,7 @@
             mTimeline.add(event);
         }
 
-        if (LOG_TO_LOGCAT_ENABLED) {
+        if (mLogToLogcatEnabled) {
             final String strEvent = eventToString(event);
             switch (event.getLogLevel()) {
                 case Event.VERBOSE:
@@ -162,9 +167,10 @@
     }
 
     private static boolean sDebuggable = Build.IS_DEBUGGABLE;
-    private static final String SYSPROP_ENABLED_PREFIX = "sysui.log.enabled.";
-    private static final boolean LOG_TO_LOGCAT_ENABLED = sDebuggable;
+    private static final String SYSPROP_ENABLED_PREFIX = "persist.sysui.log.enabled.";
+    private static final String SYSPROP_LOGCAT_ENABLED_PREFIX = "persist.sysui.log.enabled.logcat.";
     private static final boolean DEFAULT_ENABLED = sDebuggable;
+    private static final boolean DEFAULT_LOGCAT_ENABLED = false;
     private static final int DEFAULT_MAX_DEBUG_LOGS = 100;
     private static final int DEFAULT_MAX_LOGS = 50;
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
index 686e7db..f10274a 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
@@ -64,6 +64,7 @@
     private IPinnedStackController mPinnedStackController;
     private ComponentName mLastPipComponentName;
     private float mReentrySnapFraction = INVALID_SNAP_FRACTION;
+    private Size mReentrySize = null;
 
     private float mDefaultAspectRatio;
     private float mMinAspectRatio;
@@ -162,7 +163,7 @@
     public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
             Rect animatingBounds, DisplayInfo displayInfo) {
         getInsetBounds(insetBounds);
-        final Rect defaultBounds = getDefaultBounds(INVALID_SNAP_FRACTION);
+        final Rect defaultBounds = getDefaultBounds(INVALID_SNAP_FRACTION, null);
         normalBounds.set(defaultBounds);
         if (animatingBounds.isEmpty()) {
             animatingBounds.set(defaultBounds);
@@ -175,26 +176,28 @@
     }
 
     /**
-     * Responds to IPinnedStackListener on saving reentry snap fraction
+     * Responds to IPinnedStackListener on saving reentry snap fraction and size
      * for a given {@link ComponentName}.
      */
-    public void onSaveReentrySnapFraction(ComponentName componentName, Rect bounds) {
+    public void onSaveReentryBounds(ComponentName componentName, Rect bounds) {
         mReentrySnapFraction = getSnapFraction(bounds);
+        mReentrySize = new Size(bounds.width(), bounds.height());
         mLastPipComponentName = componentName;
     }
 
     /**
-     * Responds to IPinnedStackListener on resetting reentry snap fraction
+     * Responds to IPinnedStackListener on resetting reentry snap fraction and size
      * for a given {@link ComponentName}.
      */
-    public void onResetReentrySnapFraction(ComponentName componentName) {
+    public void onResetReentryBounds(ComponentName componentName) {
         if (componentName.equals(mLastPipComponentName)) {
-            onResetReentrySnapFractionUnchecked();
+            onResetReentryBoundsUnchecked();
         }
     }
 
-    private void onResetReentrySnapFractionUnchecked() {
+    private void onResetReentryBoundsUnchecked() {
         mReentrySnapFraction = INVALID_SNAP_FRACTION;
+        mReentrySize = null;
         mLastPipComponentName = null;
     }
 
@@ -233,7 +236,7 @@
     public void onPrepareAnimation(Rect sourceRectHint, float aspectRatio, Rect bounds) {
         final Rect destinationBounds;
         if (bounds == null) {
-            destinationBounds = getDefaultBounds(mReentrySnapFraction);
+            destinationBounds = getDefaultBounds(mReentrySnapFraction, mReentrySize);
         } else {
             destinationBounds = new Rect(bounds);
         }
@@ -245,7 +248,7 @@
             return;
         }
         mAspectRatio = aspectRatio;
-        onResetReentrySnapFractionUnchecked();
+        onResetReentryBoundsUnchecked();
         try {
             mPinnedStackController.startAnimation(destinationBounds, sourceRectHint,
                     -1 /* animationDuration */);
@@ -269,13 +272,14 @@
      */
     private void transformBoundsToAspectRatio(Rect stackBounds, float aspectRatio,
             boolean useCurrentMinEdgeSize) {
-        // Save the snap fraction, calculate the aspect ratio based on screen size
+
+        // Save the snap fraction and adjust the size based on the new aspect ratio.
         final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds,
                 getMovementBounds(stackBounds));
-
         final int minEdgeSize = useCurrentMinEdgeSize ? mCurrentMinSize : mDefaultMinSize;
-        final Size size = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, minEdgeSize,
-                mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
+        final Size size = mSnapAlgorithm.getSizeForAspectRatio(
+                new Size(stackBounds.width(), stackBounds.height()), aspectRatio, minEdgeSize);
+
         final int left = (int) (stackBounds.centerX() - size.getWidth() / 2f);
         final int top = (int) (stackBounds.centerY() - size.getHeight() / 2f);
         stackBounds.set(left, top, left + size.getWidth(), top + size.getHeight());
@@ -286,21 +290,20 @@
     }
 
     /**
-     * @return the default bounds to show the PIP, if a {@param snapFraction} is provided, then it
-     * will apply the default bounds to the provided snap fraction.
+     * @return the default bounds to show the PIP, if a {@param snapFraction} and {@param size} are
+     * provided, then it will apply the default bounds to the provided snap fraction and size.
      */
-    private Rect getDefaultBounds(float snapFraction) {
-        final Rect insetBounds = new Rect();
-        getInsetBounds(insetBounds);
-
+    private Rect getDefaultBounds(float snapFraction, Size size) {
         final Rect defaultBounds = new Rect();
-        final Size size = mSnapAlgorithm.getSizeForAspectRatio(mDefaultAspectRatio,
-                mDefaultMinSize, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
-        if (snapFraction != INVALID_SNAP_FRACTION) {
+        if (snapFraction != INVALID_SNAP_FRACTION && size != null) {
             defaultBounds.set(0, 0, size.getWidth(), size.getHeight());
             final Rect movementBounds = getMovementBounds(defaultBounds);
             mSnapAlgorithm.applySnapFraction(defaultBounds, movementBounds, snapFraction);
         } else {
+            final Rect insetBounds = new Rect();
+            getInsetBounds(insetBounds);
+            size = mSnapAlgorithm.getSizeForAspectRatio(mDefaultAspectRatio,
+                    mDefaultMinSize, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
             Gravity.apply(mDefaultStackGravity, size.getWidth(), size.getHeight(), insetBounds,
                     0, Math.max(mIsImeShowing ? mImeHeight : 0,
                             mIsShelfShowing ? mShelfHeight : 0),
@@ -364,11 +367,19 @@
      * @return the default snap fraction to apply instead of the default gravity when calculating
      *         the default stack bounds when first entering PiP.
      */
-    private float getSnapFraction(Rect stackBounds) {
+    public float getSnapFraction(Rect stackBounds) {
         return mSnapAlgorithm.getSnapFraction(stackBounds, getMovementBounds(stackBounds));
     }
 
     /**
+     * Applies the given snap fraction to the given stack bounds.
+     */
+    public void applySnapFraction(Rect stackBounds, float snapFraction) {
+        final Rect movementBounds = getMovementBounds(stackBounds);
+        mSnapAlgorithm.applySnapFraction(stackBounds, movementBounds, snapFraction);
+    }
+
+    /**
      * @return the pixels for a given dp value.
      */
     private int dpToPx(float dpValue, DisplayMetrics dm) {
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 c33b8d9..a4707cf 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -65,6 +65,7 @@
     private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
     private final Rect mTmpInsetBounds = new Rect();
     private final Rect mTmpNormalBounds = new Rect();
+    private final Rect mReentryBounds = new Rect();
 
     private PipBoundsHandler mPipBoundsHandler;
     private InputConsumerController mInputConsumerController;
@@ -164,13 +165,25 @@
         }
 
         @Override
-        public void onSaveReentrySnapFraction(ComponentName componentName, Rect bounds) {
-            mHandler.post(() -> mPipBoundsHandler.onSaveReentrySnapFraction(componentName, bounds));
+        public void onSaveReentryBounds(ComponentName componentName, Rect bounds) {
+            mHandler.post(() -> {
+                // On phones, the expansion animation that happens on pip tap before restoring
+                // to fullscreen makes it so that the bounds received here are the expanded
+                // bounds. We want to restore to the unexpanded bounds when re-entering pip,
+                // so we save the bounds before expansion (normal) instead of the current
+                // bounds.
+                mReentryBounds.set(mTouchHandler.getNormalBounds());
+                // Apply the snap fraction of the current bounds to the normal bounds.
+                float snapFraction = mPipBoundsHandler.getSnapFraction(bounds);
+                mPipBoundsHandler.applySnapFraction(mReentryBounds, snapFraction);
+                // Save reentry bounds (normal non-expand bounds with current position applied).
+                mPipBoundsHandler.onSaveReentryBounds(componentName, mReentryBounds);
+            });
         }
 
         @Override
-        public void onResetReentrySnapFraction(ComponentName componentName) {
-            mHandler.post(() -> mPipBoundsHandler.onResetReentrySnapFraction(componentName));
+        public void onResetReentryBounds(ComponentName componentName) {
+            mHandler.post(() -> mPipBoundsHandler.onResetReentryBounds(componentName));
         }
 
         @Override
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 f59b372..2e90a3e 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -592,6 +592,13 @@
     }
 
     /**
+     * @return the unexpanded bounds.
+     */
+    public Rect getNormalBounds() {
+        return mNormalBounds;
+    }
+
+    /**
      * Gesture controlling normal movement of the PIP.
      */
     private PipTouchGesture mDefaultMovementGesture = new PipTouchGesture() {
diff --git a/packages/SystemUI/src/com/android/systemui/power/InattentiveSleepWarningController.java b/packages/SystemUI/src/com/android/systemui/power/InattentiveSleepWarningController.java
deleted file mode 100644
index 7d4bd01..0000000
--- a/packages/SystemUI/src/com/android/systemui/power/InattentiveSleepWarningController.java
+++ /dev/null
@@ -1,62 +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.systemui.power;
-
-import android.content.Context;
-
-import com.android.systemui.SystemUI;
-import com.android.systemui.statusbar.CommandQueue;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/**
- * Receives messages sent from {@link com.android.server.power.InattentiveSleepWarningController}
- * and shows the appropriate inattentive sleep UI (e.g. {@link InattentiveSleepWarningView}).
- */
-@Singleton
-public class InattentiveSleepWarningController extends SystemUI implements CommandQueue.Callbacks {
-    private final CommandQueue mCommandQueue;
-    private InattentiveSleepWarningView mOverlayView;
-
-    @Inject
-    public InattentiveSleepWarningController(Context context, CommandQueue commandQueue) {
-        super(context);
-        mCommandQueue = commandQueue;
-    }
-
-    @Override
-    public void start() {
-        mCommandQueue.addCallback(this);
-    }
-
-    @Override
-    public void showInattentiveSleepWarning() {
-        if (mOverlayView == null) {
-            mOverlayView = new InattentiveSleepWarningView(mContext);
-        }
-
-        mOverlayView.show();
-    }
-
-    @Override
-    public void dismissInattentiveSleepWarning(boolean animated) {
-        if (mOverlayView != null) {
-            mOverlayView.dismiss(animated);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 4982dd4..eb19571 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -476,7 +476,7 @@
                 });
         d.setOnDismissListener(dialogInterface -> {
             mUsbHighTempDialog = null;
-            Events.writeEvent(mContext, Events.EVENT_DISMISS_USB_OVERHEAT_ALARM,
+            Events.writeEvent(Events.EVENT_DISMISS_USB_OVERHEAT_ALARM,
                     Events.DISMISS_REASON_USB_OVERHEAD_ALARM_CHANGED,
                     mKeyguard.isKeyguardLocked());
         });
@@ -485,7 +485,7 @@
         d.show();
         mUsbHighTempDialog = d;
 
-        Events.writeEvent(mContext, Events.EVENT_SHOW_USB_OVERHEAT_ALARM,
+        Events.writeEvent(Events.EVENT_SHOW_USB_OVERHEAT_ALARM,
                 Events.SHOW_REASON_USB_OVERHEAD_ALARM_CHANGED,
                 mKeyguard.isKeyguardLocked());
     }
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index f60d9db..59ac329 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -46,6 +46,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.StatusBar;
 
 import java.io.FileDescriptor;
@@ -60,7 +61,7 @@
 import dagger.Lazy;
 
 @Singleton
-public class PowerUI extends SystemUI {
+public class PowerUI extends SystemUI implements CommandQueue.Callbacks {
 
     static final String TAG = "PowerUI";
     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -80,6 +81,7 @@
 
     private PowerManager mPowerManager;
     private WarningsUI mWarnings;
+    private InattentiveSleepWarningView mOverlayView;
     private final Configuration mLastConfiguration = new Configuration();
     private int mPlugType = 0;
     private int mInvalidCharger = 0;
@@ -105,13 +107,15 @@
     private IThermalEventListener mSkinThermalEventListener;
     private IThermalEventListener mUsbThermalEventListener;
     private final BroadcastDispatcher mBroadcastDispatcher;
+    private final CommandQueue mCommandQueue;
     private final Lazy<StatusBar> mStatusBarLazy;
 
     @Inject
     public PowerUI(Context context, BroadcastDispatcher broadcastDispatcher,
-            Lazy<StatusBar> statusBarLazy) {
+            CommandQueue commandQueue, Lazy<StatusBar> statusBarLazy) {
         super(context);
         mBroadcastDispatcher = broadcastDispatcher;
+        mCommandQueue = commandQueue;
         mStatusBarLazy = statusBarLazy;
     }
 
@@ -162,6 +166,7 @@
                     }
                 });
         initThermalEventListeners();
+        mCommandQueue.addCallback(this);
     }
 
     @Override
@@ -581,6 +586,22 @@
         }
     }
 
+    @Override
+    public void showInattentiveSleepWarning() {
+        if (mOverlayView == null) {
+            mOverlayView = new InattentiveSleepWarningView(mContext);
+        }
+
+        mOverlayView.show();
+    }
+
+    @Override
+    public void dismissInattentiveSleepWarning(boolean animated) {
+        if (mOverlayView != null) {
+            mOverlayView.dismiss(animated);
+        }
+    }
+
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.print("mLowBatteryAlertCloseLevel=");
         pw.println(mLowBatteryAlertCloseLevel);
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
deleted file mode 100644
index a5a915b..0000000
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
+++ /dev/null
@@ -1,110 +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.privacy
-
-import android.content.Context
-import android.util.AttributeSet
-import android.view.Gravity
-import android.view.ViewGroup
-import android.widget.FrameLayout
-import android.widget.ImageView
-import android.widget.LinearLayout
-import com.android.systemui.R
-
-class OngoingPrivacyChip @JvmOverloads constructor(
-    context: Context,
-    attrs: AttributeSet? = null,
-    defStyleAttrs: Int = 0,
-    defStyleRes: Int = 0
-) : LinearLayout(context, attrs, defStyleAttrs, defStyleRes) {
-
-    private val iconMarginExpanded = context.resources.getDimensionPixelSize(
-                    R.dimen.ongoing_appops_chip_icon_margin_expanded)
-    private val iconMarginCollapsed = context.resources.getDimensionPixelSize(
-                    R.dimen.ongoing_appops_chip_icon_margin_collapsed)
-    private val iconSize =
-            context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_size)
-    private val iconColor = context.resources.getColor(
-            R.color.status_bar_clock_color, context.theme)
-    private val sidePadding =
-            context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_side_padding)
-    private val backgroundDrawable = context.getDrawable(R.drawable.privacy_chip_bg)
-    private lateinit var iconsContainer: LinearLayout
-    private lateinit var back: FrameLayout
-    var expanded = false
-        set(value) {
-            if (value != field) {
-                field = value
-                updateView()
-            }
-        }
-
-    var builder = PrivacyDialogBuilder(context, emptyList<PrivacyItem>())
-    var privacyList = emptyList<PrivacyItem>()
-        set(value) {
-            field = value
-            builder = PrivacyDialogBuilder(context, value)
-            updateView()
-        }
-
-    override fun onFinishInflate() {
-        super.onFinishInflate()
-
-        back = findViewById(R.id.background)
-        iconsContainer = findViewById(R.id.icons_container)
-    }
-
-    // Should only be called if the builder icons or app changed
-    private fun updateView() {
-        back.background = if (expanded) backgroundDrawable else null
-        val padding = if (expanded) sidePadding else 0
-        back.setPaddingRelative(padding, 0, padding, 0)
-        fun setIcons(dialogBuilder: PrivacyDialogBuilder, iconsContainer: ViewGroup) {
-            iconsContainer.removeAllViews()
-            dialogBuilder.generateIcons().forEachIndexed { i, it ->
-                it.mutate()
-                it.setTint(iconColor)
-                val image = ImageView(context).apply {
-                    setImageDrawable(it)
-                    scaleType = ImageView.ScaleType.CENTER_INSIDE
-                }
-                iconsContainer.addView(image, iconSize, iconSize)
-                if (i != 0) {
-                    val lp = image.layoutParams as MarginLayoutParams
-                    lp.marginStart = if (expanded) iconMarginExpanded else iconMarginCollapsed
-                    image.layoutParams = lp
-                }
-            }
-        }
-
-        if (!privacyList.isEmpty()) {
-            generateContentDescription()
-            setIcons(builder, iconsContainer)
-            val lp = iconsContainer.layoutParams as FrameLayout.LayoutParams
-            lp.gravity = Gravity.CENTER_VERTICAL or
-                    (if (expanded) Gravity.CENTER_HORIZONTAL else Gravity.END)
-            iconsContainer.layoutParams = lp
-        } else {
-            iconsContainer.removeAllViews()
-        }
-        requestLayout()
-    }
-
-    private fun generateContentDescription() {
-        val typesText = builder.joinTypes()
-        contentDescription = context.getString(
-                R.string.ongoing_privacy_chip_content_multiple_apps, typesText)
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt
deleted file mode 100644
index d08a373..0000000
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt
+++ /dev/null
@@ -1,56 +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.privacy
-
-import android.content.Context
-import android.graphics.drawable.Drawable
-import com.android.systemui.R
-
-class PrivacyDialogBuilder(private val context: Context, itemsList: List<PrivacyItem>) {
-
-    val appsAndTypes: List<Pair<PrivacyApplication, List<PrivacyType>>>
-    val types: List<PrivacyType>
-    private val separator = context.getString(R.string.ongoing_privacy_dialog_separator)
-    private val lastSeparator = context.getString(R.string.ongoing_privacy_dialog_last_separator)
-
-    init {
-        appsAndTypes = itemsList.groupBy({ it.application }, { it.privacyType })
-                .toList()
-                .sortedWith(compareBy({ -it.second.size }, // Sort by number of AppOps
-                        { it.second.min() })) // Sort by "smallest" AppOpp (Location is largest)
-        types = itemsList.map { it.privacyType }.distinct().sorted()
-    }
-
-    fun generateIconsForApp(types: List<PrivacyType>): List<Drawable> {
-        return types.sorted().map { it.getIcon(context) }
-    }
-
-    fun generateIcons() = types.map { it.getIcon(context) }
-
-    private fun <T> List<T>.joinWithAnd(): StringBuilder {
-        return subList(0, size - 1).joinTo(StringBuilder(), separator = separator).apply {
-            append(lastSeparator)
-            append(this@joinWithAnd.last())
-        }
-    }
-
-    fun joinTypes(): String {
-        return when (types.size) {
-            0 -> ""
-            1 -> types[0].getName(context)
-            else -> types.map { it.getName(context) }.joinWithAnd().toString()
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
deleted file mode 100644
index 2909424..0000000
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
+++ /dev/null
@@ -1,80 +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.privacy
-
-import android.content.Context
-import android.content.pm.ApplicationInfo
-import android.content.pm.PackageManager
-import android.graphics.drawable.Drawable
-import android.os.UserHandle
-import android.util.IconDrawableFactory
-import com.android.systemui.R
-
-typealias Privacy = PrivacyType
-
-enum class PrivacyType(private val nameId: Int, val iconId: Int) {
-    // This is uses the icons used by the corresponding permission groups in the AndroidManifest
-    TYPE_CAMERA(R.string.privacy_type_camera,
-            com.android.internal.R.drawable.perm_group_camera),
-    TYPE_MICROPHONE(R.string.privacy_type_microphone,
-            com.android.internal.R.drawable.perm_group_microphone),
-    TYPE_LOCATION(R.string.privacy_type_location,
-            com.android.internal.R.drawable.perm_group_location);
-
-    fun getName(context: Context) = context.resources.getString(nameId)
-
-    fun getIcon(context: Context) = context.resources.getDrawable(iconId, context.theme)
-}
-
-data class PrivacyItem(
-    val privacyType: PrivacyType,
-    val application: PrivacyApplication
-)
-
-data class PrivacyApplication(val packageName: String, val uid: Int, val context: Context)
-    : Comparable<PrivacyApplication> {
-
-    override fun compareTo(other: PrivacyApplication): Int {
-        return applicationName.compareTo(other.applicationName)
-    }
-
-    private val applicationInfo: ApplicationInfo? by lazy {
-        try {
-            val userHandle = UserHandle.getUserHandleForUid(uid)
-            context.createPackageContextAsUser(packageName, 0, userHandle).getPackageManager()
-                    .getApplicationInfo(packageName, 0)
-        } catch (_: PackageManager.NameNotFoundException) {
-            null
-        }
-    }
-    val icon: Drawable by lazy {
-        applicationInfo?.let {
-            try {
-                val iconFactory = IconDrawableFactory.newInstance(context, true)
-                iconFactory.getBadgedIcon(it, UserHandle.getUserId(uid))
-            } catch (_: Exception) {
-                null
-            }
-        } ?: context.getDrawable(android.R.drawable.sym_def_app_icon)
-    }
-
-    val applicationName: String by lazy {
-        applicationInfo?.let {
-            context.packageManager.getApplicationLabel(it) as String
-        } ?: packageName
-    }
-
-    override fun toString() = "PrivacyApplication(packageName=$packageName, uid=$uid)"
-}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
deleted file mode 100644
index d592492..0000000
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+++ /dev/null
@@ -1,299 +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.privacy
-
-import android.app.ActivityManager
-import android.app.AppOpsManager
-import android.content.BroadcastReceiver
-import android.content.Context
-import android.content.Intent
-import android.content.IntentFilter
-import android.os.Handler
-import android.os.Looper
-import android.os.Message
-import android.os.UserHandle
-import android.os.UserManager
-import android.provider.DeviceConfig
-import com.android.internal.annotations.VisibleForTesting
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags
-import com.android.systemui.Dumpable
-import com.android.systemui.R
-import com.android.systemui.appops.AppOpItem
-import com.android.systemui.appops.AppOpsController
-import com.android.systemui.broadcast.BroadcastDispatcher
-import com.android.systemui.dagger.qualifiers.BgHandler
-import com.android.systemui.dagger.qualifiers.MainHandler
-import java.io.FileDescriptor
-import java.io.PrintWriter
-import java.lang.ref.WeakReference
-import javax.inject.Inject
-import javax.inject.Singleton
-
-fun isPermissionsHubEnabled() = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
-                SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, false)
-
-@Singleton
-class PrivacyItemController @Inject constructor(
-    private val context: Context,
-    private val appOpsController: AppOpsController,
-    @MainHandler private val uiHandler: Handler,
-    @BgHandler private val bgHandler: Handler,
-    private val broadcastDispatcher: BroadcastDispatcher
-) : Dumpable {
-
-    @VisibleForTesting
-    internal companion object {
-        val OPS = intArrayOf(AppOpsManager.OP_CAMERA,
-                AppOpsManager.OP_RECORD_AUDIO,
-                AppOpsManager.OP_COARSE_LOCATION,
-                AppOpsManager.OP_FINE_LOCATION)
-        val intents = listOf(Intent.ACTION_USER_FOREGROUND,
-                Intent.ACTION_MANAGED_PROFILE_ADDED,
-                Intent.ACTION_MANAGED_PROFILE_REMOVED)
-        const val TAG = "PrivacyItemController"
-        const val SYSTEM_UID = 1000
-        const val MSG_ADD_CALLBACK = 0
-        const val MSG_REMOVE_CALLBACK = 1
-        const val MSG_UPDATE_LISTENING_STATE = 2
-    }
-
-    @VisibleForTesting
-    internal var privacyList = emptyList<PrivacyItem>()
-        @Synchronized get() = field.toList() // Returns a shallow copy of the list
-        @Synchronized set
-
-    private val userManager = context.getSystemService(UserManager::class.java)
-    private var currentUserIds = emptyList<Int>()
-    private var listening = false
-    val systemApp =
-            PrivacyApplication(context.getString(R.string.device_services), SYSTEM_UID, context)
-    private val callbacks = mutableListOf<WeakReference<Callback>>()
-    private val messageHandler = H(WeakReference(this), uiHandler.looper)
-
-    private val notifyChanges = Runnable {
-        val list = privacyList
-        callbacks.forEach { it.get()?.privacyChanged(list) }
-    }
-
-    private val updateListAndNotifyChanges = Runnable {
-        updatePrivacyList()
-        uiHandler.post(notifyChanges)
-    }
-
-    private var indicatorsAvailable = isPermissionsHubEnabled()
-    @VisibleForTesting
-    internal val devicePropertiesChangedListener =
-            object : DeviceConfig.OnPropertiesChangedListener {
-        override fun onPropertiesChanged(properties: DeviceConfig.Properties) {
-            if (DeviceConfig.NAMESPACE_PRIVACY.equals(properties.getNamespace()) &&
-                    properties.getKeyset().contains(
-                    SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED)) {
-                indicatorsAvailable = properties.getBoolean(
-                        SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, false)
-                messageHandler.removeMessages(MSG_UPDATE_LISTENING_STATE)
-                messageHandler.sendEmptyMessage(MSG_UPDATE_LISTENING_STATE)
-            }
-        }
-    }
-
-    private val cb = object : AppOpsController.Callback {
-        override fun onActiveStateChanged(
-            code: Int,
-            uid: Int,
-            packageName: String,
-            active: Boolean
-        ) {
-            val userId = UserHandle.getUserId(uid)
-            if (userId in currentUserIds) {
-                update(false)
-            }
-        }
-    }
-
-    @VisibleForTesting
-    internal var userSwitcherReceiver = Receiver()
-        set(value) {
-            context.unregisterReceiver(field)
-            field = value
-            registerReceiver()
-        }
-
-    init {
-        DeviceConfig.addOnPropertiesChangedListener(
-                DeviceConfig.NAMESPACE_PRIVACY,
-                context.mainExecutor,
-                devicePropertiesChangedListener)
-    }
-
-    private fun unregisterReceiver() {
-        broadcastDispatcher.unregisterReceiver(userSwitcherReceiver)
-    }
-
-    private fun registerReceiver() {
-        broadcastDispatcher.registerReceiver(userSwitcherReceiver, IntentFilter().apply {
-            intents.forEach {
-                addAction(it)
-            }
-        }, null /* handler */, UserHandle.ALL)
-    }
-
-    private fun update(updateUsers: Boolean) {
-        if (updateUsers) {
-            val currentUser = ActivityManager.getCurrentUser()
-            currentUserIds = userManager.getProfiles(currentUser).map { it.id }
-        }
-        bgHandler.post(updateListAndNotifyChanges)
-    }
-
-    /**
-     * Updates listening status based on whether there are callbacks and the indicators are enabled
-     *
-     * This is only called from private (add/remove)Callback and from the config listener, all in
-     * main thread.
-     */
-    private fun setListeningState() {
-        val listen = !callbacks.isEmpty() and indicatorsAvailable
-        if (listening == listen) return
-        listening = listen
-        if (listening) {
-            appOpsController.addCallback(OPS, cb)
-            registerReceiver()
-            update(true)
-        } else {
-            appOpsController.removeCallback(OPS, cb)
-            unregisterReceiver()
-            // Make sure that we remove all indicators and notify listeners if we are not
-            // listening anymore due to indicators being disabled
-            update(false)
-        }
-    }
-
-    private fun addCallback(callback: WeakReference<Callback>) {
-        callbacks.add(callback)
-        if (callbacks.isNotEmpty() && !listening) {
-            messageHandler.removeMessages(MSG_UPDATE_LISTENING_STATE)
-            messageHandler.sendEmptyMessage(MSG_UPDATE_LISTENING_STATE)
-        }
-        // Notify this callback if we didn't set to listening
-        else if (listening) uiHandler.post(NotifyChangesToCallback(callback.get(), privacyList))
-    }
-
-    private fun removeCallback(callback: WeakReference<Callback>) {
-        // Removes also if the callback is null
-        callbacks.removeIf { it.get()?.equals(callback.get()) ?: true }
-        if (callbacks.isEmpty()) {
-            messageHandler.removeMessages(MSG_UPDATE_LISTENING_STATE)
-            messageHandler.sendEmptyMessage(MSG_UPDATE_LISTENING_STATE)
-        }
-    }
-
-    fun addCallback(callback: Callback) {
-        messageHandler.obtainMessage(MSG_ADD_CALLBACK, callback).sendToTarget()
-    }
-
-    fun removeCallback(callback: Callback) {
-        messageHandler.obtainMessage(MSG_REMOVE_CALLBACK, callback).sendToTarget()
-    }
-
-    private fun updatePrivacyList() {
-        if (!listening) {
-            privacyList = emptyList()
-            return
-        }
-        val list = currentUserIds.flatMap { appOpsController.getActiveAppOpsForUser(it) }
-                .mapNotNull { toPrivacyItem(it) }.distinct()
-        privacyList = list
-    }
-
-    private fun toPrivacyItem(appOpItem: AppOpItem): PrivacyItem? {
-        val type: PrivacyType = when (appOpItem.code) {
-            AppOpsManager.OP_CAMERA -> PrivacyType.TYPE_CAMERA
-            AppOpsManager.OP_COARSE_LOCATION -> PrivacyType.TYPE_LOCATION
-            AppOpsManager.OP_FINE_LOCATION -> PrivacyType.TYPE_LOCATION
-            AppOpsManager.OP_RECORD_AUDIO -> PrivacyType.TYPE_MICROPHONE
-            else -> return null
-        }
-        if (appOpItem.uid == SYSTEM_UID) return PrivacyItem(type, systemApp)
-        val app = PrivacyApplication(appOpItem.packageName, appOpItem.uid, context)
-        return PrivacyItem(type, app)
-    }
-
-    // Used by containing class to get notified of changes
-    interface Callback {
-        fun privacyChanged(privacyItems: List<PrivacyItem>)
-    }
-
-    internal inner class Receiver : BroadcastReceiver() {
-        override fun onReceive(context: Context?, intent: Intent?) {
-            if (intent?.action in intents) {
-                update(true)
-            }
-        }
-    }
-
-    private class NotifyChangesToCallback(
-        private val callback: Callback?,
-        private val list: List<PrivacyItem>
-    ) : Runnable {
-        override fun run() {
-            callback?.privacyChanged(list)
-        }
-    }
-
-    override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
-        pw.println("PrivacyItemController state:")
-        pw.println("  Listening: $listening")
-        pw.println("  Current user ids: $currentUserIds")
-        pw.println("  Privacy Items:")
-        privacyList.forEach {
-            pw.print("    ")
-            pw.println(it.toString())
-        }
-        pw.println("  Callbacks:")
-        callbacks.forEach {
-            it.get()?.let {
-                pw.print("    ")
-                pw.println(it.toString())
-            }
-        }
-    }
-
-    private class H(
-        private val outerClass: WeakReference<PrivacyItemController>,
-        looper: Looper
-    ) : Handler(looper) {
-        override fun handleMessage(msg: Message) {
-            super.handleMessage(msg)
-            when (msg.what) {
-                MSG_UPDATE_LISTENING_STATE -> outerClass.get()?.setListeningState()
-
-                MSG_ADD_CALLBACK -> {
-                    if (msg.obj !is PrivacyItemController.Callback) return
-                    outerClass.get()?.addCallback(
-                            WeakReference(msg.obj as PrivacyItemController.Callback))
-                }
-
-                MSG_REMOVE_CALLBACK -> {
-                    if (msg.obj !is PrivacyItemController.Callback) return
-                    outerClass.get()?.removeCallback(
-                            WeakReference(msg.obj as PrivacyItemController.Callback))
-                }
-                else -> {}
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index 60d30da..019cb14 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -28,6 +28,7 @@
 import android.util.SparseArray;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewStub;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -58,7 +59,8 @@
 
     protected View mQsDetailHeader;
     protected TextView mQsDetailHeaderTitle;
-    protected Switch mQsDetailHeaderSwitch;
+    private ViewStub mQsDetailHeaderSwitchStub;
+    private Switch mQsDetailHeaderSwitch;
     protected ImageView mQsDetailHeaderProgress;
 
     protected QSTileHost mHost;
@@ -98,7 +100,7 @@
 
         mQsDetailHeader = findViewById(R.id.qs_detail_header);
         mQsDetailHeaderTitle = (TextView) mQsDetailHeader.findViewById(android.R.id.title);
-        mQsDetailHeaderSwitch = (Switch) mQsDetailHeader.findViewById(android.R.id.toggle);
+        mQsDetailHeaderSwitchStub = mQsDetailHeader.findViewById(R.id.toggle_stub);
         mQsDetailHeaderProgress = findViewById(R.id.qs_detail_header_progress);
 
         updateDetailText();
@@ -252,9 +254,12 @@
         mQsDetailHeaderTitle.setText(adapter.getTitle());
         final Boolean toggleState = adapter.getToggleState();
         if (toggleState == null) {
-            mQsDetailHeaderSwitch.setVisibility(INVISIBLE);
+            if (mQsDetailHeaderSwitch != null) mQsDetailHeaderSwitch.setVisibility(INVISIBLE);
             mQsDetailHeader.setClickable(false);
         } else {
+            if (mQsDetailHeaderSwitch == null) {
+                mQsDetailHeaderSwitch = (Switch) mQsDetailHeaderSwitchStub.inflate();
+            }
             mQsDetailHeaderSwitch.setVisibility(VISIBLE);
             handleToggleStateChanged(toggleState, adapter.getToggleEnabled());
             mQsDetailHeader.setClickable(true);
@@ -274,9 +279,9 @@
         if (mAnimatingOpen) {
             return;
         }
-        mQsDetailHeaderSwitch.setChecked(state);
+        if (mQsDetailHeaderSwitch != null) mQsDetailHeaderSwitch.setChecked(state);
         mQsDetailHeader.setEnabled(toggleEnabled);
-        mQsDetailHeaderSwitch.setEnabled(toggleEnabled);
+        if (mQsDetailHeaderSwitch != null) mQsDetailHeaderSwitch.setEnabled(toggleEnabled);
     }
 
     private void handleScanStateChanged(boolean state) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
index 1a4c327..f7e4c79 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
@@ -18,8 +18,11 @@
 
 import android.app.Notification;
 import android.app.PendingIntent;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.content.res.ColorStateList;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -35,6 +38,7 @@
 import android.media.session.PlaybackState;
 import android.text.TextUtils;
 import android.util.Log;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -54,6 +58,8 @@
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
 
+import java.util.List;
+
 /**
  * Single media player for carousel in QSPanel
  */
@@ -70,6 +76,83 @@
     private int mHeight;
     private int mForegroundColor;
     private int mBackgroundColor;
+    private ComponentName mRecvComponent;
+    private QSPanel mParent;
+
+    private MediaController.Callback mSessionCallback = new MediaController.Callback() {
+        @Override
+        public void onSessionDestroyed() {
+            Log.d(TAG, "session destroyed");
+            mController.unregisterCallback(mSessionCallback);
+
+            // Hide all the old buttons
+            final int[] actionIds = {
+                    R.id.action0,
+                    R.id.action1,
+                    R.id.action2,
+                    R.id.action3,
+                    R.id.action4
+            };
+            for (int i = 0; i < actionIds.length; i++) {
+                ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
+                if (thisBtn != null) {
+                    thisBtn.setVisibility(View.GONE);
+                }
+            }
+
+            // Add a restart button
+            ImageButton btn = mMediaNotifView.findViewById(actionIds[0]);
+            btn.setOnClickListener(v -> {
+                Log.d(TAG, "Attempting to restart session");
+                // Send a media button event to previously found receiver
+                if (mRecvComponent != null) {
+                    Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+                    intent.setComponent(mRecvComponent);
+                    int keyCode = KeyEvent.KEYCODE_MEDIA_PLAY;
+                    intent.putExtra(
+                            Intent.EXTRA_KEY_EVENT,
+                            new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
+                    mContext.sendBroadcast(intent);
+                } else {
+                    Log.d(TAG, "No receiver to restart");
+                    // If we don't have a receiver, try relaunching the activity instead
+                    try {
+                        mController.getSessionActivity().send();
+                    } catch (PendingIntent.CanceledException e) {
+                        Log.e(TAG, "Pending intent was canceled");
+                        e.printStackTrace();
+                    }
+                }
+            });
+            btn.setImageDrawable(mContext.getResources().getDrawable(R.drawable.lb_ic_replay));
+            btn.setImageTintList(ColorStateList.valueOf(mForegroundColor));
+            btn.setVisibility(View.VISIBLE);
+
+            // Add long-click option to remove the player
+            ViewGroup mMediaCarousel = (ViewGroup) mMediaNotifView.getParent();
+            mMediaNotifView.setOnLongClickListener(v -> {
+                // Replace player view with delete/cancel view
+                v.setVisibility(View.GONE);
+
+                View options = LayoutInflater.from(mContext).inflate(
+                        R.layout.qs_media_panel_options, null, false);
+                ImageButton btnDelete = options.findViewById(R.id.remove);
+                btnDelete.setOnClickListener(b -> {
+                    mMediaCarousel.removeView(options);
+                    mParent.removeMediaPlayer(QSMediaPlayer.this);
+                });
+                ImageButton btnCancel = options.findViewById(R.id.cancel);
+                btnCancel.setOnClickListener(b -> {
+                    mMediaCarousel.removeView(options);
+                    v.setVisibility(View.VISIBLE);
+                });
+
+                int pos = mMediaCarousel.indexOfChild(v);
+                mMediaCarousel.addView(options, pos, v.getLayoutParams());
+                return true; // consumed click
+            });
+        }
+    };
 
     /**
      *
@@ -92,7 +175,8 @@
     }
 
     /**
-     *
+     * Create or update the player view for the given media session
+     * @param parent the parent QSPanel
      * @param token token for this media session
      * @param icon app notification icon
      * @param iconColor foreground color (for text, icons)
@@ -101,13 +185,30 @@
      * @param notif reference to original notification
      * @param device current playback device
      */
-    public void setMediaSession(MediaSession.Token token, Icon icon, int iconColor, int bgColor,
-            View actionsContainer, Notification notif, MediaDevice device) {
-        Log.d(TAG, "got media session: " + token);
+    public void setMediaSession(QSPanel parent, MediaSession.Token token, Icon icon, int iconColor,
+            int bgColor, View actionsContainer, Notification notif, MediaDevice device) {
+        mParent = parent;
         mToken = token;
         mForegroundColor = iconColor;
         mBackgroundColor = bgColor;
         mController = new MediaController(mContext, token);
+
+        // Try to find a receiver for the media button that matches this app
+        PackageManager pm = mContext.getPackageManager();
+        Intent it = new Intent(Intent.ACTION_MEDIA_BUTTON);
+        List<ResolveInfo> info = pm.queryBroadcastReceiversAsUser(it, 0, mContext.getUser());
+        if (info != null) {
+            for (ResolveInfo inf : info) {
+                if (inf.activityInfo.packageName.equals(notif.contentIntent.getCreatorPackage())) {
+                    Log.d(TAG, "Found receiver for package: " + inf);
+                    mRecvComponent = inf.getComponentInfo().getComponentName();
+                }
+            }
+        }
+
+        // reset in case we had previously restarted the stream
+        mMediaNotifView.setOnLongClickListener(null);
+        mController.registerCallback(mSessionCallback);
         MediaMetadata mMediaMetadata = mController.getMetadata();
         if (mMediaMetadata == null) {
             Log.e(TAG, "Media metadata was null");
@@ -235,7 +336,6 @@
         for (; i < actionIds.length; i++) {
             ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
             thisBtn.setVisibility(View.GONE);
-            Log.d(TAG, "hid a button");
         }
     }
 
@@ -266,8 +366,9 @@
 
     private void addAlbumArtBackground(MediaMetadata metadata, int bgColor, int width, int height) {
         Bitmap albumArt = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
+        float radius = mContext.getResources().getDimension(R.dimen.qs_media_corner_radius);
         if (albumArt != null) {
-
+            Log.d(TAG, "updating album art");
             Bitmap original = albumArt.copy(Bitmap.Config.ARGB_8888, true);
             Bitmap scaled = scaleBitmap(original, width, height);
             Canvas canvas = new Canvas(scaled);
@@ -281,12 +382,15 @@
 
             RoundedBitmapDrawable roundedDrawable = RoundedBitmapDrawableFactory.create(
                     mContext.getResources(), scaled);
-            roundedDrawable.setCornerRadius(20);
+            roundedDrawable.setCornerRadius(radius);
 
             mMediaNotifView.setBackground(roundedDrawable);
         } else {
             Log.e(TAG, "No album art available");
-            mMediaNotifView.setBackground(null);
+            GradientDrawable rect = new GradientDrawable();
+            rect.setCornerRadius(radius);
+            rect.setColor(bgColor);
+            mMediaNotifView.setBackground(rect);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 5e98f93..51e352b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -284,7 +284,7 @@
         }
 
         Log.d(TAG, "setting player session");
-        player.setMediaSession(token, icon, iconColor, bgColor, actionsContainer,
+        player.setMediaSession(this, token, icon, iconColor, bgColor, actionsContainer,
                 notif.getNotification(), mDevice);
 
         if (mMediaPlayers.size() > 0) {
@@ -303,6 +303,27 @@
         return mMediaCarousel;
     }
 
+    /**
+     * Remove the media player from the carousel
+     * @param player Player to remove
+     * @return true if removed, false if player was not found
+     */
+    protected boolean removeMediaPlayer(QSMediaPlayer player) {
+        // Remove from list
+        if (!mMediaPlayers.remove(player)) {
+            return false;
+        }
+
+        // Check if we need to collapse the carousel now
+        mMediaCarousel.removeView(player.getView());
+        if (mMediaPlayers.size() == 0) {
+            ((View) mMediaCarousel.getParent()).setVisibility(View.GONE);
+            mLocalMediaManager.stopScan();
+            mLocalMediaManager.unregisterCallback(mDeviceCallback);
+        }
+        return true;
+    }
+
     protected void addDivider() {
         mDivider = LayoutInflater.from(mContext).inflate(R.layout.qs_divider, this, false);
         mDivider.setBackgroundColor(Utils.applyAlpha(mDivider.getAlpha(),
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
index d7b8b83..d40e250 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
@@ -16,19 +16,27 @@
 
 package com.android.systemui.qs;
 
+import android.app.PendingIntent;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.ColorStateList;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
 import android.graphics.drawable.Icon;
 import android.media.MediaMetadata;
 import android.media.session.MediaController;
 import android.media.session.MediaSession;
 import android.media.session.PlaybackState;
 import android.util.Log;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -42,6 +50,8 @@
 
 import com.android.systemui.R;
 
+import java.util.List;
+
 /**
  * QQS mini media player
  */
@@ -53,6 +63,54 @@
     private LinearLayout mMediaNotifView;
     private MediaSession.Token mToken;
     private MediaController mController;
+    private int mBackgroundColor;
+    private int mForegroundColor;
+    private ComponentName mRecvComponent;
+
+    private MediaController.Callback mSessionCallback = new MediaController.Callback() {
+        @Override
+        public void onSessionDestroyed() {
+            Log.d(TAG, "session destroyed");
+            mController.unregisterCallback(mSessionCallback);
+
+            // Hide all the old buttons
+            final int[] actionIds = {R.id.action0, R.id.action1, R.id.action2};
+            for (int i = 0; i < actionIds.length; i++) {
+                ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
+                if (thisBtn != null) {
+                    thisBtn.setVisibility(View.GONE);
+                }
+            }
+
+            // Add a restart button
+            ImageButton btn = mMediaNotifView.findViewById(actionIds[0]);
+            btn.setOnClickListener(v -> {
+                Log.d(TAG, "Attempting to restart session");
+                // Send a media button event to previously found receiver
+                if (mRecvComponent != null) {
+                    Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+                    intent.setComponent(mRecvComponent);
+                    int keyCode = KeyEvent.KEYCODE_MEDIA_PLAY;
+                    intent.putExtra(
+                            Intent.EXTRA_KEY_EVENT,
+                            new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
+                    mContext.sendBroadcast(intent);
+                } else {
+                    Log.d(TAG, "No receiver to restart");
+                    // If we don't have a receiver, try relaunching the activity instead
+                    try {
+                        mController.getSessionActivity().send();
+                    } catch (PendingIntent.CanceledException e) {
+                        Log.e(TAG, "Pending intent was canceled");
+                        e.printStackTrace();
+                    }
+                }
+            });
+            btn.setImageDrawable(mContext.getResources().getDrawable(R.drawable.lb_ic_replay));
+            btn.setImageTintList(ColorStateList.valueOf(mForegroundColor));
+            btn.setVisibility(View.VISIBLE);
+        }
+    };
 
     /**
      *
@@ -83,34 +141,50 @@
             View actionsContainer, int[] actionsToShow) {
         Log.d(TAG, "Setting media session: " + token);
         mToken = token;
+        mForegroundColor = iconColor;
+        mBackgroundColor = bgColor;
         mController = new MediaController(mContext, token);
         MediaMetadata mMediaMetadata = mController.getMetadata();
 
+        // Try to find a receiver for the media button that matches this app
+        PackageManager pm = mContext.getPackageManager();
+        Intent it = new Intent(Intent.ACTION_MEDIA_BUTTON);
+        List<ResolveInfo> info = pm.queryBroadcastReceiversAsUser(it, 0, mContext.getUser());
+        if (info != null) {
+            for (ResolveInfo inf : info) {
+                if (inf.activityInfo.packageName.equals(mController.getPackageName())) {
+                    Log.d(TAG, "Found receiver for package: " + inf);
+                    mRecvComponent = inf.getComponentInfo().getComponentName();
+                }
+            }
+        }
+        mController.registerCallback(mSessionCallback);
+
         if (mMediaMetadata == null) {
             Log.e(TAG, "Media metadata was null");
             return;
         }
 
         // Album art
-        addAlbumArtBackground(mMediaMetadata, bgColor);
+        addAlbumArtBackground(mMediaMetadata, mBackgroundColor);
 
         // App icon
         ImageView appIcon = mMediaNotifView.findViewById(R.id.icon);
         Drawable iconDrawable = icon.loadDrawable(mContext);
-        iconDrawable.setTint(iconColor);
+        iconDrawable.setTint(mForegroundColor);
         appIcon.setImageDrawable(iconDrawable);
 
         // Artist name
         TextView appText = mMediaNotifView.findViewById(R.id.header_title);
         String artistName = mMediaMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
         appText.setText(artistName);
-        appText.setTextColor(iconColor);
+        appText.setTextColor(mForegroundColor);
 
         // Song name
         TextView titleText = mMediaNotifView.findViewById(R.id.header_text);
         String songName = mMediaMetadata.getString(MediaMetadata.METADATA_KEY_TITLE);
         titleText.setText(songName);
-        titleText.setTextColor(iconColor);
+        titleText.setTextColor(mForegroundColor);
 
         // Buttons we can display
         final int[] actionIds = {R.id.action0, R.id.action1, R.id.action2};
@@ -176,8 +250,17 @@
         return (state.getState() == PlaybackState.STATE_PLAYING);
     }
 
+    /**
+     * Check whether this player has an attached media session.
+     * @return whether there is a controller with a current media session.
+     */
+    public boolean hasMediaSession() {
+        return mController != null && mController.getPlaybackState() != null;
+    }
+
     private void addAlbumArtBackground(MediaMetadata metadata, int bgColor) {
         Bitmap albumArt = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
+        float radius = mContext.getResources().getDimension(R.dimen.qs_media_corner_radius);
         if (albumArt != null) {
             Rect bounds = new Rect();
             mMediaNotifView.getBoundsOnScreen(bounds);
@@ -197,12 +280,15 @@
 
             RoundedBitmapDrawable roundedDrawable = RoundedBitmapDrawableFactory.create(
                     mContext.getResources(), scaled);
-            roundedDrawable.setCornerRadius(20);
+            roundedDrawable.setCornerRadius(radius);
 
             mMediaNotifView.setBackground(roundedDrawable);
         } else {
             Log.e(TAG, "No album art available");
-            mMediaNotifView.setBackground(null);
+            GradientDrawable rect = new GradientDrawable();
+            rect.setCornerRadius(radius);
+            rect.setColor(bgColor);
+            mMediaNotifView.setBackground(rect);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index d377f1c..feb10a2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -57,6 +57,12 @@
     private int mMaxTiles;
     protected QSPanel mFullPanel;
     private QuickQSMediaPlayer mMediaPlayer;
+    private boolean mUsingMediaPlayer;
+    private LinearLayout mHorizontalLinearLayout;
+
+    // Only used with media
+    private QSTileLayout mMediaTileLayout;
+    private QSTileLayout mRegularTileLayout;
 
     @Inject
     public QuickQSPanel(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
@@ -72,8 +78,9 @@
             removeView((View) mTileLayout);
         }
 
-        if (Utils.useQsMediaPlayer(context)) {
-            LinearLayout mHorizontalLinearLayout = new LinearLayout(mContext);
+        mUsingMediaPlayer = Utils.useQsMediaPlayer(context);
+        if (mUsingMediaPlayer) {
+            mHorizontalLinearLayout = new LinearLayout(mContext);
             mHorizontalLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
             mHorizontalLinearLayout.setClipChildren(false);
             mHorizontalLinearLayout.setClipToPadding(false);
@@ -81,6 +88,8 @@
             LayoutParams lp = new LayoutParams(0, LayoutParams.MATCH_PARENT, 1);
 
             mTileLayout = new DoubleLineTileLayout(context);
+            mMediaTileLayout = mTileLayout;
+            mRegularTileLayout = new HeaderTileLayout(context);
             lp.setMarginEnd(10);
             lp.setMarginStart(0);
             mHorizontalLinearLayout.addView((View) mTileLayout, lp);
@@ -95,6 +104,8 @@
 
             mTileLayout.setListening(mListening);
             addView(mHorizontalLinearLayout, 0 /* Between brightness and footer */);
+            ((View) mRegularTileLayout).setVisibility(View.GONE);
+            addView((View) mRegularTileLayout, 0);
             super.setPadding(0, 0, 0, 0);
         } else {
             sDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
@@ -130,6 +141,8 @@
         Dependency.get(TunerService.class).removeTunable(mNumTiles);
     }
 
+
+
     @Override
     protected String getDumpableTag() {
         return TAG;
@@ -152,6 +165,42 @@
         super.drawTile(r, state);
     }
 
+    boolean switchTileLayout() {
+        if (!mUsingMediaPlayer) return false;
+        if (mMediaPlayer.hasMediaSession()
+                && mHorizontalLinearLayout.getVisibility() == View.GONE) {
+            mHorizontalLinearLayout.setVisibility(View.VISIBLE);
+            ((View) mRegularTileLayout).setVisibility(View.GONE);
+            mTileLayout.setListening(false);
+            for (TileRecord record : mRecords) {
+                mTileLayout.removeTile(record);
+                record.tile.removeCallback(record.callback);
+            }
+            mTileLayout = mMediaTileLayout;
+            setTiles(mHost.getTiles());
+            mTileLayout.setListening(mListening);
+            return true;
+        } else if (!mMediaPlayer.hasMediaSession()
+                && mHorizontalLinearLayout.getVisibility() == View.VISIBLE) {
+            mHorizontalLinearLayout.setVisibility(View.GONE);
+            ((View) mRegularTileLayout).setVisibility(View.VISIBLE);
+            mTileLayout.setListening(false);
+            for (TileRecord record : mRecords) {
+                mTileLayout.removeTile(record);
+                record.tile.removeCallback(record.callback);
+            }
+            mTileLayout = mRegularTileLayout;
+            setTiles(mHost.getTiles());
+            mTileLayout.setListening(mListening);
+            return true;
+        }
+        return false;
+    }
+
+    public boolean hasMediaPlayerSession() {
+        return mMediaPlayer.hasMediaSession();
+    }
+
     @Override
     public void setHost(QSTileHost host, QSCustomizer customizer) {
         super.setHost(host, customizer);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 02e8f59..d4af154 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -33,30 +33,24 @@
 import android.graphics.Rect;
 import android.media.AudioManager;
 import android.os.Handler;
-import android.os.Looper;
 import android.provider.AlarmClock;
-import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.service.notification.ZenModeConfig;
 import android.text.format.DateUtils;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Pair;
-import android.util.StatsLog;
 import android.view.ContextThemeWrapper;
 import android.view.DisplayCutout;
 import android.view.View;
 import android.view.WindowInsets;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
-import android.widget.LinearLayout;
 import android.widget.RelativeLayout;
-import android.widget.Space;
 import android.widget.TextView;
 
 import androidx.annotation.VisibleForTesting;
 
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.settingslib.Utils;
 import com.android.systemui.BatteryMeterView;
 import com.android.systemui.DualToneHandler;
@@ -65,11 +59,6 @@
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.privacy.OngoingPrivacyChip;
-import com.android.systemui.privacy.PrivacyDialogBuilder;
-import com.android.systemui.privacy.PrivacyItem;
-import com.android.systemui.privacy.PrivacyItemController;
-import com.android.systemui.privacy.PrivacyItemControllerKt;
 import com.android.systemui.qs.QSDetail.Callback;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.PhoneStatusBarView;
@@ -145,12 +134,8 @@
     private View mRingerContainer;
     private Clock mClockView;
     private DateView mDateView;
-    private OngoingPrivacyChip mPrivacyChip;
-    private Space mSpace;
     private BatteryMeterView mBatteryRemainingIcon;
-    private boolean mPermissionsHubEnabled;
 
-    private PrivacyItemController mPrivacyItemController;
     private BroadcastDispatcher mBroadcastDispatcher;
 
     private final BroadcastReceiver mRingerReceiver = new BroadcastReceiver() {
@@ -161,43 +146,18 @@
         }
     };
     private boolean mHasTopCutout = false;
-    private boolean mPrivacyChipLogged = false;
-
-    private final DeviceConfig.OnPropertiesChangedListener mPropertiesListener =
-            new DeviceConfig.OnPropertiesChangedListener() {
-                @Override
-                public void onPropertiesChanged(DeviceConfig.Properties properties) {
-                    if (DeviceConfig.NAMESPACE_PRIVACY.equals(properties.getNamespace())
-                            && properties.getKeyset()
-                            .contains(SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED)) {
-                        mPermissionsHubEnabled = properties.getBoolean(
-                                SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, false);
-                        StatusIconContainer iconContainer = findViewById(R.id.statusIcons);
-                        iconContainer.setIgnoredSlots(getIgnoredIconSlots());
-                    }
-                }
-            };
-
-    private PrivacyItemController.Callback mPICCallback = new PrivacyItemController.Callback() {
-        @Override
-        public void privacyChanged(List<PrivacyItem> privacyItems) {
-            mPrivacyChip.setPrivacyList(privacyItems);
-            setChipVisibility(!privacyItems.isEmpty());
-        }
-    };
 
     @Inject
     public QuickStatusBarHeader(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
             NextAlarmController nextAlarmController, ZenModeController zenModeController,
             StatusBarIconController statusBarIconController,
-            ActivityStarter activityStarter, PrivacyItemController privacyItemController,
+            ActivityStarter activityStarter,
             CommandQueue commandQueue, BroadcastDispatcher broadcastDispatcher) {
         super(context, attrs);
         mAlarmController = nextAlarmController;
         mZenController = zenModeController;
         mStatusBarIconController = statusBarIconController;
         mActivityStarter = activityStarter;
-        mPrivacyItemController = privacyItemController;
         mDualToneHandler = new DualToneHandler(
                 new ContextThemeWrapper(context, R.style.QSHeaderTheme));
         mBroadcastDispatcher = broadcastDispatcher;
@@ -228,11 +188,8 @@
         mRingerModeTextView = findViewById(R.id.ringer_mode_text);
         mRingerContainer = findViewById(R.id.ringer_container);
         mRingerContainer.setOnClickListener(this::onClick);
-        mPrivacyChip = findViewById(R.id.privacy_chip);
-        mPrivacyChip.setOnClickListener(this::onClick);
         mCarrierGroup = findViewById(R.id.carrier_group);
 
-
         updateResources();
 
         Rect tintArea = new Rect(0, 0, 0, 0);
@@ -252,7 +209,6 @@
         mClockView = findViewById(R.id.clock);
         mClockView.setOnClickListener(this);
         mDateView = findViewById(R.id.date);
-        mSpace = findViewById(R.id.space);
 
         // Tint for the battery icons are handled in setupHost()
         mBatteryRemainingIcon = findViewById(R.id.batteryRemainingIcon);
@@ -263,8 +219,6 @@
         mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE);
         mRingerModeTextView.setSelected(true);
         mNextAlarmTextView.setSelected(true);
-
-        mPermissionsHubEnabled = PrivacyItemControllerKt.isPermissionsHubEnabled();
     }
 
     private List<String> getIgnoredIconSlots() {
@@ -273,10 +227,6 @@
                 com.android.internal.R.string.status_bar_camera));
         ignored.add(mContext.getResources().getString(
                 com.android.internal.R.string.status_bar_microphone));
-        if (mPermissionsHubEnabled) {
-            ignored.add(mContext.getResources().getString(
-                    com.android.internal.R.string.status_bar_location));
-        }
 
         return ignored;
     }
@@ -292,21 +242,6 @@
         }
     }
 
-    private void setChipVisibility(boolean chipVisible) {
-        if (chipVisible && mPermissionsHubEnabled) {
-            mPrivacyChip.setVisibility(View.VISIBLE);
-            // Makes sure that the chip is logged as viewed at most once each time QS is opened
-            // mListening makes sure that the callback didn't return after the user closed QS
-            if (!mPrivacyChipLogged && mListening) {
-                mPrivacyChipLogged = true;
-                StatsLog.write(StatsLog.PRIVACY_INDICATORS_INTERACTED,
-                        StatsLog.PRIVACY_INDICATORS_INTERACTED__TYPE__CHIP_VIEWED);
-            }
-        } else {
-            mPrivacyChip.setVisibility(View.GONE);
-        }
-    }
-
     private boolean updateRingerStatus() {
         boolean isOriginalVisible = mRingerModeTextView.getVisibility() == View.VISIBLE;
         CharSequence originalRingerText = mRingerModeTextView.getText();
@@ -404,7 +339,7 @@
         if (mQsDisabled) {
             lp.height = resources.getDimensionPixelSize(
                     com.android.internal.R.dimen.quick_qs_offset_height);
-        } else if (useQsMediaPlayer(mContext)) {
+        } else if (useQsMediaPlayer(mContext) && mHeaderQsPanel.hasMediaPlayerSession()) {
             lp.height = Math.max(getMinimumHeight(),
                     resources.getDimensionPixelSize(
                             com.android.internal.R.dimen.quick_qs_total_height_with_media));
@@ -418,7 +353,6 @@
 
         updateStatusIconAlphaAnimator();
         updateHeaderTextContainerAlphaAnimator();
-        updatePrivacyChipAlphaAnimator();
     }
 
     private void updateStatusIconAlphaAnimator() {
@@ -433,12 +367,6 @@
                 .build();
     }
 
-    private void updatePrivacyChipAlphaAnimator() {
-        mPrivacyChipAlphaAnimator = new TouchAnimator.Builder()
-                .addFloat(mPrivacyChip, "alpha", 1, 0, 1)
-                .build();
-    }
-
     public void setExpanded(boolean expanded) {
         if (mExpanded == expanded) return;
         mExpanded = expanded;
@@ -477,9 +405,10 @@
                 mHeaderTextContainerView.setVisibility(INVISIBLE);
             }
         }
-        if (mPrivacyChipAlphaAnimator != null) {
-            mPrivacyChip.setExpanded(expansionFraction > 0.5);
-            mPrivacyChipAlphaAnimator.setPosition(keyguardExpansionFraction);
+        if (expansionFraction < 1 && expansionFraction > 0.99) {
+            if (mHeaderQsPanel.switchTileLayout()) {
+                updateResources();
+            }
         }
     }
 
@@ -498,9 +427,6 @@
         super.onAttachedToWindow();
         mStatusBarIconController.addIconGroup(mIconManager);
         requestApplyInsets();
-        // Change the ignored slots when DeviceConfig flag changes
-        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_PRIVACY,
-                mContext.getMainExecutor(), mPropertiesListener);
     }
 
     @Override
@@ -516,21 +442,6 @@
             mSystemIconsView.setPadding(padding.first, 0, padding.second, 0);
 
         }
-        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mSpace.getLayoutParams();
-        if (cutout != null) {
-            Rect topCutout = cutout.getBoundingRectTop();
-            if (topCutout.isEmpty()) {
-                mHasTopCutout = false;
-                lp.width = 0;
-                mSpace.setVisibility(View.GONE);
-            } else {
-                mHasTopCutout = true;
-                lp.width = topCutout.width();
-                mSpace.setVisibility(View.VISIBLE);
-            }
-        }
-        mSpace.setLayoutParams(lp);
-        setChipVisibility(mPrivacyChip.getVisibility() == View.VISIBLE);
         return super.onApplyWindowInsets(insets);
     }
 
@@ -539,7 +450,6 @@
     public void onDetachedFromWindow() {
         setListening(false);
         mStatusBarIconController.removeIconGroup(mIconManager);
-        DeviceConfig.removeOnPropertiesChangedListener(mPropertiesListener);
         super.onDetachedFromWindow();
     }
 
@@ -548,6 +458,9 @@
             return;
         }
         mHeaderQsPanel.setListening(listening);
+        if (mHeaderQsPanel.switchTileLayout()) {
+            updateResources();
+        }
         mListening = listening;
 
         if (listening) {
@@ -555,13 +468,10 @@
             mAlarmController.addCallback(this);
             mBroadcastDispatcher.registerReceiver(mRingerReceiver,
                     new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
-            mPrivacyItemController.addCallback(mPICCallback);
         } else {
             mZenController.removeCallback(this);
             mAlarmController.removeCallback(this);
-            mPrivacyItemController.removeCallback(mPICCallback);
             mBroadcastDispatcher.unregisterReceiver(mRingerReceiver);
-            mPrivacyChipLogged = false;
         }
     }
 
@@ -579,18 +489,6 @@
                 mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
                         AlarmClock.ACTION_SHOW_ALARMS), 0);
             }
-        } else if (v == mPrivacyChip) {
-            // Makes sure that the builder is grabbed as soon as the chip is pressed
-            PrivacyDialogBuilder builder = mPrivacyChip.getBuilder();
-            if (builder.getAppsAndTypes().size() == 0) return;
-            Handler mUiHandler = new Handler(Looper.getMainLooper());
-            StatsLog.write(StatsLog.PRIVACY_INDICATORS_INTERACTED,
-                    StatsLog.PRIVACY_INDICATORS_INTERACTED__TYPE__CHIP_CLICKED);
-            mUiHandler.post(() -> {
-                mActivityStarter.postStartActivityDismissingKeyguard(
-                        new Intent(Intent.ACTION_REVIEW_ONGOING_PERMISSION_USAGE), 0);
-                mHost.collapsePanels();
-            });
         } else if (v == mRingerContainer && mRingerContainer.isVisibleToUser()) {
             mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
                     Settings.ACTION_SOUND_SETTINGS), 0);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
index 20e3cee..47cb45b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
@@ -49,4 +49,9 @@
     protected boolean animationsEnabled() {
         return false;
     }
+
+    @Override
+    public boolean isLongClickable() {
+        return false;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index ff34be0..1de6355 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -32,6 +32,7 @@
 import android.widget.Toolbar;
 import android.widget.Toolbar.OnMenuItemClickListener;
 
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
 import androidx.recyclerview.widget.DefaultItemAnimator;
 import androidx.recyclerview.widget.GridLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
@@ -118,7 +119,13 @@
         mTileQueryHelper.setListener(mTileAdapter);
         mRecyclerView.setAdapter(mTileAdapter);
         mTileAdapter.getItemTouchHelper().attachToRecyclerView(mRecyclerView);
-        GridLayoutManager layout = new GridLayoutManager(getContext(), 3);
+        GridLayoutManager layout = new GridLayoutManager(getContext(), 3) {
+            @Override
+            public void onInitializeAccessibilityNodeInfoForItem(RecyclerView.Recycler recycler,
+                    RecyclerView.State state, View host, AccessibilityNodeInfoCompat info) {
+                // Do not read row and column every time it changes.
+            }
+        };
         layout.setSpanSizeLookup(mTileAdapter.getSizeLookup());
         mRecyclerView.setLayoutManager(layout);
         mRecyclerView.addItemDecoration(mTileAdapter.getItemDecoration());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index bd3297b..3afc460 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -238,9 +238,21 @@
         return true;
     }
 
+    private void setSelectableForHeaders(View view) {
+        if (mAccessibilityManager.isTouchExplorationEnabled()) {
+            final boolean selectable = mAccessibilityAction == ACTION_NONE;
+            view.setFocusable(selectable);
+            view.setImportantForAccessibility(selectable
+                    ? View.IMPORTANT_FOR_ACCESSIBILITY_YES
+                    : View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+            view.setFocusableInTouchMode(selectable);
+        }
+    }
+
     @Override
     public void onBindViewHolder(final Holder holder, int position) {
         if (holder.getItemViewType() == TYPE_HEADER) {
+            setSelectableForHeaders(holder.itemView);
             return;
         }
         if (holder.getItemViewType() == TYPE_DIVIDER) {
@@ -260,6 +272,8 @@
             }
 
             ((TextView) holder.itemView.findViewById(android.R.id.title)).setText(titleText);
+            setSelectableForHeaders(holder.itemView);
+
             return;
         }
         if (holder.getItemViewType() == TYPE_ACCESSIBLE_DROP) {
@@ -306,6 +320,7 @@
             holder.mTileView.setImportantForAccessibility(selectable
                     ? View.IMPORTANT_FOR_ACCESSIBILITY_YES
                     : View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+            holder.mTileView.setFocusableInTouchMode(selectable);
             if (selectable) {
                 holder.mTileView.setOnClickListener(new OnClickListener() {
                     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 0a9100f..f30c181 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -25,7 +25,6 @@
 import android.content.pm.ResolveInfo;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
-import android.os.Handler;
 import android.provider.Settings;
 import android.service.quicksettings.Tile;
 import android.service.quicksettings.TileService;
@@ -34,8 +33,8 @@
 import android.widget.Button;
 
 import com.android.systemui.R;
-import com.android.systemui.dagger.qualifiers.BgHandler;
-import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTile.State;
 import com.android.systemui.qs.QSTileHost;
@@ -47,6 +46,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
 
@@ -55,8 +55,8 @@
 
     private final ArrayList<TileInfo> mTiles = new ArrayList<>();
     private final ArraySet<String> mSpecs = new ArraySet<>();
-    private final Handler mBgHandler;
-    private final Handler mMainHandler;
+    private final Executor mMainExecutor;
+    private final Executor mBgExecutor;
     private final Context mContext;
     private TileStateListener mListener;
 
@@ -64,10 +64,10 @@
 
     @Inject
     public TileQueryHelper(Context context,
-            @MainHandler Handler mainHandler, @BgHandler Handler bgHandler) {
+            @Main Executor mainExecutor, @Background Executor bgExecutor) {
         mContext = context;
-        mMainHandler = mainHandler;
-        mBgHandler = bgHandler;
+        mMainExecutor = mainExecutor;
+        mBgExecutor = bgExecutor;
     }
 
     public void setListener(TileStateListener listener) {
@@ -126,7 +126,7 @@
             tilesToAdd.add(tile);
         }
 
-        mBgHandler.post(() -> {
+        mBgExecutor.execute(() -> {
             for (QSTile tile : tilesToAdd) {
                 final QSTile.State state = tile.getState().copy();
                 // Ignore the current state and get the generic label instead.
@@ -139,7 +139,7 @@
     }
 
     private void addPackageTiles(final QSTileHost host) {
-        mBgHandler.post(() -> {
+        mBgExecutor.execute(() -> {
             Collection<QSTile> params = host.getTiles();
             PackageManager pm = mContext.getPackageManager();
             List<ResolveInfo> services = pm.queryIntentServicesAsUser(
@@ -185,7 +185,7 @@
 
     private void notifyTilesChanged(final boolean finished) {
         final ArrayList<TileInfo> tilesToReturn = new ArrayList<>(mTiles);
-        mMainHandler.post(() -> {
+        mMainExecutor.execute(() -> {
             if (mListener != null) {
                 mListener.onTilesChanged(tilesToReturn);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
index dc9a2ce..9fe9703 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
@@ -22,6 +22,7 @@
 import android.provider.Settings;
 import android.service.quicksettings.Tile;
 import android.text.TextUtils;
+import android.widget.Switch;
 
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.systemui.R;
@@ -112,6 +113,7 @@
             state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         }
         state.showRippleEffect = false;
+        state.expandedAccessibilityClassName = Switch.class.getName();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
index fcdd234..f3e2f10 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
@@ -162,6 +162,8 @@
             if (runningTask.supportsSplitScreenMultiWindow) {
                 if (ActivityManagerWrapper.getInstance().setTaskWindowingModeSplitScreenPrimary(
                         runningTask.id, stackCreateMode, initialBounds)) {
+                    mDividerOptional.ifPresent(Divider::onDockedTopTask);
+
                     // The overview service is handling split screen, so just skip the wait for the
                     // first draw and notify the divider to start animating now
                     mDividerOptional.ifPresent(Divider::onRecentsDrawn);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index fedd855..5041354 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -804,8 +804,8 @@
             List<Notification.Action> actions = smartActionsFuture.get(timeoutMs,
                     TimeUnit.MILLISECONDS);
             long waitTimeMs = SystemClock.uptimeMillis() - startTimeMs;
-            Slog.d(TAG, String.format("Wait time for smart actions: %d ms",
-                    waitTimeMs));
+            Slog.d(TAG, String.format("Got %d smart actions. Wait time: %d ms",
+                    actions.size(), waitTimeMs));
             notifyScreenshotOp(screenshotId, smartActionsProvider,
                     ScreenshotNotificationSmartActionsProvider.ScreenshotOp.WAIT_FOR_SMART_ACTIONS,
                     ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.SUCCESS,
@@ -813,7 +813,8 @@
             return actions;
         } catch (Throwable e) {
             long waitTimeMs = SystemClock.uptimeMillis() - startTimeMs;
-            Slog.d(TAG, "Failed to obtain screenshot notification smart actions.", e);
+            Slog.e(TAG, String.format("Error getting smart actions. Wait time: %d ms", waitTimeMs),
+                    e);
             ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus status =
                     (e instanceof TimeoutException)
                             ? ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.TIMEOUT
@@ -942,14 +943,16 @@
     public static class SmartActionsReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
-            PendingIntent actionIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT);
+            PendingIntent pendingIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT);
+            Intent actionIntent = pendingIntent.getIntent();
+            String actionType = intent.getStringExtra(EXTRA_ACTION_TYPE);
+            Slog.d(TAG, "Executing smart action [" + actionType + "]:" + actionIntent);
             ActivityOptions opts = ActivityOptions.makeBasic();
-            context.startActivityAsUser(actionIntent.getIntent(), opts.toBundle(),
+            context.startActivityAsUser(actionIntent, opts.toBundle(),
                     UserHandle.CURRENT);
 
-            Slog.d(TAG, "Screenshot notification smart action is invoked.");
             notifyScreenshotAction(context, intent.getStringExtra(EXTRA_ID),
-                    intent.getStringExtra(EXTRA_ACTION_TYPE),
+                    actionType,
                     true);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
index d2268e1..76925b4 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
@@ -456,9 +456,9 @@
                     SystemUiDeviceConfigFlags
                             .SCREENSHOT_NOTIFICATION_SMART_ACTIONS_TIMEOUT_MS,
                     1000);
-            List<Notification.Action> smartActions = buildSmartActions(
-                    GlobalScreenshot.getSmartActions(mScreenshotId, smartActionsFuture,
-                            timeoutMs, mSmartActionsProvider), context);
+            List<Notification.Action> smartActions = GlobalScreenshot.getSmartActions(mScreenshotId,
+                    smartActionsFuture, timeoutMs, mSmartActionsProvider);
+            smartActions = buildSmartActions(smartActions, context);
             for (Notification.Action action : smartActions) {
                 notificationBuilder.addAction(action);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
index 341c49a..2005d79 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
@@ -17,14 +17,13 @@
 package com.android.systemui.statusbar;
 
 import android.annotation.NonNull;
-import android.os.Handler;
-import android.os.HandlerExecutor;
 import android.provider.DeviceConfig;
 import android.util.ArrayMap;
 
-import com.android.systemui.dagger.qualifiers.BgHandler;
+import com.android.systemui.dagger.qualifiers.Background;
 
 import java.util.Map;
+import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -49,10 +48,10 @@
     private final Map<String, Boolean> mCachedDeviceConfigFlags = new ArrayMap<>();
 
     @Inject
-    public FeatureFlags(@BgHandler Handler bgHandler) {
+    public FeatureFlags(@Background Executor executor) {
         DeviceConfig.addOnPropertiesChangedListener(
                 "systemui",
-                new HandlerExecutor(bgHandler),
+                executor,
                 this::onPropertiesChanged);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
index 9f5cf68..61043fb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -36,6 +36,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.assist.AssistHandleViewController;
 import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.statusbar.CommandQueue.Callbacks;
 import com.android.systemui.statusbar.phone.AutoHideController;
@@ -168,6 +169,9 @@
             View navigationWindow = navBar.getView().getRootView();
             WindowManagerGlobal.getInstance()
                     .removeView(navigationWindow, true /* immediate */);
+            // Also remove FragmentHostState here in case that onViewDetachedFromWindow has not yet
+            // invoked after display removal.
+            FragmentHostManager.removeAndDestroy(navigationWindow);
             mNavigationBars.remove(displayId);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index 4cc5b21..ff4ce94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -65,8 +65,18 @@
 
     boolean needsRedaction(NotificationEntry entry);
 
+    /**
+     * Has the given user chosen to allow their private (full) notifications to be shown even
+     * when the lockscreen is in "public" (secure & locked) mode?
+     */
     boolean userAllowsPrivateNotificationsInPublic(int currentUserId);
 
+    /**
+     * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
+     * "public" (secure & locked) mode?
+     */
+    boolean userAllowsNotificationsInPublic(int userId);
+
     /** Notified when the current user changes. */
     interface UserChangedListener {
         void onUserChanged(int userId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index f5710a8..0f3f6b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -435,7 +435,7 @@
      * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
      * "public" (secure & locked) mode?
      */
-    private boolean userAllowsNotificationsInPublic(int userHandle) {
+    public boolean userAllowsNotificationsInPublic(int userHandle) {
         if (isCurrentProfile(userHandle) && userHandle != mCurrentUserId) {
             return true;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index a98f826..246b0f0e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -61,7 +61,7 @@
 import com.android.systemui.statusbar.phone.LockscreenWallpaper;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.ScrimState;
-import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
@@ -104,9 +104,6 @@
 
     private final NotificationEntryManager mEntryManager;
 
-    // Late binding, also @Nullable due to being in com.android.systemui.statusbar.phone package
-    @Nullable
-    private Lazy<ShadeController> mShadeController;
     @Nullable
     private Lazy<StatusBarWindowController> mStatusBarWindowController;
 
@@ -122,6 +119,7 @@
     private final Context mContext;
     private final MediaSessionManager mMediaSessionManager;
     private final ArrayList<MediaListener> mMediaListeners;
+    private final Lazy<StatusBar> mStatusBarLazy;
     private final MediaArtworkProcessor mMediaArtworkProcessor;
     private final Set<AsyncTask<?, ?, ?>> mProcessArtworkTasks = new ArraySet<>();
 
@@ -181,7 +179,7 @@
     @Inject
     public NotificationMediaManager(
             Context context,
-            Lazy<ShadeController> shadeController,
+            Lazy<StatusBar> statusBarLazy,
             Lazy<StatusBarWindowController> statusBarWindowController,
             NotificationEntryManager notificationEntryManager,
             MediaArtworkProcessor mediaArtworkProcessor,
@@ -190,11 +188,12 @@
         mMediaArtworkProcessor = mediaArtworkProcessor;
         mKeyguardBypassController = keyguardBypassController;
         mMediaListeners = new ArrayList<>();
-        mMediaSessionManager
-                = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
         // TODO: use MediaSessionManager.SessionListener to hook us up to future updates
         // in session state
-        mShadeController = shadeController;
+        mMediaSessionManager = (MediaSessionManager) mContext.getSystemService(
+                Context.MEDIA_SESSION_SERVICE);
+        // TODO: use KeyguardStateController#isOccluded to remove this dependency
+        mStatusBarLazy = statusBarLazy;
         mStatusBarWindowController = statusBarWindowController;
         mEntryManager = notificationEntryManager;
         notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@@ -526,9 +525,8 @@
             }
         }
 
-        ShadeController shadeController = mShadeController.get();
         StatusBarWindowController windowController = mStatusBarWindowController.get();
-        boolean hideBecauseOccluded = shadeController != null && shadeController.isOccluded();
+        boolean hideBecauseOccluded = mStatusBarLazy.get().isOccluded();
 
         final boolean hasArtwork = artworkDrawable != null;
         mColorExtractor.setHasMediaArtwork(hasMediaArtwork);
@@ -599,8 +597,7 @@
                 if (DEBUG_MEDIA) {
                     Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork");
                 }
-                boolean cannotAnimateDoze = shadeController != null
-                        && shadeController.isDozing()
+                boolean cannotAnimateDoze = mStatusBarStateController.isDozing()
                         && !ScrimState.AOD.getAnimateChange();
                 boolean needsBypassFading = mKeyguardStateController.isBypassFadingAnimation();
                 if (((mBiometricUnlockController != null && mBiometricUnlockController.getMode()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index c556bc0..f6f3ac1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -58,7 +58,7 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry.EditedSuggestionInfo;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.RemoteInputUriController;
 import com.android.systemui.statusbar.policy.RemoteInputView;
 
@@ -116,7 +116,7 @@
     private final NotificationEntryManager mEntryManager;
     private final Handler mMainHandler;
 
-    private final Lazy<ShadeController> mShadeController;
+    private final Lazy<StatusBar> mStatusBarLazy;
 
     protected final Context mContext;
     private final UserManager mUserManager;
@@ -136,7 +136,7 @@
         @Override
         public boolean onClickHandler(
                 View view, PendingIntent pendingIntent, RemoteViews.RemoteResponse response) {
-            mShadeController.get().wakeUpIfDozing(SystemClock.uptimeMillis(), view,
+            mStatusBarLazy.get().wakeUpIfDozing(SystemClock.uptimeMillis(), view,
                     "NOTIFICATION_CLICK");
 
             if (handleRemoteInput(view, pendingIntent)) {
@@ -261,7 +261,7 @@
             NotificationLockscreenUserManager lockscreenUserManager,
             SmartReplyController smartReplyController,
             NotificationEntryManager notificationEntryManager,
-            Lazy<ShadeController> shadeController,
+            Lazy<StatusBar> statusBarLazy,
             StatusBarStateController statusBarStateController,
             @MainHandler Handler mainHandler,
             RemoteInputUriController remoteInputUriController) {
@@ -269,7 +269,7 @@
         mLockscreenUserManager = lockscreenUserManager;
         mSmartReplyController = smartReplyController;
         mEntryManager = notificationEntryManager;
-        mShadeController = shadeController;
+        mStatusBarLazy = statusBarLazy;
         mMainHandler = mainHandler;
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index e516af5..88f148b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -211,7 +211,7 @@
             setUserLocked(mStartingChild!!, false)
             mStartingChild = null
         }
-        if (shadeController.isDozing) {
+        if (statusBarStateController.isDozing) {
             isWakingToShadeLocked = true
             wakeUpCoordinator.willWakeUp = true
             mPowerManager!!.wakeUp(SystemClock.uptimeMillis(), WAKE_REASON_GESTURE,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
index 65f3fa9..31b7cb0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
@@ -24,18 +24,16 @@
 import android.util.Log;
 
 import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
-import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
-import dagger.Lazy;
-
 /** Handles heads-up and pulsing behavior driven by notification changes. */
 @Singleton
 public class NotificationAlertingManager {
@@ -44,7 +42,7 @@
 
     private final NotificationRemoteInputManager mRemoteInputManager;
     private final VisualStabilityManager mVisualStabilityManager;
-    private final Lazy<ShadeController> mShadeController;
+    private final StatusBarStateController mStatusBarStateController;
     private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
     private final NotificationListener mNotificationListener;
 
@@ -55,12 +53,12 @@
             NotificationEntryManager notificationEntryManager,
             NotificationRemoteInputManager remoteInputManager,
             VisualStabilityManager visualStabilityManager,
-            Lazy<ShadeController> shadeController,
+            StatusBarStateController statusBarStateController,
             NotificationInterruptionStateProvider notificationInterruptionStateProvider,
             NotificationListener notificationListener) {
         mRemoteInputManager = remoteInputManager;
         mVisualStabilityManager = visualStabilityManager;
-        mShadeController = shadeController;
+        mStatusBarStateController = statusBarStateController;
         mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
         mNotificationListener = notificationListener;
 
@@ -102,7 +100,7 @@
             // If it does and we no longer need to heads up, we should free the view.
             if (mNotificationInterruptionStateProvider.shouldHeadsUp(entry)) {
                 mHeadsUpManager.showNotification(entry);
-                if (!mShadeController.get().isDozing()) {
+                if (!mStatusBarStateController.isDozing()) {
                     // Mark as seen immediately
                     setNotificationShown(entry.getSbn());
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
index b5c6641..8ecf2b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
@@ -24,7 +24,7 @@
 import com.android.systemui.DejankUtils;
 import com.android.systemui.bubbles.BubbleController;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.StatusBar;
 
 /**
  * Click handler for generic clicks on notifications. Clicks on specific areas (expansion caret,
@@ -33,14 +33,14 @@
 public final class NotificationClicker implements View.OnClickListener {
     private static final String TAG = "NotificationClicker";
 
-    private final ShadeController mShadeController;
+    private final StatusBar mStatusBar;
     private final BubbleController mBubbleController;
     private final NotificationActivityStarter mNotificationActivityStarter;
 
-    public NotificationClicker(ShadeController shadeController,
+    public NotificationClicker(StatusBar statusBar,
             BubbleController bubbleController,
             NotificationActivityStarter notificationActivityStarter) {
-        mShadeController = shadeController;
+        mStatusBar = statusBar;
         mBubbleController = bubbleController;
         mNotificationActivityStarter = notificationActivityStarter;
     }
@@ -52,7 +52,7 @@
             return;
         }
 
-        mShadeController.wakeUpIfDozing(SystemClock.uptimeMillis(), v, "NOTIFICATION_CLICK");
+        mStatusBar.wakeUpIfDozing(SystemClock.uptimeMillis(), v, "NOTIFICATION_CLICK");
 
         final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
         final StatusBarNotification sbn = row.getEntry().getSbn();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
index e5f44bd..6c61923 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
@@ -27,6 +27,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dependency;
 import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -36,12 +37,16 @@
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
-/** Component which manages the various reasons a notification might be filtered out. */
+/** Component which manages the various reasons a notification might be filtered out.*/
+// TODO: delete NotificationFilter.java after migrating to new NotifPipeline b/145659174.
+//  Notification filtering is taken care of across the different Coordinators (mostly
+//  KeyguardCoordinator.java)
 @Singleton
 public class NotificationFilter {
 
     private final NotificationGroupManager mGroupManager = Dependency.get(
             NotificationGroupManager.class);
+    private final StatusBarStateController mStatusBarStateController;
 
     private NotificationEntryManager.KeyguardEnvironment mEnvironment;
     private ShadeController mShadeController;
@@ -49,7 +54,9 @@
     private NotificationLockscreenUserManager mUserManager;
 
     @Inject
-    public NotificationFilter() {}
+    public NotificationFilter(StatusBarStateController statusBarStateController) {
+        mStatusBarStateController = statusBarStateController;
+    }
 
     private NotificationEntryManager.KeyguardEnvironment getEnvironment() {
         if (mEnvironment == null) {
@@ -101,15 +108,15 @@
             return true;
         }
 
-        if (getShadeController().isDozing() && entry.shouldSuppressAmbient()) {
+        if (mStatusBarStateController.isDozing() && entry.shouldSuppressAmbient()) {
             return true;
         }
 
-        if (!getShadeController().isDozing() && entry.shouldSuppressNotificationList()) {
+        if (!mStatusBarStateController.isDozing() && entry.shouldSuppressNotificationList()) {
             return true;
         }
 
-        if (entry.isSuspended()) {
+        if (entry.getRanking().isSuspended()) {
             return true;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
index 3f7fd1a..7b1dc07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
@@ -64,6 +64,8 @@
         }
     };
 
+    // TODO: (b/145659174) remove after moving to NewNotifPipeline. Replaced by
+    //  DeviceProvisionedCoordinator
     private final DeviceProvisionedListener mDeviceProvisionedListener =
             new DeviceProvisionedListener() {
                 @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java
index f9f3266..9ae3882 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java
@@ -18,6 +18,8 @@
 
 import android.annotation.Nullable;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -34,7 +36,8 @@
     private final List<NotificationEntry> mUnmodifiableChildren =
             Collections.unmodifiableList(mChildren);
 
-    GroupEntry(String key) {
+    @VisibleForTesting
+    public GroupEntry(String key) {
         super(key);
     }
 
@@ -52,7 +55,8 @@
         return mUnmodifiableChildren;
     }
 
-    void setSummary(@Nullable NotificationEntry summary) {
+    @VisibleForTesting
+    public void setSummary(@Nullable NotificationEntry summary) {
         mSummary = summary;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
index dc68c4b..6ce7fd9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
@@ -18,6 +18,8 @@
 
 import android.annotation.Nullable;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 /**
  * Abstract superclass for top-level entries, i.e. things that can appear in the final notification
  * list shown to users. In practice, this means either GroupEntries or NotificationEntries.
@@ -49,7 +51,8 @@
         return mParent;
     }
 
-    void setParent(@Nullable GroupEntry parent) {
+    @VisibleForTesting
+    public void setParent(@Nullable GroupEntry parent) {
         mParent = parent;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 3eb55ef..232fb6d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -275,10 +275,6 @@
         return mRanking.getSuppressedVisualEffects();
     }
 
-    public boolean isSuspended() {
-        return mRanking.isSuspended();
-    }
-
     /** @see Ranking#canBubble() */
     public boolean canBubble() {
         return mRanking.canBubble();
@@ -951,6 +947,15 @@
     }
 
     /**
+     * Whether or not this row represents a system notification. Note that if this is
+     * {@code null}, that means we were either unable to retrieve the info or have yet to
+     * retrieve the info.
+     */
+    public Boolean isSystemNotification() {
+        return mIsSystemNotification;
+    }
+
+    /**
      * Set this notification to be sensitive.
      *
      * @param sensitive true if the content of this notification is sensitive right now
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 8bce528..48a4882 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
@@ -16,36 +16,28 @@
 
 package com.android.systemui.statusbar.notification.collection
 
-import android.app.Notification
 import android.app.NotificationManager.IMPORTANCE_DEFAULT
 import android.app.NotificationManager.IMPORTANCE_HIGH
 import android.app.NotificationManager.IMPORTANCE_LOW
 import android.app.NotificationManager.IMPORTANCE_MIN
-import android.app.Person
 import android.service.notification.NotificationListenerService.Ranking
 import android.service.notification.NotificationListenerService.RankingMap
 import android.service.notification.StatusBarNotification
 import com.android.internal.annotations.VisibleForTesting
-
 import com.android.systemui.statusbar.NotificationMediaManager
 import com.android.systemui.statusbar.notification.NotificationFilter
 import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
 import com.android.systemui.statusbar.notification.logging.NotifEvent
 import com.android.systemui.statusbar.notification.logging.NotifLog
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE
 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT
 import com.android.systemui.statusbar.phone.NotificationGroupManager
 import com.android.systemui.statusbar.policy.HeadsUpManager
-
-import java.util.Objects
-import java.util.ArrayList
-
-import javax.inject.Inject
-
-import kotlin.Comparator
-
 import dagger.Lazy
+import java.util.Objects
+import javax.inject.Inject
 
 private const val TAG = "NotifRankingManager"
 
@@ -64,7 +56,8 @@
     private val headsUpManager: HeadsUpManager,
     private val notifFilter: NotificationFilter,
     private val notifLog: NotifLog,
-    sectionsFeatureManager: NotificationSectionsFeatureManager
+    sectionsFeatureManager: NotificationSectionsFeatureManager,
+    private val peopleNotificationIdentifier: PeopleNotificationIdentifier
 ) {
 
     var rankingMap: RankingMap? = null
@@ -79,6 +72,9 @@
         val aRank = a.ranking.rank
         val bRank = b.ranking.rank
 
+        val aIsPeople = a.isPeopleNotification()
+        val bIsPeople = b.isPeopleNotification()
+
         val aMedia = isImportantMedia(a)
         val bMedia = isImportantMedia(b)
 
@@ -88,25 +84,19 @@
         val aHeadsUp = a.isRowHeadsUp
         val bHeadsUp = b.isRowHeadsUp
 
-        if (usePeopleFiltering && a.isPeopleNotification() != b.isPeopleNotification()) {
-            if (a.isPeopleNotification()) -1 else 1
-        } else if (aHeadsUp != bHeadsUp) {
-            if (aHeadsUp) -1 else 1
-        } else if (aHeadsUp) {
+        when {
+            usePeopleFiltering && aIsPeople != bIsPeople -> if (aIsPeople) -1 else 1
+            aHeadsUp != bHeadsUp -> if (aHeadsUp) -1 else 1
             // Provide consistent ranking with headsUpManager
-            headsUpManager.compare(a, b)
-        } else if (aMedia != bMedia) {
+            aHeadsUp -> headsUpManager.compare(a, b)
             // Upsort current media notification.
-            if (aMedia) -1 else 1
-        } else if (aSystemMax != bSystemMax) {
+            aMedia != bMedia -> if (aMedia) -1 else 1
             // Upsort PRIORITY_MAX system notifications
-            if (aSystemMax) -1 else 1
-        } else if (a.isHighPriority != b.isHighPriority) {
-            -1 * java.lang.Boolean.compare(a.isHighPriority, b.isHighPriority)
-        } else if (aRank != bRank) {
-            aRank - bRank
-        } else {
-            nb.notification.`when`.compareTo(na.notification.`when`)
+            aSystemMax != bSystemMax -> if (aSystemMax) -1 else 1
+            a.isHighPriority != b.isHighPriority ->
+                -1 * a.isHighPriority.compareTo(b.isHighPriority)
+            aRank != bRank -> aRank - bRank
+            else -> nb.notification.`when`.compareTo(na.notification.`when`)
         }
     }
 
@@ -138,10 +128,9 @@
         val c = entry.channel
         val n = entry.sbn.notification
 
-        if (((n.isForegroundService && entry.ranking.importance >= IMPORTANCE_LOW) ||
-            n.hasMediaSession() ||
-            n.hasPerson() ||
-            n.hasStyle(Notification.MessagingStyle::class.java))) {
+        if ((n.isForegroundService && entry.ranking.importance >= IMPORTANCE_LOW) ||
+                n.hasMediaSession() ||
+                entry.isPeopleNotification()) {
             // Users who have long pressed and demoted to silent should not see the notification
             // in the top section
             if (c != null && c.hasUserSetImportance()) {
@@ -204,7 +193,7 @@
         isMedia: Boolean,
         isSystemMax: Boolean
     ) {
-        if (usePeopleFiltering && entry.hasAssociatedPeople()) {
+        if (usePeopleFiltering && entry.isPeopleNotification()) {
             entry.bucket = BUCKET_PEOPLE
         } else if (isHeadsUp || isMedia || isSystemMax || entry.isHighPriority) {
             entry.bucket = BUCKET_ALERTING
@@ -235,6 +224,11 @@
             }
         }
     }
+
+    private fun NotificationEntry.isPeopleNotification() =
+            sbn.isPeopleNotification()
+    private fun StatusBarNotification.isPeopleNotification() =
+            peopleNotificationIdentifier.isPeopleNotification(this)
 }
 
 // Convenience functions
@@ -245,16 +239,3 @@
 private fun StatusBarNotification.isSystemNotification(): Boolean {
     return "android" == packageName || "com.android.systemui" == packageName
 }
-
-private fun Notification.hasPerson(): Boolean {
-    val people: ArrayList<Person> =
-            (extras?.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST)) ?: ArrayList()
-    return people.isNotEmpty()
-}
-
-private fun Notification.hasStyle(targetStyleClass: Class<*>): Boolean {
-    return targetStyleClass == notificationStyle
-}
-
-private fun NotificationEntry.isPeopleNotification(): Boolean =
-        sbn.notification.hasStyle(Notification.MessagingStyle::class.java)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/Coordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/Coordinator.java
new file mode 100644
index 0000000..898918e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/Coordinator.java
@@ -0,0 +1,42 @@
+/*
+ * 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.systemui.statusbar.notification.collection.coordinator;
+
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.NotifLifetimeExtender;
+import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
+
+/**
+ * Interface for registering callbacks to the {@link NewNotifPipeline}.
+ *
+ * This includes registering:
+ *  {@link Pluggable}s to the {@link NotifListBuilder}
+ *  {@link NotifCollectionListener}s and {@link NotifLifetimeExtender}s to {@link NotifCollection}
+ */
+public interface Coordinator {
+
+    /**
+     * Called after the NewNotifPipeline is initialized.
+     * Coordinators should register their {@link Pluggable}s to the notifListBuilder
+     * and their {@link NotifCollectionListener}s and {@link NotifLifetimeExtender}s
+     * to the notifCollection in this method.
+     */
+    void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
new file mode 100644
index 0000000..511aafc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DeviceProvisionedCoordinator.java
@@ -0,0 +1,96 @@
+/*
+ * 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.systemui.statusbar.notification.collection.coordinator;
+
+import android.Manifest;
+import android.app.AppGlobals;
+import android.app.Notification;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.os.RemoteException;
+import android.service.notification.StatusBarNotification;
+
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Filters out most notifications when the device is unprovisioned.
+ * Special notifications with extra permissions and tags won't be filtered out even when the
+ * device is unprovisioned.
+ */
+@Singleton
+public class DeviceProvisionedCoordinator implements Coordinator {
+    private static final String TAG = "DeviceProvisionedCoordinator";
+
+    private final DeviceProvisionedController mDeviceProvisionedController;
+
+    @Inject
+    public DeviceProvisionedCoordinator(DeviceProvisionedController deviceProvisionedController) {
+        mDeviceProvisionedController = deviceProvisionedController;
+    }
+
+    @Override
+    public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) {
+        mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
+
+        notifListBuilder.addFilter(mNotifFilter);
+    }
+
+    protected final NotifFilter mNotifFilter = new NotifFilter(TAG) {
+        @Override
+        public boolean shouldFilterOut(NotificationEntry entry, long now) {
+            return !mDeviceProvisionedController.isDeviceProvisioned()
+                    && !showNotificationEvenIfUnprovisioned(entry.getSbn());
+        }
+    };
+
+    /**
+     * Only notifications coming from packages with permission
+     * android.permission.NOTIFICATION_DURING_SETUP that also have special tags
+     * marking them as relevant for setup are allowed to show when device is unprovisioned
+     */
+    private boolean showNotificationEvenIfUnprovisioned(StatusBarNotification sbn) {
+        final boolean hasPermission = checkUidPermission(AppGlobals.getPackageManager(),
+                Manifest.permission.NOTIFICATION_DURING_SETUP,
+                sbn.getUid()) == PackageManager.PERMISSION_GRANTED;
+        return hasPermission
+                && sbn.getNotification().extras.getBoolean(Notification.EXTRA_ALLOW_DURING_SETUP);
+    }
+
+    private static int checkUidPermission(IPackageManager packageManager, String permission,
+            int uid) {
+        try {
+            return packageManager.checkUidPermission(permission, uid);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    private final DeviceProvisionedController.DeviceProvisionedListener mDeviceProvisionedListener =
+            new DeviceProvisionedController.DeviceProvisionedListener() {
+                @Override
+                public void onDeviceProvisionedChanged() {
+                    mNotifFilter.invalidateList();
+                }
+            };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java
new file mode 100644
index 0000000..4803cf4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinator.java
@@ -0,0 +1,243 @@
+/*
+ * 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.systemui.statusbar.notification.collection.coordinator;
+
+import android.app.Notification;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.util.ArraySet;
+
+import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.appops.AppOpsController;
+import com.android.systemui.dagger.qualifiers.BgHandler;
+import com.android.systemui.dagger.qualifiers.MainHandler;
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.NotifLifetimeExtender;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Handles ForegroundService interactions with notifications.
+ *  Tags notifications with appOps.
+ *  Lifetime extends notifications associated with an ongoing ForegroundService.
+ *  Filters out notifications that represent foreground services that are no longer running
+ *
+ * Previously this logic lived in
+ *  frameworks/base/packages/SystemUI/src/com/android/systemui/ForegroundServiceController
+ *  frameworks/base/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener
+ *  frameworks/base/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender
+ */
+@Singleton
+public class ForegroundCoordinator implements Coordinator {
+    private static final String TAG = "ForegroundNotificationCoordinator";
+
+    private final ForegroundServiceController mForegroundServiceController;
+    private final AppOpsController mAppOpsController;
+    private final Handler mMainHandler;
+    private final Handler mBgHandler;
+
+    private NotifCollection mNotifCollection;
+
+    @Inject
+    public ForegroundCoordinator(
+            ForegroundServiceController foregroundServiceController,
+            AppOpsController appOpsController,
+            @MainHandler Handler mainHandler,
+            @BgHandler Handler bgHandler) {
+        mForegroundServiceController = foregroundServiceController;
+        mAppOpsController = appOpsController;
+        mMainHandler = mainHandler;
+        mBgHandler = bgHandler;
+    }
+
+    @Override
+    public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) {
+        mNotifCollection = notifCollection;
+
+        // extend the lifetime of foreground notification services to show for at least 5 seconds
+        mNotifCollection.addNotificationLifetimeExtender(mForegroundLifetimeExtender);
+
+        // listen for new notifications to add appOps
+        mNotifCollection.addCollectionListener(mNotifCollectionListener);
+
+        // when appOps change, update any relevant notifications to update appOps for
+        mAppOpsController.addCallback(ForegroundServiceController.APP_OPS, this::onAppOpsChanged);
+
+        // filter out foreground service notifications that aren't necessary anymore
+        notifListBuilder.addFilter(mNotifFilter);
+    }
+
+    /**
+     * Filters out notifications that represent foreground services that are no longer running.
+     */
+    protected final NotifFilter mNotifFilter = new NotifFilter(TAG) {
+        @Override
+        public boolean shouldFilterOut(NotificationEntry entry, long now) {
+            StatusBarNotification sbn = entry.getSbn();
+            if (mForegroundServiceController.isDisclosureNotification(sbn)
+                    && !mForegroundServiceController.isDisclosureNeededForUser(sbn.getUserId())) {
+                return true;
+            }
+
+            if (mForegroundServiceController.isSystemAlertNotification(sbn)) {
+                final String[] apps = sbn.getNotification().extras.getStringArray(
+                        Notification.EXTRA_FOREGROUND_APPS);
+                if (apps != null && apps.length >= 1) {
+                    if (!mForegroundServiceController.isSystemAlertWarningNeeded(
+                            sbn.getUserId(), apps[0])) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+    };
+
+    /**
+     * Extends the lifetime of foreground notification services such that they show for at least
+     * five seconds
+     */
+    private final NotifLifetimeExtender mForegroundLifetimeExtender = new NotifLifetimeExtender() {
+        private static final int MIN_FGS_TIME_MS = 5000;
+        private OnEndLifetimeExtensionCallback mEndCallback;
+        private Map<String, Runnable> mEndRunnables = new HashMap<>();
+
+        @Override
+        public String getName() {
+            return TAG;
+        }
+
+        @Override
+        public void setCallback(OnEndLifetimeExtensionCallback callback) {
+            mEndCallback = callback;
+        }
+
+        @Override
+        public boolean shouldExtendLifetime(NotificationEntry entry, int reason) {
+            if ((entry.getSbn().getNotification().flags
+                    & Notification.FLAG_FOREGROUND_SERVICE) == 0) {
+                return false;
+            }
+
+            final long currTime = System.currentTimeMillis();
+            final boolean extendLife = currTime - entry.getSbn().getPostTime() < MIN_FGS_TIME_MS;
+
+            if (extendLife) {
+                if (!mEndRunnables.containsKey(entry.getKey())) {
+                    final Runnable runnable = new Runnable() {
+                        @Override
+                        public void run() {
+                            mEndCallback.onEndLifetimeExtension(mForegroundLifetimeExtender, entry);
+                        }
+                    };
+                    mEndRunnables.put(entry.getKey(), runnable);
+                    mBgHandler.postDelayed(runnable, MIN_FGS_TIME_MS
+                            - (currTime - entry.getSbn().getPostTime()));
+                }
+            }
+
+            return extendLife;
+        }
+
+        @Override
+        public void cancelLifetimeExtension(NotificationEntry entry) {
+            if (mEndRunnables.containsKey(entry.getKey())) {
+                Runnable endRunnable = mEndRunnables.remove(entry.getKey());
+                mBgHandler.removeCallbacks(endRunnable);
+            }
+        }
+    };
+
+    /**
+     * Adds appOps to incoming and updating notifications
+     */
+    private NotifCollectionListener mNotifCollectionListener = new NotifCollectionListener() {
+        @Override
+        public void onEntryAdded(NotificationEntry entry) {
+            tagForeground(entry);
+        }
+
+        @Override
+        public void onEntryUpdated(NotificationEntry entry) {
+            tagForeground(entry);
+        }
+
+        private void tagForeground(NotificationEntry entry) {
+            final StatusBarNotification sbn = entry.getSbn();
+            // note: requires that the ForegroundServiceController is updating their appOps first
+            ArraySet<Integer> activeOps = mForegroundServiceController.getAppOps(sbn.getUserId(),
+                    sbn.getPackageName());
+            if (activeOps != null) {
+                synchronized (entry.mActiveAppOps) {
+                    entry.mActiveAppOps.clear();
+                    entry.mActiveAppOps.addAll(activeOps);
+                }
+            }
+        }
+    };
+
+    /**
+     * Update the appOp for the posted notification associated with the current foreground service
+     * @param code code for appOp to add/remove
+     * @param uid of user the notification is sent to
+     * @param packageName package that created the notification
+     * @param active whether the appOpCode is active or not
+     */
+    private void onAppOpsChanged(int code, int uid, String packageName, boolean active) {
+        int userId = UserHandle.getUserId(uid);
+
+        // Update appOp if there's an associated posted notification:
+        final String foregroundKey = mForegroundServiceController.getStandardLayoutKey(userId,
+                packageName);
+        if (foregroundKey != null) {
+            final NotificationEntry entry = findNotificationEntryWithKey(foregroundKey);
+            if (entry != null
+                    && uid == entry.getSbn().getUid()
+                    && packageName.equals(entry.getSbn().getPackageName())) {
+                boolean changed;
+                synchronized (entry.mActiveAppOps) {
+                    if (active) {
+                        changed = entry.mActiveAppOps.add(code);
+                    } else {
+                        changed = entry.mActiveAppOps.remove(code);
+                    }
+                }
+                if (changed) {
+                    mMainHandler.post(mNotifFilter::invalidateList);
+                }
+            }
+        }
+    }
+
+    private NotificationEntry findNotificationEntryWithKey(String key) {
+        for (NotificationEntry entry : mNotifCollection.getNotifs()) {
+            if (entry.getKey().equals(key)) {
+                return entry;
+            }
+        }
+        return null;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
new file mode 100644
index 0000000..6daf3fc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -0,0 +1,244 @@
+/*
+ * 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.systemui.statusbar.notification.collection.coordinator;
+
+import static android.app.Notification.VISIBILITY_SECRET;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.service.notification.StatusBarNotification;
+
+import androidx.annotation.MainThread;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Filters low priority and privacy-sensitive notifications from the lockscreen.
+ */
+@Singleton
+public class KeyguardCoordinator implements Coordinator {
+    private static final String TAG = "KeyguardNotificationCoordinator";
+
+    private final Context mContext;
+    private final Handler mMainHandler;
+    private final KeyguardStateController mKeyguardStateController;
+    private final NotificationLockscreenUserManager mLockscreenUserManager;
+    private final BroadcastDispatcher mBroadcastDispatcher;
+    private final StatusBarStateController mStatusBarStateController;
+    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+
+    @Inject
+    public KeyguardCoordinator(
+            Context context,
+            @MainThread Handler mainThreadHandler,
+            KeyguardStateController keyguardStateController,
+            NotificationLockscreenUserManager lockscreenUserManager,
+            BroadcastDispatcher broadcastDispatcher,
+            StatusBarStateController statusBarStateController,
+            KeyguardUpdateMonitor keyguardUpdateMonitor) {
+        mContext = context;
+        mMainHandler = mainThreadHandler;
+        mKeyguardStateController = keyguardStateController;
+        mLockscreenUserManager = lockscreenUserManager;
+
+        mBroadcastDispatcher = broadcastDispatcher;
+        mStatusBarStateController = statusBarStateController;
+        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+    }
+
+    @Override
+    public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) {
+        setupInvalidateNotifListCallbacks();
+        notifListBuilder.addFilter(mNotifFilter);
+    }
+
+    protected final NotifFilter mNotifFilter = new NotifFilter(TAG) {
+        @Override
+        public boolean shouldFilterOut(NotificationEntry entry, long now) {
+            final StatusBarNotification sbn = entry.getSbn();
+
+            // FILTER OUT the notification when the notification isn't for the current profile
+            if (!mLockscreenUserManager.isCurrentProfile(sbn.getUserId())) {
+                return true;
+            }
+
+            // FILTER OUT the notification when the keyguard is showing and...
+            if (mKeyguardStateController.isShowing()) {
+                // ... user settings or the device policy manager doesn't allow lockscreen
+                // notifications;
+                if (!mLockscreenUserManager.shouldShowLockscreenNotifications()) {
+                    return true;
+                }
+
+                final int currUserId = mLockscreenUserManager.getCurrentUserId();
+                final int notifUserId = (sbn.getUser().getIdentifier() == UserHandle.USER_ALL)
+                        ? currUserId : sbn.getUser().getIdentifier();
+
+                // ... user is in lockdown
+                if (mKeyguardUpdateMonitor.isUserInLockdown(currUserId)
+                        || mKeyguardUpdateMonitor.isUserInLockdown(notifUserId)) {
+                    return true;
+                }
+
+                // ... device is in public mode and the user's settings doesn't allow
+                // notifications to show in public mode
+                if (mLockscreenUserManager.isLockscreenPublicMode(currUserId)
+                        || mLockscreenUserManager.isLockscreenPublicMode(notifUserId)) {
+                    if (entry.getRanking().getVisibilityOverride() == VISIBILITY_SECRET) {
+                        return true;
+                    }
+
+                    if (!mLockscreenUserManager.userAllowsNotificationsInPublic(currUserId)
+                            || !mLockscreenUserManager.userAllowsNotificationsInPublic(
+                            notifUserId)) {
+                        return true;
+                    }
+                }
+
+                // ... neither this notification nor its summary have high enough priority
+                // to be shown on the lockscreen
+                // TODO: grouping hasn't happened yet (b/145134683)
+                if (entry.getParent() != null) {
+                    final NotificationEntry summary = entry.getParent().getRepresentativeEntry();
+                    if (priorityExceedsLockscreenShowingThreshold(summary)) {
+                        return false;
+                    }
+                }
+                return !priorityExceedsLockscreenShowingThreshold(entry);
+            }
+            return false;
+        }
+    };
+
+    private boolean priorityExceedsLockscreenShowingThreshold(NotificationEntry entry) {
+        if (entry == null) {
+            return false;
+        }
+        if (NotificationUtils.useNewInterruptionModel(mContext)
+                && hideSilentNotificationsOnLockscreen()) {
+            // TODO: make sure in the NewNotifPipeline that entry.isHighPriority() has been
+            //  correctly updated before reaching this point (b/145134683)
+            return entry.isHighPriority();
+        } else {
+            return !entry.getRanking().isAmbient();
+        }
+    }
+
+    private boolean hideSilentNotificationsOnLockscreen() {
+        return Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1) == 0;
+    }
+
+    private void setupInvalidateNotifListCallbacks() {
+        // register onKeyguardShowing callback
+        mKeyguardStateController.addCallback(mKeyguardCallback);
+        mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
+
+        // register lockscreen settings changed callbacks:
+        final ContentObserver settingsObserver = new ContentObserver(mMainHandler) {
+            @Override
+            public void onChange(boolean selfChange, Uri uri) {
+                if (mKeyguardStateController.isShowing()) {
+                    invalidateListFromFilter("Settings " + uri + " changed");
+                }
+            }
+        };
+
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS),
+                false,
+                settingsObserver,
+                UserHandle.USER_ALL);
+
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
+                true,
+                settingsObserver,
+                UserHandle.USER_ALL);
+
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.ZEN_MODE),
+                false,
+                settingsObserver);
+
+        // register (maybe) public mode changed callbacks:
+        mStatusBarStateController.addCallback(mStatusBarStateListener);
+        mBroadcastDispatcher.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (mKeyguardStateController.isShowing()) {
+                    // maybe public mode changed
+                    invalidateListFromFilter(intent.getAction());
+                }
+            }}, new IntentFilter(Intent.ACTION_USER_SWITCHED));
+    }
+
+    private void invalidateListFromFilter(String reason) {
+        mNotifFilter.invalidateList();
+    }
+
+    private final KeyguardStateController.Callback mKeyguardCallback =
+            new KeyguardStateController.Callback() {
+        @Override
+        public void onUnlockedChanged() {
+            invalidateListFromFilter("onUnlockedChanged");
+        }
+
+        @Override
+        public void onKeyguardShowingChanged() {
+            invalidateListFromFilter("onKeyguardShowingChanged");
+        }
+    };
+
+    private final StatusBarStateController.StateListener mStatusBarStateListener =
+            new StatusBarStateController.StateListener() {
+                @Override
+                public void onStateChanged(int newState) {
+                    // maybe public mode changed
+                    invalidateListFromFilter("onStatusBarStateChanged");
+                }
+    };
+
+    private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
+            new KeyguardUpdateMonitorCallback() {
+        @Override
+        public void onStrongAuthStateChanged(int userId) {
+            // maybe lockdown mode changed
+            invalidateListFromFilter("onStrongAuthStateChanged");
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
new file mode 100644
index 0000000..13247193
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
@@ -0,0 +1,78 @@
+/*
+ * 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.systemui.statusbar.notification.collection.coordinator;
+
+import com.android.systemui.Dumpable;
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.NotifLifetimeExtender;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Handles the attachment of the {@link NotifListBuilder} and {@link NotifCollection} to the
+ * {@link Coordinator}s, so that the Coordinators can register their respective callbacks.
+ */
+@Singleton
+public class NotifCoordinators implements Dumpable {
+    private static final String TAG = "NotifCoordinators";
+    private final List<Coordinator> mCoordinators = new ArrayList<>();
+
+    /**
+     * Creates all the coordinators.
+     */
+    @Inject
+    public NotifCoordinators(
+            KeyguardCoordinator keyguardCoordinator,
+            RankingCoordinator rankingCoordinator,
+            ForegroundCoordinator foregroundCoordinator,
+            DeviceProvisionedCoordinator deviceProvisionedCoordinator) {
+        mCoordinators.add(keyguardCoordinator);
+        mCoordinators.add(rankingCoordinator);
+        mCoordinators.add(foregroundCoordinator);
+        mCoordinators.add(deviceProvisionedCoordinator);
+        // TODO: add new Coordinators here! (b/145134683, b/112656837)
+    }
+
+    /**
+     * Sends the initialized notifListBuilder and notifCollection to each
+     * coordinator to indicate the notifListBuilder is ready to accept {@link Pluggable}s
+     * and the notifCollection is ready to accept {@link NotifCollectionListener}s and
+     * {@link NotifLifetimeExtender}s.
+     */
+    public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) {
+        for (Coordinator c : mCoordinators) {
+            c.attach(notifCollection, notifListBuilder);
+        }
+    }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println(TAG + ":");
+        for (Coordinator c : mCoordinators) {
+            pw.println("\t" + c.getClass());
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
new file mode 100644
index 0000000..c390f96
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
@@ -0,0 +1,83 @@
+/*
+ * 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.systemui.statusbar.notification.collection.coordinator;
+
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Filters out NotificationEntries based on its Ranking.
+ */
+@Singleton
+public class RankingCoordinator implements Coordinator {
+    private static final String TAG = "RankingNotificationCoordinator";
+
+    private final StatusBarStateController mStatusBarStateController;
+
+    @Inject
+    public RankingCoordinator(StatusBarStateController statusBarStateController) {
+        mStatusBarStateController = statusBarStateController;
+    }
+
+    @Override
+    public void attach(NotifCollection notifCollection, NotifListBuilder notifListBuilder) {
+        mStatusBarStateController.addCallback(mStatusBarStateCallback);
+
+        notifListBuilder.addFilter(mNotifFilter);
+    }
+
+    /**
+     * Checks whether to filter out the given notification based the notification's Ranking object.
+     * NotifListBuilder invalidates the notification list each time the ranking is updated,
+     * so we don't need to explicitly invalidate this filter on ranking update.
+     */
+    protected final NotifFilter mNotifFilter = new NotifFilter(TAG) {
+        @Override
+        public boolean shouldFilterOut(NotificationEntry entry, long now) {
+            // App suspended from Ranking
+            if (entry.getRanking().isSuspended()) {
+                return true;
+            }
+
+            // Dozing + DND Settings from Ranking object
+            if (mStatusBarStateController.isDozing() && entry.shouldSuppressAmbient()) {
+                return true;
+            }
+
+            if (!mStatusBarStateController.isDozing() && entry.shouldSuppressNotificationList()) {
+                return true;
+            }
+
+            return false;
+        }
+    };
+
+
+    private final StatusBarStateController.StateListener mStatusBarStateCallback =
+            new StatusBarStateController.StateListener() {
+                @Override
+                public void onDozingChanged(boolean isDozing) {
+                    mNotifFilter.invalidateList();
+                }
+            };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java
index 3b3e7e2..5fc55da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java
@@ -23,6 +23,7 @@
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
+import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinators;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -37,6 +38,7 @@
 public class NewNotifPipeline implements Dumpable {
     private final NotifCollection mNotifCollection;
     private final NotifListBuilderImpl mNotifPipeline;
+    private final NotifCoordinators mNotifPluggableCoordinators;
     private final DumpController mDumpController;
 
     private final FakePipelineConsumer mFakePipelineConsumer = new FakePipelineConsumer();
@@ -45,9 +47,11 @@
     public NewNotifPipeline(
             NotifCollection notifCollection,
             NotifListBuilderImpl notifPipeline,
+            NotifCoordinators notifCoordinators,
             DumpController dumpController) {
         mNotifCollection = notifCollection;
         mNotifPipeline = notifPipeline;
+        mNotifPluggableCoordinators = notifCoordinators;
         mDumpController = dumpController;
     }
 
@@ -57,6 +61,7 @@
         mFakePipelineConsumer.attach(mNotifPipeline);
         mNotifPipeline.attach(mNotifCollection);
         mNotifCollection.attach(notificationService);
+        mNotifPluggableCoordinators.attach(mNotifCollection, mNotifPipeline);
 
         Log.d(TAG, "Notif pipeline initialized");
 
@@ -66,6 +71,7 @@
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         mFakePipelineConsumer.dump(fd, pw, args);
+        mNotifPluggableCoordinators.dump(fd, pw, args);
     }
 
     private static final String TAG = "NewNotifPipeline";
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 5a5f9e9..9dd7f48 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
@@ -174,7 +174,7 @@
             if (ops.contains(OP_CAMERA) || ops.contains(OP_RECORD_AUDIO)) {
                 startAppDetailsSettingsActivity(pkg, uid, null, row);
             } else {
-                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
+                Intent intent = new Intent(Settings.ACTION_MANAGE_APP_OVERLAY_PERMISSION);
                 intent.setData(Uri.fromParts("package", pkg, null));
                 mNotificationActivityStarter.startNotificationGutsIntent(intent, uid, row);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
index 2a4b315..352ba0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
@@ -179,21 +179,22 @@
         if (Utils.useQsMediaPlayer(mContext)) {
             final int[] compactActions = mRow.getEntry().getSbn().getNotification().extras
                     .getIntArray(Notification.EXTRA_COMPACT_ACTIONS);
+            int tintColor = getNotificationHeader().getOriginalIconColor();
             StatusBarWindowController ctrl = Dependency.get(StatusBarWindowController.class);
             QuickQSPanel panel = ctrl.getStatusBarView().findViewById(
                     com.android.systemui.R.id.quick_qs_panel);
             panel.getMediaPlayer().setMediaSession(token,
                     mRow.getEntry().getSbn().getNotification().getSmallIcon(),
-                    getNotificationHeader().getOriginalIconColor(),
-                    mRow.getCurrentBackgroundTint(),
+                    tintColor,
+                    mBackgroundColor,
                     mActions,
                     compactActions);
             QSPanel bigPanel = ctrl.getStatusBarView().findViewById(
                     com.android.systemui.R.id.quick_settings_panel);
             bigPanel.addMediaSession(token,
                     mRow.getEntry().getSbn().getNotification().getSmallIcon(),
-                    getNotificationHeader().getOriginalIconColor(),
-                    mRow.getCurrentBackgroundTint(),
+                    tintColor,
+                    mBackgroundColor,
                     mActions,
                     mRow.getEntry().getSbn());
         }
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 fdd51e9e..8e9a051e 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
@@ -318,7 +318,7 @@
                 }
                 mParent.addView(mPeopleHubView, targetIndex);
                 return true;
-            } else if (currentHubIndex != targetIndex - 1) {
+            } else if (currentHubIndex != targetIndex) {
                 if (currentHubIndex < targetIndex) {
                     targetIndex--;
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index 063ad85..09ebb64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -88,10 +88,9 @@
     private final PulseExpansionHandler mPulseExpansionHandler;
     private final StatusBarWindowController mStatusBarWindowController;
     private final NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
-    private final StatusBarWindowViewController mStatusBarWindowViewController;
+    private StatusBarWindowViewController mStatusBarWindowViewController;
     private final LockscreenLockIconController mLockscreenLockIconController;
     private NotificationIconAreaController mNotificationIconAreaController;
-    private StatusBarWindowView mStatusBarWindow;
     private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     private NotificationPanelView mNotificationPanel;
     private View mAmbientIndicationContainer;
@@ -112,7 +111,6 @@
             PulseExpansionHandler pulseExpansionHandler,
             StatusBarWindowController statusBarWindowController,
             NotificationWakeUpCoordinator notificationWakeUpCoordinator,
-            StatusBarWindowViewController statusBarWindowViewController,
             LockscreenLockIconController lockscreenLockIconController) {
         super();
         mDozeLog = dozeLog;
@@ -132,7 +130,6 @@
         mPulseExpansionHandler = pulseExpansionHandler;
         mStatusBarWindowController = statusBarWindowController;
         mNotificationWakeUpCoordinator = notificationWakeUpCoordinator;
-        mStatusBarWindowViewController = statusBarWindowViewController;
         mLockscreenLockIconController = lockscreenLockIconController;
     }
 
@@ -143,14 +140,14 @@
      */
     public void initialize(StatusBar statusBar,
             NotificationIconAreaController notificationIconAreaController,
-            StatusBarWindowView statusBarWindow,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+            StatusBarWindowViewController statusBarWindowViewController,
             NotificationPanelView notificationPanel, View ambientIndicationContainer) {
         mStatusBar = statusBar;
         mNotificationIconAreaController = notificationIconAreaController;
-        mStatusBarWindow = statusBarWindow;
         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
         mNotificationPanel = notificationPanel;
+        mStatusBarWindowViewController = statusBarWindowViewController;
         mAmbientIndicationContainer = ambientIndicationContainer;
         mBiometricUnlockController = mBiometricUnlockControllerLazy.get();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index 4d6b54c..f3e9b6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -134,6 +134,7 @@
         if (fd != null) {
             try {
                 BitmapFactory.Options options = new BitmapFactory.Options();
+                options.inPreferredConfig = Bitmap.Config.HARDWARE;
                 return LoaderResult.success(BitmapFactory.decodeFileDescriptor(
                         fd.getFileDescriptor(), null, options));
             } catch (OutOfMemoryError e) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 35407c6..ed2fb0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -2989,7 +2989,7 @@
                 return true;
             case StatusBarState.SHADE_LOCKED:
                 if (!mQsExpanded) {
-                    mShadeController.goToKeyguard();
+                    mStatusBarStateController.setState(StatusBarState.KEYGUARD);
                 }
                 return true;
             case StatusBarState.SHADE:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index bfecaaa..8d43c66 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -43,10 +43,6 @@
 import com.android.systemui.R;
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.privacy.PrivacyItem;
-import com.android.systemui.privacy.PrivacyItemController;
-import com.android.systemui.privacy.PrivacyItemControllerKt;
-import com.android.systemui.privacy.PrivacyType;
 import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.qs.tiles.RotationLockTile;
 import com.android.systemui.statusbar.CommandQueue;
@@ -67,9 +63,6 @@
 import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.statusbar.policy.ZenModeController;
 
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.List;
 import java.util.Locale;
 
 /**
@@ -84,12 +77,12 @@
                 ZenModeController.Callback,
                 DeviceProvisionedListener,
                 KeyguardStateController.Callback,
-                PrivacyItemController.Callback,
                 LocationController.LocationChangeCallback {
     private static final String TAG = "PhoneStatusBarPolicy";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    public static final int LOCATION_STATUS_ICON_ID = PrivacyType.TYPE_LOCATION.getIconId();
+    public static final int LOCATION_STATUS_ICON_ID =
+            com.android.internal.R.drawable.perm_group_location;
 
     private final String mSlotCast;
     private final String mSlotHotspot;
@@ -122,7 +115,6 @@
     private final DeviceProvisionedController mProvisionedController;
     private final KeyguardStateController mKeyguardStateController;
     private final LocationController mLocationController;
-    private final PrivacyItemController mPrivacyItemController;
     private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
     private final SensorPrivacyController mSensorPrivacyController;
 
@@ -156,7 +148,6 @@
         mProvisionedController = Dependency.get(DeviceProvisionedController.class);
         mKeyguardStateController = Dependency.get(KeyguardStateController.class);
         mLocationController = Dependency.get(LocationController.class);
-        mPrivacyItemController = Dependency.get(PrivacyItemController.class);
         mSensorPrivacyController = Dependency.get(SensorPrivacyController.class);
 
         mSlotCast = context.getString(com.android.internal.R.string.status_bar_cast);
@@ -233,13 +224,6 @@
                 context.getString(R.string.accessibility_data_saver_on));
         mIconController.setIconVisibility(mSlotDataSaver, false);
 
-        // privacy items
-        mIconController.setIcon(mSlotMicrophone, PrivacyType.TYPE_MICROPHONE.getIconId(),
-                PrivacyType.TYPE_MICROPHONE.getName(mContext));
-        mIconController.setIconVisibility(mSlotMicrophone, false);
-        mIconController.setIcon(mSlotCamera, PrivacyType.TYPE_CAMERA.getIconId(),
-                PrivacyType.TYPE_CAMERA.getName(mContext));
-        mIconController.setIconVisibility(mSlotCamera, false);
         mIconController.setIcon(mSlotLocation, LOCATION_STATUS_ICON_ID,
                 mContext.getString(R.string.accessibility_location_active));
         mIconController.setIconVisibility(mSlotLocation, false);
@@ -259,7 +243,6 @@
         mNextAlarmController.addCallback(mNextAlarmCallback);
         mDataSaver.addCallback(this);
         mKeyguardStateController.addCallback(this);
-        mPrivacyItemController.addCallback(this);
         mSensorPrivacyController.addCallback(mSensorPrivacyListener);
         mLocationController.addCallback(this);
 
@@ -603,46 +586,9 @@
         mIconController.setIconVisibility(mSlotDataSaver, isDataSaving);
     }
 
-    @Override  // PrivacyItemController.Callback
-    public void privacyChanged(List<PrivacyItem> privacyItems) {
-        updatePrivacyItems(privacyItems);
-    }
-
-    private void updatePrivacyItems(List<PrivacyItem> items) {
-        boolean showCamera = false;
-        boolean showMicrophone = false;
-        boolean showLocation = false;
-        for (PrivacyItem item : items) {
-            if (item == null /* b/124234367 */) {
-                if (DEBUG) {
-                    Log.e(TAG, "updatePrivacyItems - null item found");
-                    StringWriter out = new StringWriter();
-                    mPrivacyItemController.dump(null, new PrintWriter(out), null);
-                    Log.e(TAG, out.toString());
-                }
-                continue;
-            }
-            switch (item.getPrivacyType()) {
-                case TYPE_CAMERA:
-                    showCamera = true;
-                    break;
-                case TYPE_LOCATION:
-                    showLocation = true;
-                    break;
-                case TYPE_MICROPHONE:
-                    showMicrophone = true;
-                    break;
-            }
-        }
-
-        mIconController.setIconVisibility(mSlotCamera, showCamera);
-        mIconController.setIconVisibility(mSlotMicrophone, showMicrophone);
-        mIconController.setIconVisibility(mSlotLocation, showLocation);
-    }
-
     @Override
     public void onLocationActiveChanged(boolean active) {
-        if (!PrivacyItemControllerKt.isPermissionsHubEnabled()) updateLocation();
+        updateLocation();
     }
 
     // Updates the status view based on the current state of location requests.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
index f359fe7..deea3f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
@@ -14,11 +14,9 @@
 
 package com.android.systemui.statusbar.phone;
 
-import android.annotation.NonNull;
 import android.view.View;
 
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 
 /**
  * {@link ShadeController} is an abstraction of the work that used to be hard-coded in
@@ -30,14 +28,6 @@
 public interface ShadeController {
 
     /**
-     * Shows the keyguard bouncer - the password challenge on the lock screen
-     *
-     * @param scrimmed true when the bouncer should show scrimmed, false when the user will be
-     * dragging it and translation should be deferred {@see KeyguardBouncer#show(boolean, boolean)}
-     */
-    void showBouncer(boolean scrimmed);
-
-    /**
      * Make our window larger and the panel expanded
      */
     void instantExpandNotificationsPanel();
@@ -71,20 +61,6 @@
     void addPostCollapseAction(Runnable action);
 
     /**
-     * Ask shade controller to set the state to {@link StatusBarState#KEYGUARD}, but only from
-     * {@link StatusBarState#SHADE_LOCKED}
-     */
-    void goToKeyguard();
-
-    /**
-     * When the keyguard is showing and covered by something (bouncer, keyguard activity, etc.) it
-     * is occluded. This is controlled by {@link com.android.server.policy.PhoneWindowManager}
-     *
-     * @return whether the keyguard is currently occluded
-     */
-    boolean isOccluded();
-
-    /**
      * Notify the shade controller that the current user changed
      *
      * @param newUserId userId of the new user
@@ -92,22 +68,6 @@
     void setLockscreenUser(int newUserId);
 
     /**
-     * Dozing is when the screen is in AOD or asleep
-     *
-     * @return true if we are dozing
-     */
-    boolean isDozing();
-
-    /**
-     * Ask the display to wake up if currently dozing, else do nothing
-     *
-     * @param time when to wake up
-     * @param view the view requesting the wakeup
-     * @param why the reason for the wake up
-     */
-    void wakeUpIfDozing(long time, View view, @NonNull String why);
-
-    /**
      * If secure with redaction: Show bouncer, go to unlocked shade.
      *
      * <p>If secure without redaction or no security: Go to {@link StatusBarState#SHADE_LOCKED}.</p>
@@ -117,11 +77,6 @@
     void goToLockedShade(View startingChild);
 
     /**
-     * Adds a {@param runnable} to be executed after Keyguard is gone.
-     */
-    void addAfterKeyguardGoneRunnable(Runnable runnable);
-
-    /**
      * Close the shade if it was open
      *
      * @return true if the shade was open, else false
@@ -135,16 +90,4 @@
      * @param animate
      */
     void collapsePanel(boolean animate);
-
-    /**
-     * Callback to tell the shade controller that an activity launch animation was canceled
-     */
-    void onLaunchAnimationCancelled();
-
-    /**
-     * Callback to notify the shade controller that a {@link ActivatableNotificationView} has become
-     * inactive
-     */
-    void onActivationReset();
-
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 170261e..709143d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -237,9 +237,9 @@
 import java.util.Optional;
 
 import javax.inject.Named;
+import javax.inject.Provider;
 
 import dagger.Lazy;
-import dagger.Subcomponent;
 
 public class StatusBar extends SystemUI implements DemoMode,
         ActivityStarter, KeyguardStateController.Callback,
@@ -343,6 +343,7 @@
     private BiometricUnlockController mBiometricUnlockController;
     private final LightBarController mLightBarController;
     private final Lazy<LockscreenWallpaper> mLockscreenWallpaperLazy;
+    @Nullable
     protected LockscreenWallpaper mLockscreenWallpaper;
     private final AutoHideController mAutoHideController;
     @Nullable
@@ -377,9 +378,10 @@
     private final FalsingManager mFalsingManager;
     private final BroadcastDispatcher mBroadcastDispatcher;
     private final ConfigurationController mConfigurationController;
-    private final StatusBarWindowViewController mStatusBarWindowViewController;
+    protected StatusBarWindowViewController mStatusBarWindowViewController;
     private final DozeParameters mDozeParameters;
     private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
+    private final Provider<StatusBarComponent.Builder> mStatusBarComponentBuilder;
     private final PluginManager mPluginManager;
     private final RemoteInputUriController mRemoteInputUriController;
     private final Optional<Divider> mDividerOptional;
@@ -583,6 +585,8 @@
                     }
                 }
 
+                // TODO: (b/145659174) remove when moving to NewNotifPipeline. Replaced by
+                //  KeyguardCoordinator
                 @Override
                 public void onStrongAuthStateChanged(int userId) {
                     super.onStrongAuthStateChanged(userId);
@@ -659,7 +663,6 @@
             NotificationListener notificationListener,
             ConfigurationController configurationController,
             StatusBarWindowController statusBarWindowController,
-            StatusBarWindowViewController statusBarWindowViewController,
             LockscreenLockIconController lockscreenLockIconController,
             DozeParameters dozeParameters,
             ScrimController scrimController,
@@ -673,6 +676,7 @@
             VolumeComponent volumeComponent,
             CommandQueue commandQueue,
             Optional<Recents> recentsOptional,
+            Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
             PluginManager pluginManager,
             RemoteInputUriController remoteInputUriController,
             Optional<Divider> dividerOptional,
@@ -732,7 +736,6 @@
         mNotificationListener = notificationListener;
         mConfigurationController = configurationController;
         mStatusBarWindowController = statusBarWindowController;
-        mStatusBarWindowViewController = statusBarWindowViewController;
         mLockscreenLockIconController = lockscreenLockIconController;
         mDozeServiceHost = dozeServiceHost;
         mPowerManager = powerManager;
@@ -746,6 +749,7 @@
         mVolumeComponent = volumeComponent;
         mCommandQueue = commandQueue;
         mRecentsOptional = recentsOptional;
+        mStatusBarComponentBuilder = statusBarComponentBuilder;
         mPluginManager = pluginManager;
         mRemoteInputUriController = remoteInputUriController;
         mDividerOptional = dividerOptional;
@@ -895,7 +899,8 @@
 
         mKeyguardUpdateMonitor.registerCallback(mUpdateCallback);
         mDozeServiceHost.initialize(this, mNotificationIconAreaController,
-                mStatusBarWindow, mStatusBarKeyguardViewManager,
+                mStatusBarKeyguardViewManager,
+                mStatusBarWindowViewController,
                 mNotificationPanel, mAmbientIndicationContainer);
 
         Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(this);
@@ -962,7 +967,7 @@
         updateResources();
         updateTheme();
 
-        inflateStatusBarWindow(context);
+        inflateStatusBarWindow();
         mStatusBarWindowViewController.setService(this);
         mStatusBarWindow.setOnTouchListener(getStatusBarWindowTouchListener());
 
@@ -1055,7 +1060,7 @@
 
         createNavigationBar(result);
 
-        if (ENABLE_LOCKSCREEN_WALLPAPER) {
+        if (ENABLE_LOCKSCREEN_WALLPAPER && mWallpaperSupported) {
             mLockscreenWallpaper = mLockscreenWallpaperLazy.get();
             mLockscreenWallpaper.setHandler(mHandler);
         }
@@ -1233,7 +1238,9 @@
         mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanel,
                 mHeadsUpManager, mStatusBarWindow, mStackScroller, mDozeScrimController,
                 mScrimController, mActivityLaunchAnimator, mDynamicPrivacyController,
-                mNotificationAlertingManager, rowBinder, mKeyguardStateController, mCommandQueue);
+                mNotificationAlertingManager, rowBinder, mKeyguardStateController,
+                mKeyguardIndicationController,
+                this /* statusBar */, mCommandQueue);
 
         mNotificationListController =
                 new NotificationListController(
@@ -1246,7 +1253,7 @@
 
         mNotificationActivityStarter =
                 mStatusBarNotificationActivityStarterBuilder
-                        .setShadeController(this)
+                        .setStatusBar(this)
                         .setActivityLaunchAnimator(mActivityLaunchAnimator)
                         .setNotificationPresenter(mPresenter)
                         .build();
@@ -1276,17 +1283,13 @@
         mCommandQueue.disable(mDisplayId, state1, state2, false /* animate */);
     }
 
-    @Override
-    public void addAfterKeyguardGoneRunnable(Runnable runnable) {
-        mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
-    }
-
-    @Override
-    public boolean isDozing() {
-        return mDozing;
-    }
-
-    @Override
+    /**
+     * Ask the display to wake up if currently dozing, else do nothing
+     *
+     * @param time when to wake up
+     * @param where the view requesting the wakeup
+     * @param why the reason for the wake up
+     */
     public void wakeUpIfDozing(long time, View where, String why) {
         if (mDozing) {
             mPowerManager.wakeUp(
@@ -1380,8 +1383,11 @@
                 mNotificationPanel);
     }
 
-    protected void inflateStatusBarWindow(Context context) {
+    private void inflateStatusBarWindow() {
         mStatusBarWindow = mSuperStatusBarViewFactory.getStatusBarWindowView();
+        StatusBarComponent statusBarComponent = mStatusBarComponentBuilder.get()
+                .statusBarWindowView(mStatusBarWindow).build();
+        mStatusBarWindowViewController = statusBarComponent.getStatusBarWindowViewController();
         mStatusBarWindowViewController.setupExpandedStatusBar();
     }
 
@@ -1699,7 +1705,7 @@
     @Override
     public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
         mEntryManager.updateNotifications("onHeadsUpStateChanged");
-        if (isDozing() && isHeadsUp) {
+        if (mStatusBarStateController.isDozing() && isHeadsUp) {
             entry.setPulseSuppressed(false);
             mDozeServiceHost.fireNotificationPulse(entry);
             if (mDozeServiceHost.isPulsing()) {
@@ -1751,7 +1757,12 @@
         return mAmbientIndicationContainer;
     }
 
-    @Override
+    /**
+     * When the keyguard is showing and covered by a "showWhenLocked" activity it
+     * is occluded. This is controlled by {@link com.android.server.policy.PhoneWindowManager}
+     *
+     * @return whether the keyguard is currently occluded
+     */
     public boolean isOccluded() {
         return mIsOccluded;
     }
@@ -2794,7 +2805,9 @@
 
     @Override
     public void setLockscreenUser(int newUserId) {
-        mLockscreenWallpaper.setCurrentUser(newUserId);
+        if (mLockscreenWallpaper != null) {
+            mLockscreenWallpaper.setCurrentUser(newUserId);
+        }
         mScrimController.setCurrentUser(newUserId);
         if (mWallpaperSupported) {
             mWallpaperChangedReceiver.onReceive(mContext, null);
@@ -3437,16 +3450,11 @@
     private void showBouncerIfKeyguard() {
         if ((mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)
                 && !mKeyguardViewMediator.isHiding()) {
-            showBouncer(true /* scrimmed */);
+            mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */);
         }
     }
 
     @Override
-    public void showBouncer(boolean scrimmed) {
-        mStatusBarKeyguardViewManager.showBouncer(scrimmed);
-    }
-
-    @Override
     public void instantExpandNotificationsPanel() {
         // Make our window larger and the panel expanded.
         makeExpandedVisible(true);
@@ -3567,10 +3575,6 @@
                 mStatusBarKeyguardViewManager.isOccluded());
     }
 
-    public void onActivationReset() {
-        mKeyguardIndicationController.hideTransientIndication();
-    }
-
     public void onTrackingStarted() {
         runPostCollapseRunnables();
     }
@@ -3612,7 +3616,7 @@
     public void onTrackingStopped(boolean expand) {
         if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
             if (!expand && !mKeyguardStateController.canDismissLockScreen()) {
-                showBouncer(false /* scrimmed */);
+                mStatusBarKeyguardViewManager.showBouncer(false /* scrimmed */);
             }
         }
     }
@@ -3672,15 +3676,6 @@
     }
 
     /**
-     * Goes back to the keyguard after hanging around in {@link StatusBarState#SHADE_LOCKED}.
-     */
-    public void goToKeyguard() {
-        if (mState == StatusBarState.SHADE_LOCKED) {
-            mStatusBarStateController.setState(StatusBarState.KEYGUARD);
-        }
-    }
-
-    /**
      * Propagation of the bouncer state, indicating that it's fully visible.
      */
     public void setBouncerShowing(boolean bouncerShowing) {
@@ -4003,7 +3998,8 @@
     }
 
     public boolean shouldIgnoreTouch() {
-        return isDozing() && mDozeServiceHost.getIgnoreTouchWhilePulsing();
+        return mStatusBarStateController.isDozing()
+                && mDozeServiceHost.getIgnoreTouchWhilePulsing();
     }
 
     // Begin Extra BaseStatusBar methods.
@@ -4391,11 +4387,6 @@
         return mGutsManager;
     }
 
-    @Subcomponent
-    public interface StatusBarInjector {
-        void createStatusBar(StatusBar statusbar);
-    }
-
     boolean isTransientShown() {
         return mTransientShown;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarComponent.java
new file mode 100644
index 0000000..f3c843c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarComponent.java
@@ -0,0 +1,57 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Scope;
+
+import dagger.BindsInstance;
+import dagger.Subcomponent;
+
+/**
+ * Dagger subcomponent tied to the lifecycle of StatusBar views.
+ */
+@Subcomponent
+public interface StatusBarComponent {
+    /**
+     * Builder for {@link StatusBarComponent}.
+     */
+    @Subcomponent.Builder
+    interface Builder {
+        @BindsInstance Builder statusBarWindowView(StatusBarWindowView statusBarWindowView);
+        StatusBarComponent build();
+    }
+
+    /**
+     * Scope annotation for singleton items within the StatusBarComponent.
+     */
+    @Documented
+    @Retention(RUNTIME)
+    @Scope
+    @interface StatusBarScope {}
+
+    /**
+     * Creates a StatusBarWindowViewController.
+     */
+    @StatusBarScope
+    StatusBarWindowViewController getStatusBarWindowViewController();
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 31d0362..dac4e58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -365,6 +365,12 @@
         cancelPendingWakeupAction();
     }
 
+    /**
+     * Shows the keyguard bouncer - the password challenge on the lock screen
+     *
+     * @param scrimmed true when the bouncer should show scrimmed, false when the user will be
+     * dragging it and translation should be deferred {@see KeyguardBouncer#show(boolean, boolean)}
+     */
     public void showBouncer(boolean scrimmed) {
         if (mShowing && !mBouncer.isShowing()) {
             mBouncer.show(false /* resetSecuritySelection */, scrimmed);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
index 5d69409..312c85f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
@@ -77,6 +77,7 @@
 import java.util.Optional;
 
 import javax.inject.Named;
+import javax.inject.Provider;
 import javax.inject.Singleton;
 
 import dagger.Lazy;
@@ -143,7 +144,6 @@
             NotificationListener notificationListener,
             ConfigurationController configurationController,
             StatusBarWindowController statusBarWindowController,
-            StatusBarWindowViewController statusBarWindowViewController,
             LockscreenLockIconController lockscreenLockIconController,
             DozeParameters dozeParameters,
             ScrimController scrimController,
@@ -157,6 +157,7 @@
             VolumeComponent volumeComponent,
             CommandQueue commandQueue,
             Optional<Recents> recentsOptional,
+            Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
             PluginManager pluginManager,
             RemoteInputUriController remoteInputUriController,
             Optional<Divider> dividerOptional,
@@ -217,7 +218,6 @@
                 notificationListener,
                 configurationController,
                 statusBarWindowController,
-                statusBarWindowViewController,
                 lockscreenLockIconController,
                 dozeParameters,
                 scrimController,
@@ -231,6 +231,7 @@
                 volumeComponent,
                 commandQueue,
                 recentsOptional,
+                statusBarComponentBuilder,
                 pluginManager,
                 remoteInputUriController,
                 dividerOptional,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 863874e..1988b42 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -93,6 +93,7 @@
     private final NotificationRemoteInputManager mRemoteInputManager;
     private final NotificationLockscreenUserManager mLockscreenUserManager;
     private final ShadeController mShadeController;
+    private final StatusBar mStatusBar;
     private final KeyguardStateController mKeyguardStateController;
     private final ActivityStarter mActivityStarter;
     private final NotificationEntryManager mEntryManager;
@@ -104,6 +105,7 @@
     private final NotificationPresenter mPresenter;
     private final LockPatternUtils mLockPatternUtils;
     private final HeadsUpManagerPhone mHeadsUpManager;
+    private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     private final KeyguardManager mKeyguardManager;
     private final ActivityLaunchAnimator mActivityLaunchAnimator;
     private final IStatusBarService mBarService;
@@ -121,11 +123,14 @@
             NotificationPresenter presenter, NotificationEntryManager entryManager,
             HeadsUpManagerPhone headsUpManager, ActivityStarter activityStarter,
             ActivityLaunchAnimator activityLaunchAnimator, IStatusBarService statusBarService,
-            StatusBarStateController statusBarStateController, KeyguardManager keyguardManager,
+            StatusBarStateController statusBarStateController,
+            StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+            KeyguardManager keyguardManager,
             IDreamManager dreamManager, NotificationRemoteInputManager remoteInputManager,
             StatusBarRemoteInputCallback remoteInputCallback, NotificationGroupManager groupManager,
             NotificationLockscreenUserManager lockscreenUserManager,
-            ShadeController shadeController, KeyguardStateController keyguardStateController,
+            ShadeController shadeController, StatusBar statusBar,
+            KeyguardStateController keyguardStateController,
             NotificationInterruptionStateProvider notificationInterruptionStateProvider,
             MetricsLogger metricsLogger, LockPatternUtils lockPatternUtils,
             Handler mainThreadHandler, Handler backgroundHandler,
@@ -137,11 +142,14 @@
         mActivityLaunchAnimator = activityLaunchAnimator;
         mBarService = statusBarService;
         mCommandQueue = commandQueue;
+        mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
         mKeyguardManager = keyguardManager;
         mDreamManager = dreamManager;
         mRemoteInputManager = remoteInputManager;
         mLockscreenUserManager = lockscreenUserManager;
         mShadeController = shadeController;
+        // TODO: use KeyguardStateController#isOccluded to remove this dependency
+        mStatusBar = statusBar;
         mKeyguardStateController = keyguardStateController;
         mActivityStarter = activityStarter;
         mEntryManager = entryManager;
@@ -198,7 +206,7 @@
         final boolean afterKeyguardGone = isActivityIntent
                 && mActivityIntentHelper.wouldLaunchResolverActivity(intent.getIntent(),
                 mLockscreenUserManager.getCurrentUserId());
-        final boolean wasOccluded = mShadeController.isOccluded();
+        final boolean wasOccluded = mStatusBar.isOccluded();
         boolean showOverLockscreen = mKeyguardStateController.isShowing() && intent != null
                 && mActivityIntentHelper.wouldShowOverLockscreen(intent.getIntent(),
                 mLockscreenUserManager.getCurrentUserId());
@@ -253,8 +261,8 @@
             mShadeController.addPostCollapseAction(runnable);
             mShadeController.collapsePanel(true /* animate */);
         } else if (mKeyguardStateController.isShowing()
-                && mShadeController.isOccluded()) {
-            mShadeController.addAfterKeyguardGoneRunnable(runnable);
+                && mStatusBar.isOccluded()) {
+            mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
             mShadeController.collapsePanel();
         } else {
             mBackgroundHandler.postAtFrontOfQueue(runnable);
@@ -384,7 +392,7 @@
                         .addNextIntentWithParentStack(intent)
                         .startActivities(getActivityOptions(
                                 mActivityLaunchAnimator.getLaunchAnimation(
-                                        row, mShadeController.isOccluded())),
+                                        row, mStatusBar.isOccluded())),
                                 new UserHandle(UserHandle.getUserId(appUid)));
                 mActivityLaunchAnimator.setLaunchResult(launchResult, true /* isActivityIntent */);
                 if (shouldCollapse()) {
@@ -500,6 +508,7 @@
         private final ActivityStarter mActivityStarter;
         private final IStatusBarService mStatusBarService;
         private final StatusBarStateController mStatusBarStateController;
+        private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
         private final KeyguardManager mKeyguardManager;
         private final IDreamManager mDreamManager;
         private final NotificationRemoteInputManager mRemoteInputManager;
@@ -518,6 +527,7 @@
         private ShadeController mShadeController;
         private NotificationPresenter mNotificationPresenter;
         private ActivityLaunchAnimator mActivityLaunchAnimator;
+        private StatusBar mStatusBar;
 
         @Inject
         public Builder(Context context,
@@ -528,6 +538,7 @@
                 ActivityStarter activityStarter,
                 IStatusBarService statusBarService,
                 StatusBarStateController statusBarStateController,
+                StatusBarKeyguardViewManager statusBarKeyguardViewManager,
                 KeyguardManager keyguardManager,
                 IDreamManager dreamManager,
                 NotificationRemoteInputManager remoteInputManager,
@@ -551,6 +562,7 @@
             mActivityStarter = activityStarter;
             mStatusBarService = statusBarService;
             mStatusBarStateController = statusBarStateController;
+            mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
             mKeyguardManager = keyguardManager;
             mDreamManager = dreamManager;
             mRemoteInputManager = remoteInputManager;
@@ -567,8 +579,11 @@
             mBubbleController = bubbleController;
             mSuperStatusBarViewFactory = superStatusBarViewFactory;
         }
-        public Builder setShadeController(ShadeController shadeController) {
-            mShadeController = shadeController;
+
+        /** Sets the status bar to use as {@link StatusBar} and {@link ShadeController}. */
+        public Builder setStatusBar(StatusBar statusBar) {
+            mStatusBar = statusBar;
+            mShadeController = statusBar;
             return this;
         }
 
@@ -593,6 +608,7 @@
                     mActivityLaunchAnimator,
                     mStatusBarService,
                     mStatusBarStateController,
+                    mStatusBarKeyguardViewManager,
                     mKeyguardManager,
                     mDreamManager,
                     mRemoteInputManager,
@@ -600,6 +616,7 @@
                     mGroupManager,
                     mLockscreenUserManager,
                     mShadeController,
+                    mStatusBar,
                     mKeyguardStateController,
                     mNotificationInterruptionStateProvider,
                     mMetricsLogger,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 30e26e5..2649166 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -49,6 +49,7 @@
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationPresenter;
@@ -113,6 +114,8 @@
     private final DozeScrimController mDozeScrimController;
     private final ScrimController mScrimController;
     private final Context mContext;
+    private final KeyguardIndicationController mKeyguardIndicationController;
+    private final StatusBar mStatusBar;
     private final CommandQueue mCommandQueue;
 
     private final AccessibilityManager mAccessibilityManager;
@@ -140,12 +143,17 @@
             NotificationAlertingManager notificationAlertingManager,
             NotificationRowBinderImpl notificationRowBinder,
             KeyguardStateController keyguardStateController,
+            KeyguardIndicationController keyguardIndicationController,
+            StatusBar statusBar,
             CommandQueue commandQueue) {
         mContext = context;
         mKeyguardStateController = keyguardStateController;
         mNotificationPanel = panel;
         mHeadsUpManager = headsUp;
         mDynamicPrivacyController = dynamicPrivacyController;
+        mKeyguardIndicationController = keyguardIndicationController;
+        // TODO: use KeyguardStateController#isOccluded to remove this dependency
+        mStatusBar = statusBar;
         mCommandQueue = commandQueue;
         mAboveShelfObserver = new AboveShelfObserver(stackScroller);
         mActivityLaunchAnimator = activityLaunchAnimator;
@@ -319,7 +327,7 @@
                     mCommandQueue.animateCollapsePanels();
                 } else if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED
                         && !isCollapsing()) {
-                    mShadeController.goToKeyguard();
+                    mStatusBarStateController.setState(StatusBarState.KEYGUARD);
                 }
             }
         }
@@ -330,7 +338,7 @@
     }
 
     public boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn) {
-        if (mShadeController.isOccluded()) {
+        if (mStatusBar.isOccluded()) {
             boolean devicePublic = mLockscreenUserManager.
                     isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId());
             boolean userPublic = devicePublic
@@ -356,7 +364,7 @@
             } else {
                 // we only allow head-up on the lockscreen if it doesn't have a fullscreen intent
                 return !mKeyguardStateController.isShowing()
-                        || mShadeController.isOccluded();
+                        || mStatusBar.isOccluded();
             }
         }
         return true;
@@ -416,7 +424,7 @@
     public void onActivationReset(ActivatableNotificationView view) {
         if (view == mNotificationPanel.getActivatedChild()) {
             mNotificationPanel.setActivatedChild(null);
-            mShadeController.onActivationReset();
+            mKeyguardIndicationController.hideTransientIndication();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 3e6ba4d..2012b57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -64,6 +64,7 @@
     private final ActivityStarter mActivityStarter;
     private final Lazy<ShadeController> mShadeControllerLazy;
     private final Context mContext;
+    private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     private final ActivityIntentHelper mActivityIntentHelper;
     private final NotificationGroupManager mGroupManager;
     private View mPendingWorkRemoteInputView;
@@ -81,9 +82,11 @@
             NotificationLockscreenUserManager notificationLockscreenUserManager,
             KeyguardStateController keyguardStateController,
             StatusBarStateController statusBarStateController,
+            StatusBarKeyguardViewManager statusBarKeyguardViewManager,
             ActivityStarter activityStarter, Lazy<ShadeController> shadeControllerLazy,
             CommandQueue commandQueue) {
         mContext = context;
+        mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
         mContext.registerReceiverAsUser(mChallengeReceiver, UserHandle.ALL,
                 new IntentFilter(ACTION_DEVICE_LOCKED_CHANGED), null, null);
         mLockscreenUserManager = notificationLockscreenUserManager;
@@ -118,7 +121,7 @@
         if (!row.isPinned()) {
             mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
         }
-        mShadeControllerLazy.get().showBouncer(true /* scrimmed */);
+        mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */);
         mPendingRemoteInputView = clicked;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
index feac5da..f8929e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
@@ -43,7 +43,6 @@
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.PulseExpansionHandler;
-import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -57,14 +56,13 @@
 import java.io.PrintWriter;
 
 import javax.inject.Inject;
-import javax.inject.Singleton;
 
 import dagger.Lazy;
 
 /**
  * Controller for {@link StatusBarWindowView}.
  */
-@Singleton
+//@Singleton
 public class StatusBarWindowViewController {
     private final InjectionInflationController mInjectionInflationController;
     private final NotificationWakeUpCoordinator mCoordinator;
@@ -116,9 +114,9 @@
             DozeLog dozeLog,
             DozeParameters dozeParameters,
             CommandQueue commandQueue,
-            SuperStatusBarViewFactory superStatusBarViewFactory,
             Lazy<ShadeController> shadeControllerLazy,
-            DockManager dockManager) {
+            DockManager dockManager,
+            StatusBarWindowView statusBarWindowView) {
         mInjectionInflationController = injectionInflationController;
         mCoordinator = coordinator;
         mPulseExpansionHandler = pulseExpansionHandler;
@@ -134,7 +132,7 @@
         mDozeLog = dozeLog;
         mDozeParameters = dozeParameters;
         mCommandQueue = commandQueue;
-        mView = superStatusBarViewFactory.getStatusBarWindowView();
+        mView = statusBarWindowView;
         mShadeControllerLazy = shadeControllerLazy;
         mDockManager = dockManager;
 
@@ -265,7 +263,7 @@
                 if (isDown) {
                     mStackScrollLayout.closeControlsIfOutsideTouch(ev);
                 }
-                if (mService.isDozing()) {
+                if (mStatusBarStateController.isDozing()) {
                     mService.mDozeScrimController.extendPulse();
                 }
                 // In case we start outside of the view bounds (below the status bar), we need to
@@ -286,7 +284,8 @@
 
             @Override
             public boolean shouldInterceptTouchEvent(MotionEvent ev) {
-                if (mService.isDozing() && !mService.isPulsing() && !mDockManager.isDocked()) {
+                if (mStatusBarStateController.isDozing() && !mService.isPulsing()
+                        && !mDockManager.isDocked()) {
                     // Capture all touch events in always-on.
                     return true;
                 }
@@ -294,7 +293,7 @@
                 if (notificationPanelView.isFullyExpanded()
                         && mDragDownHelper.isDragDownEnabled()
                         && !mService.isBouncerShowing()
-                        && !mService.isDozing()) {
+                        && !mStatusBarStateController.isDozing()) {
                     intercept = mDragDownHelper.onInterceptTouchEvent(ev);
                 }
 
@@ -314,7 +313,7 @@
             @Override
             public boolean handleTouchEvent(MotionEvent ev) {
                 boolean handled = false;
-                if (mService.isDozing()) {
+                if (mStatusBarStateController.isDozing()) {
                     handled = !mService.isPulsing();
                 }
                 if ((mDragDownHelper.isDragDownEnabled() && !handled)
@@ -360,7 +359,7 @@
                         break;
                     case KeyEvent.KEYCODE_VOLUME_DOWN:
                     case KeyEvent.KEYCODE_VOLUME_UP:
-                        if (mService.isDozing()) {
+                        if (mStatusBarStateController.isDozing()) {
                             MediaSessionLegacyHelper.getHelper(mView.getContext())
                                     .sendVolumeKeyEvent(
                                             event, AudioManager.USE_DEFAULT_STREAM_TYPE, true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 3f25bb6..b0cd90c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -50,9 +50,9 @@
 
 import java.io.PrintWriter;
 import java.util.BitSet;
-import java.util.concurrent.Executor;
-import java.util.Objects;
 import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -552,8 +552,8 @@
         // If this is the data subscription, update the currentState data name
         if (mCurrentState.networkNameData.equals(mNetworkNameDefault) && mServiceState != null
                 && mCurrentState.dataSim
-                && !TextUtils.isEmpty(mServiceState.getDataOperatorAlphaShort())) {
-            mCurrentState.networkNameData = mServiceState.getDataOperatorAlphaShort();
+                && !TextUtils.isEmpty(mServiceState.getOperatorAlphaShort())) {
+            mCurrentState.networkNameData = mServiceState.getOperatorAlphaShort();
         }
 
         notifyListenersIfNecessary();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java
index 9b685f0..74739e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java
@@ -16,32 +16,44 @@
 
 package com.android.systemui.statusbar.tv;
 
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.annotation.IntDef;
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.graphics.PixelFormat;
-import android.graphics.drawable.Drawable;
+import android.util.ArraySet;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewPropertyAnimator;
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
-import android.widget.ImageView;
 import android.widget.TextView;
 
 import com.android.systemui.R;
 
-import java.util.ArrayList;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
-import java.util.List;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.Set;
 
+/**
+ * A component of {@link TvStatusBar} responsible for notifying the user whenever an application is
+ * recording audio.
+ *
+ * @see TvStatusBar
+ */
 class AudioRecordingDisclosureBar {
     private static final String TAG = "AudioRecordingDisclosureBar";
     private static final boolean DEBUG = false;
@@ -50,121 +62,310 @@
     // CtsSystemUiHostTestCases:TvMicrophoneCaptureIndicatorTest
     private static final String LAYOUT_PARAMS_TITLE = "MicrophoneCaptureIndicator";
 
-    private static final int ANIM_DURATION_MS = 150;
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"STATE_"}, value = {
+            STATE_NOT_SHOWN,
+            STATE_APPEARING,
+            STATE_SHOWN,
+            STATE_MINIMIZING,
+            STATE_MINIMIZED,
+            STATE_MAXIMIZING,
+            STATE_DISAPPEARING
+    })
+    public @interface State {}
+
+    private static final int STATE_NOT_SHOWN = 0;
+    private static final int STATE_APPEARING = 1;
+    private static final int STATE_SHOWN = 2;
+    private static final int STATE_MINIMIZING = 3;
+    private static final int STATE_MINIMIZED = 4;
+    private static final int STATE_MAXIMIZING = 5;
+    private static final int STATE_DISAPPEARING = 6;
+
+    private static final int ANIMATION_DURATION = 600;
+    private static final int MAXIMIZED_DURATION = 3000;
+    private static final int PULSE_BIT_DURATION = 1000;
+    private static final float PULSE_SCALE = 1.25f;
 
     private final Context mContext;
-    private final List<String> mAudioRecordingApps = new ArrayList<>();
-    private View mView;
-    private ViewGroup mAppsInfoContainer;
+
+    private View mIndicatorView;
+    private View mIconTextsContainer;
+    private View mIconContainerBg;
+    private View mIcon;
+    private View mBgRight;
+    private View mTextsContainers;
+    private TextView mTextView;
+
+    @State private int mState = STATE_NOT_SHOWN;
+    private final Set<String> mAudioRecordingApps = new HashSet<>();
+    private final Queue<String> mPendingNotifications = new LinkedList<>();
 
     AudioRecordingDisclosureBar(Context context) {
         mContext = context;
     }
 
     void start() {
-        // Inflate and add audio recording disclosure bar
-        createView();
-
         // Register AppOpsManager callback
         final AppOpsManager appOpsManager = (AppOpsManager) mContext.getSystemService(
                 Context.APP_OPS_SERVICE);
         appOpsManager.startWatchingActive(
-                new String[]{AppOpsManager.OPSTR_RECORD_AUDIO}, mContext.getMainExecutor(),
+                new String[]{AppOpsManager.OPSTR_RECORD_AUDIO},
+                mContext.getMainExecutor(),
                 new OnActiveRecordingListener());
     }
 
-    private void createView() {
-        //TODO(b/142228704): this is to be re-implemented once proper design is completed
-        mView = View.inflate(mContext,
-                R.layout.tv_status_bar_audio_recording, null);
-        mAppsInfoContainer = mView.findViewById(R.id.container);
+    private void onStartedRecording(String packageName) {
+        if (!mAudioRecordingApps.add(packageName)) {
+            // This app is already known to perform recording
+            return;
+        }
+
+        switch (mState) {
+            case STATE_NOT_SHOWN:
+                show(packageName);
+                break;
+
+            case STATE_MINIMIZED:
+                expand(packageName);
+                break;
+
+            case STATE_DISAPPEARING:
+            case STATE_APPEARING:
+            case STATE_MAXIMIZING:
+            case STATE_SHOWN:
+            case STATE_MINIMIZING:
+                // Currently animating or expanded. Thus add to the pending notifications, and it
+                // will be picked up once the indicator comes to the STATE_MINIMIZED.
+                mPendingNotifications.add(packageName);
+                break;
+        }
+    }
+
+    private void onDoneRecording(String packageName) {
+        if (!mAudioRecordingApps.remove(packageName)) {
+            // Was not marked as an active recorder, do nothing
+            return;
+        }
+
+        // If not MINIMIZED, will check whether the indicator should be hidden when the indicator
+        // comes to the STATE_MINIMIZED eventually. If is in the STATE_MINIMIZED, but there are
+        // other active recorders - simply ignore.
+        if (mState == STATE_MINIMIZED && mAudioRecordingApps.isEmpty()) {
+            hide();
+        }
+    }
+
+    private void show(String packageName) {
+        // Inflate the indicator view
+        mIndicatorView = LayoutInflater.from(mContext).inflate(
+                R.layout.tv_audio_recording_indicator,
+                null);
+        mIconTextsContainer = mIndicatorView.findViewById(R.id.icon_texts_container);
+        mIconContainerBg = mIconTextsContainer.findViewById(R.id.icon_container_bg);
+        mIcon = mIconTextsContainer.findViewById(R.id.icon_mic);
+        mTextsContainers = mIconTextsContainer.findViewById(R.id.texts_container);
+        mTextView = mTextsContainers.findViewById(R.id.text);
+        mBgRight = mIndicatorView.findViewById(R.id.bg_right);
+
+        // Set up the notification text
+        final String label = getApplicationLabel(packageName);
+        mTextView.setText(mContext.getString(R.string.app_accessed_mic, label));
+
+        // Initially change the visibility to INVISIBLE, wait until and receives the size and
+        // then animate it moving from "off" the screen correctly
+        mIndicatorView.setVisibility(View.INVISIBLE);
+        mIndicatorView
+                .getViewTreeObserver()
+                .addOnGlobalLayoutListener(
+                        new ViewTreeObserver.OnGlobalLayoutListener() {
+                            @Override
+                            public void onGlobalLayout() {
+                                // Remove the observer
+                                mIndicatorView.getViewTreeObserver().removeOnGlobalLayoutListener(
+                                        this);
+
+                                // Now that the width of the indicator has been assigned, we can
+                                // move it in from off the screen.
+                                final int initialOffset = mIndicatorView.getWidth();
+                                final AnimatorSet set = new AnimatorSet();
+                                set.setDuration(ANIMATION_DURATION);
+                                set.playTogether(
+                                        ObjectAnimator.ofFloat(mIndicatorView,
+                                                View.TRANSLATION_X, initialOffset, 0),
+                                        ObjectAnimator.ofFloat(mIndicatorView, View.ALPHA, 0f,
+                                                1f));
+                                set.addListener(
+                                        new AnimatorListenerAdapter() {
+                                            @Override
+                                            public void onAnimationStart(Animator animation,
+                                                    boolean isReverse) {
+                                                // Indicator is INVISIBLE at the moment, change it.
+                                                mIndicatorView.setVisibility(View.VISIBLE);
+                                            }
+
+                                            @Override
+                                            public void onAnimationEnd(Animator animation) {
+                                                startPulsatingAnimation();
+                                                onExpanded();
+                                            }
+                                        });
+                                set.start();
+                            }
+                        });
 
         final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
-                MATCH_PARENT,
+                WRAP_CONTENT,
                 WRAP_CONTENT,
                 WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                 PixelFormat.TRANSLUCENT);
-        layoutParams.gravity = Gravity.BOTTOM;
+        layoutParams.gravity = Gravity.TOP | Gravity.RIGHT;
         layoutParams.setTitle(LAYOUT_PARAMS_TITLE);
         layoutParams.packageName = mContext.getPackageName();
-
         final WindowManager windowManager = (WindowManager) mContext.getSystemService(
                 Context.WINDOW_SERVICE);
-        windowManager.addView(mView, layoutParams);
+        windowManager.addView(mIndicatorView, layoutParams);
 
-        // Set invisible first until it gains its actual size and we are able to hide it by moving
-        // off the screen
-        mView.setVisibility(View.INVISIBLE);
-        mView.getViewTreeObserver().addOnGlobalLayoutListener(
-                new ViewTreeObserver.OnGlobalLayoutListener() {
+        mState = STATE_APPEARING;
+    }
+
+    private void expand(String packageName) {
+        final String label = getApplicationLabel(packageName);
+        mTextView.setText(mContext.getString(R.string.app_accessed_mic, label));
+
+        final AnimatorSet set = new AnimatorSet();
+        set.playTogether(
+                ObjectAnimator.ofFloat(mIconTextsContainer, View.TRANSLATION_X, 0),
+                ObjectAnimator.ofFloat(mIconContainerBg, View.ALPHA, 1f),
+                ObjectAnimator.ofFloat(mTextsContainers, View.ALPHA, 1f),
+                ObjectAnimator.ofFloat(mBgRight, View.ALPHA, 1f));
+        set.setDuration(ANIMATION_DURATION);
+        set.addListener(
+                new AnimatorListenerAdapter() {
                     @Override
-                    public void onGlobalLayout() {
-                        // Now that we get the height, we can move the bar off ("below") the screen
-                        final int height = mView.getHeight();
-                        mView.setTranslationY(height);
-                        // Remove the observer
-                        mView.getViewTreeObserver()
-                                .removeOnGlobalLayoutListener(this);
-                        // Now, that the view has been measured, and the translation was set to
-                        // move it off the screen, we change the visibility to GONE
-                        mView.setVisibility(View.GONE);
+                    public void onAnimationEnd(Animator animation) {
+                        onExpanded();
                     }
                 });
+        set.start();
+
+        mState = STATE_MAXIMIZING;
     }
 
-    private void showAudioRecordingDisclosureBar() {
-        mView.setVisibility(View.VISIBLE);
-        mView.animate()
-                .translationY(0f)
-                .setDuration(ANIM_DURATION_MS)
-                .start();
+    private void minimize() {
+        final int targetOffset = mTextsContainers.getWidth();
+        final AnimatorSet set = new AnimatorSet();
+        set.playTogether(
+                ObjectAnimator.ofFloat(mIconTextsContainer, View.TRANSLATION_X, targetOffset),
+                ObjectAnimator.ofFloat(mIconContainerBg, View.ALPHA, 0f),
+                ObjectAnimator.ofFloat(mTextsContainers, View.ALPHA, 0f),
+                ObjectAnimator.ofFloat(mBgRight, View.ALPHA, 0f));
+        set.setDuration(ANIMATION_DURATION);
+        set.addListener(
+                new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        onMinimized();
+                    }
+                });
+        set.start();
+
+        mState = STATE_MINIMIZING;
     }
 
-    private void addToAudioRecordingDisclosureBar(String packageName) {
+    private void hide() {
+        final int targetOffset =
+                mIndicatorView.getWidth() - (int) mIconTextsContainer.getTranslationX();
+        final AnimatorSet set = new AnimatorSet();
+        set.playTogether(
+                ObjectAnimator.ofFloat(mIndicatorView, View.TRANSLATION_X, targetOffset),
+                ObjectAnimator.ofFloat(mIcon, View.ALPHA, 0f));
+        set.setDuration(ANIMATION_DURATION);
+        set.addListener(
+                new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        onHidden();
+                    }
+                });
+        set.start();
+
+        mState = STATE_DISAPPEARING;
+    }
+
+    private void onExpanded() {
+        mState = STATE_SHOWN;
+
+        mIndicatorView.postDelayed(this::minimize, MAXIMIZED_DURATION);
+    }
+
+    private void onMinimized() {
+        mState = STATE_MINIMIZED;
+
+        if (!mPendingNotifications.isEmpty()) {
+            // There is a new application that started recording, tell the user about it.
+            expand(mPendingNotifications.poll());
+        } else if (mAudioRecordingApps.isEmpty()) {
+            // Nobody is recording anymore, remove the indicator.
+            hide();
+        }
+    }
+
+    private void onHidden() {
+        final WindowManager windowManager = (WindowManager) mContext.getSystemService(
+                Context.WINDOW_SERVICE);
+        windowManager.removeView(mIndicatorView);
+
+        mIndicatorView = null;
+        mIconTextsContainer = null;
+        mIconContainerBg = null;
+        mIcon = null;
+        mTextsContainers = null;
+        mTextView = null;
+        mBgRight = null;
+
+        mState = STATE_NOT_SHOWN;
+    }
+
+    private void startPulsatingAnimation() {
+        final View pulsatingView = mIconTextsContainer.findViewById(R.id.pulsating_circle);
+        final ObjectAnimator animator =
+                ObjectAnimator.ofPropertyValuesHolder(
+                        pulsatingView,
+                        PropertyValuesHolder.ofFloat(View.SCALE_X, PULSE_SCALE),
+                        PropertyValuesHolder.ofFloat(View.SCALE_Y, PULSE_SCALE));
+        animator.setDuration(PULSE_BIT_DURATION);
+        animator.setRepeatCount(ObjectAnimator.INFINITE);
+        animator.setRepeatMode(ObjectAnimator.REVERSE);
+        animator.start();
+    }
+
+    private String getApplicationLabel(String packageName) {
         final PackageManager pm = mContext.getPackageManager();
         final ApplicationInfo appInfo;
         try {
             appInfo = pm.getApplicationInfo(packageName, 0);
         } catch (PackageManager.NameNotFoundException e) {
-            return;
+            return packageName;
         }
-        final CharSequence label = pm.getApplicationLabel(appInfo);
-        final Drawable icon = pm.getApplicationIcon(appInfo);
-
-        final View view = LayoutInflater.from(mContext).inflate(R.layout.tv_item_app_info,
-                mAppsInfoContainer, false);
-        ((TextView) view.findViewById(R.id.title)).setText(label);
-        ((ImageView) view.findViewById(R.id.icon)).setImageDrawable(icon);
-
-        mAppsInfoContainer.addView(view);
-    }
-
-    private void removeFromAudioRecordingDisclosureBar(int index) {
-        mAppsInfoContainer.removeViewAt(index);
-    }
-
-    private void hideAudioRecordingDisclosureBar() {
-        final ViewPropertyAnimator animator = mView.animate();
-        animator.translationY(mView.getHeight())
-                .setDuration(ANIM_DURATION_MS)
-                .withEndAction(() -> mView.setVisibility(View.GONE))
-                .start();
+        return pm.getApplicationLabel(appInfo).toString();
     }
 
     private class OnActiveRecordingListener implements AppOpsManager.OnOpActiveChangedListener {
-        private final List<String> mExemptApps;
+        private final Set<String> mExemptApps;
 
         private OnActiveRecordingListener() {
-            mExemptApps = Arrays.asList(mContext.getResources().getStringArray(
-                    R.array.audio_recording_disclosure_exempt_apps));
+            mExemptApps = new ArraySet<>(Arrays.asList(mContext.getResources().getStringArray(
+                    R.array.audio_recording_disclosure_exempt_apps)));
         }
 
         @Override
         public void onOpActiveChanged(String op, int uid, String packageName, boolean active) {
             if (DEBUG) {
                 Log.d(TAG,
-                        "OP_RECORD_AUDIO active change, active=" + active + ", app=" + packageName);
+                        "OP_RECORD_AUDIO active change, active=" + active + ", app="
+                                + packageName);
             }
 
             if (mExemptApps.contains(packageName)) {
@@ -174,37 +375,10 @@
                 return;
             }
 
-            final boolean alreadyTracking = mAudioRecordingApps.contains(packageName);
-            if ((active && alreadyTracking) || (!active && !alreadyTracking)) {
-                if (DEBUG) {
-                    Log.d(TAG, "\t- nothing changed");
-                }
-                return;
-            }
-
             if (active) {
-                if (DEBUG) {
-                    Log.d(TAG, "\t- new recording app");
-                }
-
-                if (mAudioRecordingApps.isEmpty()) {
-                    showAudioRecordingDisclosureBar();
-                }
-
-                mAudioRecordingApps.add(packageName);
-                addToAudioRecordingDisclosureBar(packageName);
+                onStartedRecording(packageName);
             } else {
-                if (DEBUG) {
-                    Log.d(TAG, "\t- not recording any more");
-                }
-
-                final int index = mAudioRecordingApps.indexOf(packageName);
-                removeFromAudioRecordingDisclosureBar(index);
-                mAudioRecordingApps.remove(index);
-
-                if (mAudioRecordingApps.isEmpty()) {
-                    hideAudioRecordingDisclosureBar();
-                }
+                onDoneRecording(packageName);
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
index fd99ef3..286b7c0 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
@@ -71,6 +71,7 @@
 
         final AlertController.AlertParams ap = mAlertParams;
         ap.mTitle = appName;
+        boolean useRecordWarning = false;
         if (mDevice == null) {
             ap.mMessage = getString(R.string.usb_accessory_confirm_prompt, appName,
                     mAccessory.getDescription());
@@ -83,7 +84,7 @@
                             packageName)
                             == android.content.pm.PackageManager.PERMISSION_GRANTED;
             boolean isAudioCaptureDevice = mDevice.getHasAudioCapture();
-            boolean useRecordWarning = isAudioCaptureDevice && !hasRecordPermission;
+            useRecordWarning = isAudioCaptureDevice && !hasRecordPermission;
 
             int strID = useRecordWarning
                     ? R.string.usb_device_confirm_prompt_warn
@@ -98,22 +99,23 @@
         ap.mNegativeButtonListener = this;
 
         // add "always use" checkbox
-        LayoutInflater inflater = (LayoutInflater)getSystemService(
-                Context.LAYOUT_INFLATER_SERVICE);
-        ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
-        mAlwaysUse = (CheckBox)ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
-        if (mDevice == null) {
-            mAlwaysUse.setText(getString(R.string.always_use_accessory, appName,
-                    mAccessory.getDescription()));
-        } else {
-            mAlwaysUse.setText(getString(R.string.always_use_device, appName,
-                    mDevice.getProductName()));
+        if (!useRecordWarning) {
+            LayoutInflater inflater = (LayoutInflater) getSystemService(
+                    Context.LAYOUT_INFLATER_SERVICE);
+            ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
+            mAlwaysUse = (CheckBox) ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
+            if (mDevice == null) {
+                mAlwaysUse.setText(getString(R.string.always_use_accessory, appName,
+                        mAccessory.getDescription()));
+            } else {
+                mAlwaysUse.setText(getString(R.string.always_use_device, appName,
+                        mDevice.getProductName()));
+            }
+            mAlwaysUse.setOnCheckedChangeListener(this);
+            mClearDefaultHint = (TextView) ap.mView.findViewById(
+                    com.android.internal.R.id.clearDefaultHint);
+            mClearDefaultHint.setVisibility(View.GONE);
         }
-        mAlwaysUse.setOnCheckedChangeListener(this);
-        mClearDefaultHint = (TextView)ap.mView.findViewById(
-                                                    com.android.internal.R.id.clearDefaultHint);
-        mClearDefaultHint.setVisibility(View.GONE);
-
         setupAlert();
 
     }
@@ -133,7 +135,7 @@
                 IUsbManager service = IUsbManager.Stub.asInterface(b);
                 final int uid = mResolveInfo.activityInfo.applicationInfo.uid;
                 final int userId = UserHandle.myUserId();
-                boolean alwaysUse = mAlwaysUse.isChecked();
+                boolean alwaysUse = mAlwaysUse != null ? mAlwaysUse.isChecked() : false;
                 Intent intent = null;
 
                 if (mDevice != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
new file mode 100644
index 0000000..24f49ff
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
@@ -0,0 +1,88 @@
+/*
+ * 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.systemui.util.concurrency;
+
+import android.content.Context;
+import android.os.Handler;
+
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.BgHandler;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dagger.qualifiers.MainHandler;
+
+import java.util.concurrent.Executor;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Dagger Module for classes found within the concurrent package.
+ */
+@Module
+public abstract class ConcurrencyModule {
+    /**
+     * Provide a Background-Thread Executor by default.
+     */
+    @Provides
+    public static Executor provideExecutor(@BgHandler Handler handler) {
+        return new ExecutorImpl(handler);
+    }
+
+    /**
+     * Provide a Background-Thread Executor.
+     */
+    @Provides
+    @Background
+    public static Executor provideBackgroundExecutor(@BgHandler Handler handler) {
+        return new ExecutorImpl(handler);
+    }
+
+    /**
+     * Provide a Main-Thread Executor.
+     */
+    @Provides
+    @Main
+    public static Executor provideMainExecutor(Context context) {
+        return context.getMainExecutor();
+    }
+
+    /**
+     * Provide a Background-Thread Executor by default.
+     */
+    @Provides
+    public static DelayableExecutor provideDelayableExecutor(@BgHandler Handler handler) {
+        return new ExecutorImpl(handler);
+    }
+
+    /**
+     * Provide a Background-Thread Executor.
+     */
+    @Provides
+    @Background
+    public static DelayableExecutor provideBackgroundDelayableExecutor(@BgHandler Handler handler) {
+        return new ExecutorImpl(handler);
+    }
+
+    /**
+     * Provide a Main-Thread Executor.
+     */
+    @Provides
+    @Main
+    public static DelayableExecutor provideMainDelayableExecutor(@MainHandler Handler handler) {
+        return new ExecutorImpl(handler);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/DelayableExecutor.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/DelayableExecutor.java
new file mode 100644
index 0000000..ac15e2d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/DelayableExecutor.java
@@ -0,0 +1,65 @@
+/*
+ * 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.systemui.util.concurrency;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A sub-class of {@link Executor} that allows Runnables to be delayed and/or cancelled.
+ */
+public interface DelayableExecutor extends Executor {
+    /**
+     * Execute supplied Runnable on the Executors thread after a specified delay.
+     *
+     * See {@link android.os.Handler#postDelayed(Runnable, long)}.
+     *
+     * @return A Runnable that, when run, removes the supplied argument from the Executor queue.
+     */
+    default Runnable executeDelayed(Runnable r, long delayMillis) {
+        return executeDelayed(r, delayMillis, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Execute supplied Runnable on the Executors thread after a specified delay.
+     *
+     * See {@link android.os.Handler#postDelayed(Runnable, long)}.
+     *
+     * @return A Runnable that, when run, removes the supplied argument from the Executor queue..
+     */
+    Runnable executeDelayed(Runnable r, long delay, TimeUnit unit);
+
+    /**
+     * Execute supplied Runnable on the Executors thread at a specified uptime.
+     *
+     * See {@link android.os.Handler#postAtTime(Runnable, long)}.
+     *
+     * @return A Runnable that, when run, removes the supplied argument from the Executor queue.
+     */
+    default Runnable executeAtTime(Runnable r, long uptime) {
+        return executeAtTime(r, uptime, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Execute supplied Runnable on the Executors thread at a specified uptime.
+     *
+     * See {@link android.os.Handler#postAtTime(Runnable, long)}.
+     *
+     * @return A Runnable that, when run, removes the supplied argument from the Executor queue.
+     */
+    Runnable executeAtTime(Runnable r, long uptimeMillis, TimeUnit unit);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/ExecutorImpl.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/ExecutorImpl.java
new file mode 100644
index 0000000..7e77321
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/ExecutorImpl.java
@@ -0,0 +1,53 @@
+/*
+ * 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.systemui.util.concurrency;
+
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.Message;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Implementations of {@link DelayableExecutor} for SystemUI.
+ */
+public class ExecutorImpl extends HandlerExecutor implements DelayableExecutor {
+    private final Handler mHandler;
+
+    public ExecutorImpl(Handler handler) {
+        super(handler);
+        mHandler = handler;
+    }
+
+    @Override
+    public Runnable executeDelayed(Runnable r, long delay, TimeUnit unit) {
+        Object token = new Object();
+        Message m = mHandler.obtainMessage(0, token);
+        mHandler.sendMessageDelayed(m, unit.toMillis(delay));
+
+        return () -> mHandler.removeCallbacksAndMessages(token);
+    }
+
+    @Override
+    public Runnable executeAtTime(Runnable r, long uptimeMillis, TimeUnit unit) {
+        Object token = new Object();
+        Message m = mHandler.obtainMessage(0, token);
+        mHandler.sendMessageAtTime(m, unit.toMillis(uptimeMillis));
+
+        return () -> mHandler.removeCallbacksAndMessages(token);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ConfigurableTexts.java b/packages/SystemUI/src/com/android/systemui/volume/ConfigurableTexts.java
index 20de5bb..f1b9590 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ConfigurableTexts.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ConfigurableTexts.java
@@ -43,6 +43,9 @@
 
     public int add(final TextView text, final int labelResId) {
         if (text == null) return 0;
+        if (mTexts.containsKey(text)) {
+            return mTexts.get(text);
+        }
         final Resources res = mContext.getResources();
         final float fontScale = res.getConfiguration().fontScale;
         final float density = res.getDisplayMetrics().density;
@@ -63,6 +66,11 @@
         return sp;
     }
 
+    public void remove(final TextView text) {
+        mTexts.remove(text);
+        mTextLabels.remove(text);
+    }
+
     public void update() {
         if (mTexts.isEmpty()) return;
         mTexts.keyAt(0).post(mUpdateAll);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Events.java b/packages/SystemUI/src/com/android/systemui/volume/Events.java
index 9bbfd22..5ed8b8f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/Events.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/Events.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.volume;
 
-import android.content.Context;
 import android.media.AudioManager;
 import android.media.AudioSystem;
 import android.provider.Settings.Global;
@@ -125,7 +124,12 @@
 
     public static Callback sCallback;
 
-    public static void writeEvent(Context context, int tag, Object... list) {
+    /**
+     * Logs an event to the system log and the event log.
+     * @param tag One of the EVENT_* codes above.
+     * @param list Any additional event-specific arguments, documented above.
+     */
+    public static void writeEvent(int tag, Object... list) {
         MetricsLogger logger = new MetricsLogger();
         final long time = System.currentTimeMillis();
         final StringBuilder sb = new StringBuilder("writeEvent ").append(EVENT_TAGS[tag]);
@@ -133,33 +137,33 @@
             sb.append(" ");
             switch (tag) {
                 case EVENT_SHOW_DIALOG:
-                    MetricsLogger.visible(context, MetricsEvent.VOLUME_DIALOG);
-                    MetricsLogger.histogram(context, "volume_from_keyguard",
+                    logger.visible(MetricsEvent.VOLUME_DIALOG);
+                    logger.histogram("volume_from_keyguard",
                             (Boolean) list[1] ? 1 : 0);
                     sb.append(SHOW_REASONS[(Integer) list[0]]).append(" keyguard=").append(list[1]);
                     break;
                 case EVENT_EXPAND:
-                    MetricsLogger.visibility(context, MetricsEvent.VOLUME_DIALOG_DETAILS,
+                    logger.visibility(MetricsEvent.VOLUME_DIALOG_DETAILS,
                             (Boolean) list[0]);
                     sb.append(list[0]);
                     break;
                 case EVENT_DISMISS_DIALOG:
-                    MetricsLogger.hidden(context, MetricsEvent.VOLUME_DIALOG);
+                    logger.hidden(MetricsEvent.VOLUME_DIALOG);
                     sb.append(DISMISS_REASONS[(Integer) list[0]]);
                     break;
                 case EVENT_ACTIVE_STREAM_CHANGED:
-                    MetricsLogger.action(context, MetricsEvent.ACTION_VOLUME_STREAM,
+                    logger.action(MetricsEvent.ACTION_VOLUME_STREAM,
                             (Integer) list[0]);
                     sb.append(AudioSystem.streamToString((Integer) list[0]));
                     break;
                 case EVENT_ICON_CLICK:
-                    MetricsLogger.action(context, MetricsEvent.ACTION_VOLUME_ICON,
+                    logger.action(MetricsEvent.ACTION_VOLUME_ICON,
                             (Integer) list[0]);
                     sb.append(AudioSystem.streamToString((Integer) list[0])).append(' ')
                             .append(iconStateToString((Integer) list[1]));
                     break;
                 case EVENT_TOUCH_LEVEL_DONE:
-                    MetricsLogger.action(context, MetricsEvent.ACTION_VOLUME_SLIDER,
+                    logger.action(MetricsEvent.ACTION_VOLUME_SLIDER,
                             (Integer) list[1]);
                     // fall through
                 case EVENT_TOUCH_LEVEL_CHANGED:
@@ -169,7 +173,7 @@
                             .append(list[1]);
                     break;
                 case EVENT_KEY:
-                    MetricsLogger.action(context, MetricsEvent.ACTION_VOLUME_KEY,
+                    logger.action(MetricsEvent.ACTION_VOLUME_KEY,
                             (Integer) list[0]);
                     sb.append(AudioSystem.streamToString((Integer) list[0])).append(' ')
                             .append(list[1]);
@@ -181,7 +185,7 @@
                     logger.action(MetricsEvent.ACTION_VOLUME_SETTINGS);
                     break;
                 case EVENT_EXTERNAL_RINGER_MODE_CHANGED:
-                    MetricsLogger.action(context, MetricsEvent.ACTION_RINGER_MODE,
+                    logger.action(MetricsEvent.ACTION_RINGER_MODE,
                             (Integer) list[0]);
                     // fall through
                 case EVENT_INTERNAL_RINGER_MODE_CHANGED:
@@ -194,14 +198,14 @@
                     sb.append(list[0]).append(' ').append(list[1]);
                     break;
                 case EVENT_SHOW_USB_OVERHEAT_ALARM:
-                    MetricsLogger.visible(context, MetricsEvent.POWER_OVERHEAT_ALARM);
-                    MetricsLogger.histogram(context, "show_usb_overheat_alarm",
+                    logger.visible(MetricsEvent.POWER_OVERHEAT_ALARM);
+                    logger.histogram("show_usb_overheat_alarm",
                             (Boolean) list[1] ? 1 : 0);
                     sb.append(SHOW_REASONS[(Integer) list[0]]).append(" keyguard=").append(list[1]);
                     break;
                 case EVENT_DISMISS_USB_OVERHEAT_ALARM:
-                    MetricsLogger.hidden(context, MetricsEvent.POWER_OVERHEAT_ALARM);
-                    MetricsLogger.histogram(context, "dismiss_usb_overheat_alarm",
+                    logger.hidden(MetricsEvent.POWER_OVERHEAT_ALARM);
+                    logger.histogram("dismiss_usb_overheat_alarm",
                             (Boolean) list[1] ? 1 : 0);
                     sb.append(DISMISS_REASONS[(Integer) list[0]])
                         .append(" keyguard=").append(list[1]);
@@ -255,4 +259,5 @@
         void writeEvent(long time, int tag, Object[] list);
         void writeState(long time, State state);
     }
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 02c699f..a4ed31d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -150,7 +150,7 @@
         mStatusBarOptionalLazy = statusBarOptionalLazy;
         mNotificationManager = (NotificationManager) mContext.getSystemService(
                 Context.NOTIFICATION_SERVICE);
-        Events.writeEvent(mContext, Events.EVENT_COLLECTION_STARTED);
+        Events.writeEvent(Events.EVENT_COLLECTION_STARTED);
         mWorkerThread = new HandlerThread(VolumeDialogControllerImpl.class.getSimpleName());
         mWorkerThread.start();
         mWorker = new W(mWorkerThread.getLooper());
@@ -237,7 +237,7 @@
         if (D.BUG) Log.d(TAG, "destroy");
         if (mDestroyed) return;
         mDestroyed = true;
-        Events.writeEvent(mContext, Events.EVENT_COLLECTION_STOPPED);
+        Events.writeEvent(Events.EVENT_COLLECTION_STOPPED);
         mMediaSessions.destroy();
         mObserver.destroy();
         mReceiver.destroy();
@@ -487,7 +487,7 @@
             mCallbacks.onShowSilentHint();
         }
         if (changed && fromKey) {
-            Events.writeEvent(mContext, Events.EVENT_KEY, stream, lastAudibleStreamVolume);
+            Events.writeEvent(Events.EVENT_KEY, stream, lastAudibleStreamVolume);
         }
         return changed;
     }
@@ -495,7 +495,7 @@
     private boolean updateActiveStreamW(int activeStream) {
         if (activeStream == mState.activeStream) return false;
         mState.activeStream = activeStream;
-        Events.writeEvent(mContext, Events.EVENT_ACTIVE_STREAM_CHANGED, activeStream);
+        Events.writeEvent(Events.EVENT_ACTIVE_STREAM_CHANGED, activeStream);
         if (D.BUG) Log.d(TAG, "updateActiveStreamW " + activeStream);
         final int s = activeStream < DYNAMIC_STREAM_START_INDEX ? activeStream : -1;
         if (D.BUG) Log.d(TAG, "forceVolumeControlStream " + s);
@@ -544,7 +544,7 @@
         if (ss.level == level) return false;
         ss.level = level;
         if (isLogWorthy(stream)) {
-            Events.writeEvent(mContext, Events.EVENT_LEVEL_CHANGED, stream, level);
+            Events.writeEvent(Events.EVENT_LEVEL_CHANGED, stream, level);
         }
         return true;
     }
@@ -567,7 +567,7 @@
         if (ss.muted == muted) return false;
         ss.muted = muted;
         if (isLogWorthy(stream)) {
-            Events.writeEvent(mContext, Events.EVENT_MUTE_CHANGED, stream, muted);
+            Events.writeEvent(Events.EVENT_MUTE_CHANGED, stream, muted);
         }
         if (muted && isRinger(stream)) {
             updateRingerModeInternalW(mAudio.getRingerModeInternal());
@@ -583,7 +583,7 @@
         if (Objects.equals(mState.effectsSuppressor, effectsSuppressor)) return false;
         mState.effectsSuppressor = effectsSuppressor;
         mState.effectsSuppressorName = getApplicationName(mContext, mState.effectsSuppressor);
-        Events.writeEvent(mContext, Events.EVENT_SUPPRESSOR_CHANGED, mState.effectsSuppressor,
+        Events.writeEvent(Events.EVENT_SUPPRESSOR_CHANGED, mState.effectsSuppressor,
                 mState.effectsSuppressorName);
         return true;
     }
@@ -607,7 +607,7 @@
                 Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
         if (mState.zenMode == zen) return false;
         mState.zenMode = zen;
-        Events.writeEvent(mContext, Events.EVENT_ZEN_MODE_CHANGED, zen);
+        Events.writeEvent(Events.EVENT_ZEN_MODE_CHANGED, zen);
         return true;
     }
 
@@ -633,23 +633,23 @@
         mState.disallowMedia = disallowMedia;
         mState.disallowSystem = disallowSystem;
         mState.disallowRinger = disallowRinger;
-        Events.writeEvent(mContext, Events.EVENT_ZEN_CONFIG_CHANGED, "disallowAlarms=" +
-                disallowAlarms + " disallowMedia=" + disallowMedia + " disallowSystem=" +
-                disallowSystem + " disallowRinger=" + disallowRinger);
+        Events.writeEvent(Events.EVENT_ZEN_CONFIG_CHANGED, "disallowAlarms="
+                + disallowAlarms + " disallowMedia=" + disallowMedia + " disallowSystem="
+                + disallowSystem + " disallowRinger=" + disallowRinger);
         return true;
     }
 
     private boolean updateRingerModeExternalW(int rm) {
         if (rm == mState.ringerModeExternal) return false;
         mState.ringerModeExternal = rm;
-        Events.writeEvent(mContext, Events.EVENT_EXTERNAL_RINGER_MODE_CHANGED, rm);
+        Events.writeEvent(Events.EVENT_EXTERNAL_RINGER_MODE_CHANGED, rm);
         return true;
     }
 
     private boolean updateRingerModeInternalW(int rm) {
         if (rm == mState.ringerModeInternal) return false;
         mState.ringerModeInternal = rm;
-        Events.writeEvent(mContext, Events.EVENT_INTERNAL_RINGER_MODE_CHANGED, rm);
+        Events.writeEvent(Events.EVENT_INTERNAL_RINGER_MODE_CHANGED, rm);
 
         if (mState.ringerModeInternal == RINGER_MODE_NORMAL) {
             playTouchFeedback();
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 24d6c4c..f5c1587 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -429,7 +429,7 @@
         row.icon.setImageResource(iconRes);
         if (row.stream != AudioSystem.STREAM_ACCESSIBILITY) {
             row.icon.setOnClickListener(v -> {
-                Events.writeEvent(mContext, Events.EVENT_ICON_CLICK, row.stream, row.iconState);
+                Events.writeEvent(Events.EVENT_ICON_CLICK, row.stream, row.iconState);
                 mController.setActiveStream(row.stream);
                 if (row.stream == AudioManager.STREAM_RING) {
                     final boolean hasVibrator = mController.hasVibrator();
@@ -468,7 +468,7 @@
         }
         if (mSettingsIcon != null) {
             mSettingsIcon.setOnClickListener(v -> {
-                Events.writeEvent(mContext, Events.EVENT_SETTINGS_CLICK);
+                Events.writeEvent(Events.EVENT_SETTINGS_CLICK);
                 Intent intent = new Intent(Settings.Panel.ACTION_VOLUME);
                 dismissH(DISMISS_REASON_SETTINGS_CLICKED);
                 Dependency.get(ActivityStarter.class).startActivity(intent,
@@ -504,7 +504,7 @@
                         mController.setStreamVolume(AudioManager.STREAM_RING, 1);
                     }
                 }
-                Events.writeEvent(mContext, Events.EVENT_RINGER_TOGGLE, newRingerMode);
+                Events.writeEvent(Events.EVENT_RINGER_TOGGLE, newRingerMode);
                 incrementManualToggleCount();
                 updateRingerH();
                 provideTouchFeedbackH(newRingerMode);
@@ -519,7 +519,7 @@
         if (mODICaptionsIcon != null) {
             mODICaptionsIcon.setOnConfirmedTapListener(() -> {
                 onCaptionIconClicked();
-                Events.writeEvent(mContext, Events.EVENT_ODI_CAPTIONS_CLICK);
+                Events.writeEvent(Events.EVENT_ODI_CAPTIONS_CLICK);
             }, mHandler);
         }
 
@@ -541,7 +541,7 @@
             mODICaptionsTooltipView = mODICaptionsTooltipViewStub.inflate();
             mODICaptionsTooltipView.findViewById(R.id.dismiss).setOnClickListener(v -> {
                 hideCaptionsTooltip();
-                Events.writeEvent(mContext, Events.EVENT_ODI_CAPTIONS_TOOLTIP_CLICK);
+                Events.writeEvent(Events.EVENT_ODI_CAPTIONS_TOOLTIP_CLICK);
             });
             mODICaptionsTooltipViewStub = null;
             rescheduleTimeoutH();
@@ -694,7 +694,7 @@
         initSettingsH();
         mShowing = true;
         mDialog.show();
-        Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked());
+        Events.writeEvent(Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked());
         mController.notifyVisible(true);
         mController.getCaptionsComponentState(false);
         checkODICaptionsTooltip(false);
@@ -741,7 +741,7 @@
         if (mShowing) {
             mShowing = false;
             // Only logs when the volume dialog visibility is changed.
-            Events.writeEvent(mContext, Events.EVENT_DISMISS_DIALOG, reason);
+            Events.writeEvent(Events.EVENT_DISMISS_DIALOG, reason);
         }
         mDialogView.setTranslationX(0);
         mDialogView.setAlpha(1);
@@ -922,6 +922,7 @@
             if (!mDynamic.get(row.stream)) {
                 mRows.remove(i);
                 mDialogRowsView.removeView(row.view);
+                mConfigurableTexts.remove(row.header);
             }
         }
     }
@@ -1400,7 +1401,7 @@
                     mController.setActiveStream(mRow.stream);
                     mController.setStreamVolume(mRow.stream, userLevel);
                     mRow.requestedLevel = userLevel;
-                    Events.writeEvent(mContext, Events.EVENT_TOUCH_LEVEL_CHANGED, mRow.stream,
+                    Events.writeEvent(Events.EVENT_TOUCH_LEVEL_CHANGED, mRow.stream,
                             userLevel);
                 }
             }
@@ -1419,7 +1420,7 @@
             mRow.tracking = false;
             mRow.userAttempt = SystemClock.uptimeMillis();
             final int userLevel = getImpliedLevel(seekBar, seekBar.getProgress());
-            Events.writeEvent(mContext, Events.EVENT_TOUCH_LEVEL_DONE, mRow.stream, userLevel);
+            Events.writeEvent(Events.EVENT_TOUCH_LEVEL_DONE, mRow.stream, userLevel);
             if (mRow.ss.level != userLevel) {
                 mHandler.sendMessageDelayed(mHandler.obtainMessage(H.RECHECK, mRow),
                         USER_ATTEMPT_GRACE_PERIOD);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
index 0990e22..4cb5472 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
@@ -49,6 +49,7 @@
 import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 import junit.framework.Assert;
@@ -70,6 +71,7 @@
     @Mock private NotificationEntryManager mEntryManager;
     @Mock private AppOpsController mAppOpsController;
     @Mock private Handler mMainHandler;
+    @Mock private NotifCollection mNotifCollection;
 
     @Before
     public void setUp() throws Exception {
@@ -79,7 +81,7 @@
         MockitoAnnotations.initMocks(this);
         mFsc = new ForegroundServiceController(mEntryManager, mAppOpsController, mMainHandler);
         mListener = new ForegroundServiceNotificationListener(
-                mContext, mFsc, mEntryManager);
+                mContext, mFsc, mEntryManager, mNotifCollection);
         ArgumentCaptor<NotificationEntryListener> entryListenerCaptor =
                 ArgumentCaptor.forClass(NotificationEntryListener.class);
         verify(mEntryManager).addNotificationEntryListener(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
index ead14e5..42fbf59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
@@ -93,7 +93,7 @@
         // These should be valid filters
         `when`(intentFilter.countActions()).thenReturn(1)
         `when`(intentFilterOther.countActions()).thenReturn(1)
-        `when`(mockContext.user).thenReturn(user0)
+        setUserMock(mockContext, user0)
     }
 
     @Test
@@ -140,6 +140,18 @@
         verify(mockUBRUser1, never()).unregisterReceiver(broadcastReceiver)
     }
 
+    @Test
+    fun testRegisterCurrentAsActualUser() {
+        setUserMock(mockContext, user1)
+        broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, mockHandler,
+                UserHandle.CURRENT)
+
+        testableLooper.processAllMessages()
+
+        verify(mockUBRUser1).registerReceiver(capture(argumentCaptor))
+        assertSame(broadcastReceiver, argumentCaptor.value.receiver)
+    }
+
     @Test(expected = IllegalArgumentException::class)
     fun testFilterMustContainActions() {
         val testFilter = IntentFilter()
@@ -178,6 +190,19 @@
         broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
     }
 
+    @Test(expected = IllegalArgumentException::class)
+    fun testFilterMustNotSetPriority() {
+        val testFilter = IntentFilter(TEST_ACTION).apply {
+            priority = IntentFilter.SYSTEM_HIGH_PRIORITY
+        }
+        broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
+    }
+
+    private fun setUserMock(mockContext: Context, user: UserHandle) {
+        `when`(mockContext.user).thenReturn(user)
+        `when`(mockContext.userId).thenReturn(user.identifier)
+    }
+
     private class TestBroadcastDispatcher(
         context: Context,
         mainHandler: Handler,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 8c9f759..e0d31d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -82,6 +82,7 @@
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.policy.RemoteInputUriController;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.util.InjectionInflationController;
 
@@ -153,13 +154,20 @@
     private Resources mResources;
     @Mock
     private Lazy<ShadeController> mShadeController;
+    @Mock
+    private RemoteInputUriController mRemoteInputUriController;
 
     private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
     private BubbleData mBubbleData;
 
+    private TestableLooper mTestableLooper;
+
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
+
+        mTestableLooper = TestableLooper.get(this);
+
         mContext.addMockSystemService(FaceManager.class, mFaceManager);
         when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
 
@@ -207,7 +215,8 @@
                 mZenModeController,
                 mLockscreenUserManager,
                 mNotificationGroupManager,
-                mNotificationEntryManager);
+                mNotificationEntryManager,
+                mRemoteInputUriController);
         mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
         mBubbleController.setExpandListener(mBubbleExpandListener);
 
@@ -262,7 +271,7 @@
                 mRow.getEntry().getKey()));
 
         // Make it look like dismissed notif
-        mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).setShowInShadeWhenBubble(false);
+        mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).setShowInShade(false);
 
         // Now remove the bubble
         mBubbleController.removeBubble(
@@ -346,14 +355,14 @@
         verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
 
         // Last added is the one that is expanded
-        assertEquals(mRow2.getEntry(), stackView.getExpandedBubbleView().getEntry());
+        assertEquals(mRow2.getEntry(), mBubbleData.getSelectedBubble().getEntry());
         assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow2.getEntry().getKey()));
 
         // Switch which bubble is expanded
         mBubbleController.selectBubble(mRow.getEntry().getKey());
         stackView.setExpandedBubble(mRow.getEntry().getKey());
-        assertEquals(mRow.getEntry(), stackView.getExpandedBubbleView().getEntry());
+        assertEquals(mRow.getEntry(), stackView.getExpandedBubble().getEntry());
         assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow.getEntry().getKey()));
 
@@ -377,7 +386,9 @@
         assertTrue(mBubbleController.hasBubbles());
         assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow.getEntry().getKey()));
-        assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showBubbleDot());
+
+        mTestableLooper.processAllMessages();
+        assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
 
         // Expand
         mBubbleController.expandStack();
@@ -388,7 +399,7 @@
         assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow.getEntry().getKey()));
         // Notif shouldn't show dot after expansion
-        assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showBubbleDot());
+        assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
     }
 
     @Test
@@ -401,10 +412,11 @@
         assertTrue(mBubbleController.hasBubbles());
         assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow.getEntry().getKey()));
-        assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showBubbleDot());
+
+        mTestableLooper.processAllMessages();
+        assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
 
         // Expand
-        BubbleStackView stackView = mBubbleController.getStackView();
         mBubbleController.expandStack();
         assertTrue(mBubbleController.isStackExpanded());
         verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
@@ -413,7 +425,7 @@
         assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow.getEntry().getKey()));
         // Notif shouldn't show dot after expansion
-        assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showBubbleDot());
+        assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
 
         // Send update
         mEntryListener.onPreEntryUpdated(mRow.getEntry());
@@ -423,7 +435,7 @@
         assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow.getEntry().getKey()));
         // Notif shouldn't show dot after expansion
-        assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showBubbleDot());
+        assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
     }
 
     @Test
@@ -443,7 +455,7 @@
         verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
 
         // Last added is the one that is expanded
-        assertEquals(mRow2.getEntry(), stackView.getExpandedBubbleView().getEntry());
+        assertEquals(mRow2.getEntry(), stackView.getExpandedBubble().getEntry());
         assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow2.getEntry().getKey()));
 
@@ -453,7 +465,7 @@
         verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
 
         // Make sure first bubble is selected
-        assertEquals(mRow.getEntry(), stackView.getExpandedBubbleView().getEntry());
+        assertEquals(mRow.getEntry(), stackView.getExpandedBubble().getEntry());
         verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
 
         // Dismiss that one
@@ -467,7 +479,7 @@
     }
 
     @Test
-    public void testAutoExpand_FailsNotForeground() {
+    public void testAutoExpand_fails_noFlag() {
         assertFalse(mBubbleController.isStackExpanded());
         setMetadataFlags(mRow.getEntry(),
                 Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, false /* enableFlag */);
@@ -486,7 +498,7 @@
     }
 
     @Test
-    public void testAutoExpand_SucceedsForeground() {
+    public void testAutoExpand_succeeds_withFlag() {
         setMetadataFlags(mRow.getEntry(),
                 Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, true /* enableFlag */);
 
@@ -504,23 +516,7 @@
     }
 
     @Test
-    public void testSuppressNotif_FailsNotForeground() {
-        setMetadataFlags(mRow.getEntry(),
-                Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, false /* enableFlag */);
-
-        // Add the suppress notif bubble
-        mEntryListener.onPendingEntryAdded(mRow.getEntry());
-        mBubbleController.updateBubble(mRow.getEntry());
-
-        // Should not be suppressed because we weren't forground
-        assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
-                mRow.getEntry().getKey()));
-        // # of bubbles should change
-        verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
-    }
-
-    @Test
-    public void testSuppressNotif_SucceedsForeground() {
+    public void testSuppressNotif_onInitialNotif() {
         setMetadataFlags(mRow.getEntry(),
                 Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */);
 
@@ -531,12 +527,42 @@
         // Notif should be suppressed because we were foreground
         assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow.getEntry().getKey()));
+        // Dot + flyout is hidden because notif is suppressed
+        assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+        assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showFlyout());
 
         // # of bubbles should change
         verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
     }
 
     @Test
+    public void testSuppressNotif_onUpdateNotif() {
+        mBubbleController.updateBubble(mRow.getEntry());
+
+        // Should not be suppressed
+        assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
+                mRow.getEntry().getKey()));
+        // Should show dot
+        assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+
+        // Update to suppress notif
+        setMetadataFlags(mRow.getEntry(),
+                Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */);
+        mBubbleController.updateBubble(mRow.getEntry());
+
+        // Notif should be suppressed
+        assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
+                mRow.getEntry().getKey()));
+        // Dot + flyout is hidden because notif is suppressed
+        assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
+        assertFalse(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showFlyout());
+
+        // # of bubbles should change
+        verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
+    }
+
+
+    @Test
     public void testExpandStackAndSelectBubble_removedFirst() {
         final String key = mRow.getEntry().getKey();
 
@@ -555,7 +581,9 @@
         mEntryListener.onPendingEntryAdded(mRow.getEntry());
         assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow.getEntry().getKey()));
-        assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showBubbleDot());
+
+        mTestableLooper.processAllMessages();
+        assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
     }
 
     @Test
@@ -698,11 +726,13 @@
                 ZenModeController zenModeController,
                 NotificationLockscreenUserManager lockscreenUserManager,
                 NotificationGroupManager groupManager,
-                NotificationEntryManager entryManager) {
+                NotificationEntryManager entryManager,
+                RemoteInputUriController remoteInputUriController) {
             super(context,
                     statusBarWindowController, statusBarStateController, shadeController,
                     data, Runnable::run, configurationController, interruptionStateProvider,
-                    zenModeController, lockscreenUserManager, groupManager, entryManager);
+                    zenModeController, lockscreenUserManager, groupManager, entryManager,
+                    remoteInputUriController);
         }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
index a9be30b..1554abc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
@@ -42,6 +42,7 @@
 import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.NotificationTestHelper;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 
 import com.google.common.collect.ImmutableList;
 
@@ -119,7 +120,9 @@
                 .setVisuallyInterruptive(true)
                 .build();
 
+        ExpandableNotificationRow row = mNotificationTestHelper.createBubble();
         mEntryDismissed = createBubbleEntry(1, "dismissed", "package.d");
+        mEntryDismissed.setRow(row);
 
         mBubbleA1 = new Bubble(mContext, mEntryA1);
         mBubbleA2 = new Bubble(mContext, mEntryA2);
@@ -183,7 +186,7 @@
         // Verify
         verifyUpdateReceived();
         BubbleData.Update update = mUpdateCaptor.getValue();
-        assertThat(update.addedBubble.showFlyoutForBubble()).isFalse();
+        assertThat(update.addedBubble.showFlyout()).isFalse();
     }
 
     @Test
@@ -192,14 +195,13 @@
         mBubbleData.setListener(mListener);
 
         // Test
-        mBubbleData.notificationEntryUpdated(mEntryInterruptive, /* suppressFlyout */
-                false, /* showInShade */
-                true);
+        mBubbleData.notificationEntryUpdated(mEntryInterruptive,
+                false /* suppressFlyout */, true  /* showInShade */);
 
         // Verify
         verifyUpdateReceived();
         BubbleData.Update update = mUpdateCaptor.getValue();
-        assertThat(update.addedBubble.showFlyoutForBubble()).isTrue();
+        assertThat(update.addedBubble.showFlyout()).isTrue();
     }
 
     @Test
@@ -208,38 +210,40 @@
         mBubbleData.setListener(mListener);
 
         // Test
-        mBubbleData.notificationEntryUpdated(mEntryC1, /* suppressFlyout */ false, /* showInShade */
-                true);
+        mBubbleData.notificationEntryUpdated(mEntryC1, false /* suppressFlyout */,
+                true /* showInShade */);
         verifyUpdateReceived();
 
-        mBubbleData.notificationEntryUpdated(mEntryC1, /* suppressFlyout */ false, /* showInShade */
-                true);
+        mBubbleData.notificationEntryUpdated(mEntryC1, false /* suppressFlyout */,
+                true /* showInShade */);
         verifyUpdateReceived();
 
         // Verify
         BubbleData.Update update = mUpdateCaptor.getValue();
-        assertThat(update.updatedBubble.showFlyoutForBubble()).isFalse();
+        assertThat(update.updatedBubble.showFlyout()).isFalse();
     }
 
     @Test
     public void sameUpdate_NotInShade_showFlyout() {
         // Setup
         mBubbleData.setListener(mListener);
-        setMetadataFlags(mEntryDismissed,
-                Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, /* enableFlag */ true);
 
         // Test
-        mBubbleData.notificationEntryUpdated(mEntryDismissed, /* suppressFlyout */ false,
-                /* showInShade */ false);
+        mBubbleData.notificationEntryUpdated(mEntryDismissed, false /* suppressFlyout */,
+                false /* showInShade */);
         verifyUpdateReceived();
 
-        mBubbleData.notificationEntryUpdated(mEntryDismissed, /* suppressFlyout */
-                false, /* showInShade */ false);
+        // Make it look like user swiped away row
+        mEntryDismissed.getRow().dismiss(false /* refocusOnDismiss */);
+        assertThat(mBubbleData.getBubbleWithKey(mEntryDismissed.getKey()).showInShade()).isFalse();
+
+        mBubbleData.notificationEntryUpdated(mEntryDismissed, false /* suppressFlyout */,
+                false /* showInShade */);
         verifyUpdateReceived();
 
         // Verify
         BubbleData.Update update = mUpdateCaptor.getValue();
-        assertThat(update.updatedBubble.showFlyoutForBubble()).isTrue();
+        assertThat(update.updatedBubble.showFlyout()).isTrue();
     }
 
     // COLLAPSED / ADD
@@ -936,23 +940,6 @@
     }
 
     /**
-     * Sets the bubble metadata flags for this entry. These flags are normally set by
-     * NotificationManagerService when the notification is sent, however, these tests do not
-     * go through that path so we set them explicitly when testing.
-     */
-    private void setMetadataFlags(NotificationEntry entry, int flag, boolean enableFlag) {
-        Notification.BubbleMetadata bubbleMetadata =
-                entry.getSbn().getNotification().getBubbleMetadata();
-        int flags = bubbleMetadata.getFlags();
-        if (enableFlag) {
-            flags |= flag;
-        } else {
-            flags &= ~flag;
-        }
-        bubbleMetadata.setFlags(flags);
-    }
-
-    /**
      * No ExpandableNotificationRow is required to test BubbleData. This setup is all that is
      * required for BubbleData functionality and verification. NotificationTestHelper is used only
      * as a convenience to create a Notification w/BubbleMetadata.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleFlyoutViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleFlyoutViewTest.java
index a8961a8..376ecf7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleFlyoutViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleFlyoutViewTest.java
@@ -60,7 +60,8 @@
     @Test
     public void testShowFlyout_isVisible() {
         mFlyout.setupFlyoutStartingAsDot(
-                "Hello", new PointF(100, 100), 500, true, Color.WHITE, null, null, mDotCenter);
+                "Hello", new PointF(100, 100), 500, true, Color.WHITE, null, null, mDotCenter,
+                false);
         mFlyout.setVisibility(View.VISIBLE);
 
         assertEquals("Hello", mFlyoutText.getText());
@@ -71,7 +72,8 @@
     public void testFlyoutHide_runsCallback() {
         Runnable after = Mockito.mock(Runnable.class);
         mFlyout.setupFlyoutStartingAsDot(
-                "Hello", new PointF(100, 100), 500, true, Color.WHITE, null, after, mDotCenter);
+                "Hello", new PointF(100, 100), 500, true, Color.WHITE, null, after, mDotCenter,
+                false);
         mFlyout.hideFlyout();
 
         verify(after).run();
@@ -80,7 +82,8 @@
     @Test
     public void testSetCollapsePercent() {
         mFlyout.setupFlyoutStartingAsDot(
-                "Hello", new PointF(100, 100), 500, true, Color.WHITE, null, null, mDotCenter);
+                "Hello", new PointF(100, 100), 500, true, Color.WHITE, null, null, mDotCenter,
+                false);
         mFlyout.setVisibility(View.VISIBLE);
 
         mFlyout.setCollapsePercent(1f);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java b/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java
index 378bba1..1e8ebea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java
@@ -48,7 +48,7 @@
 
     @Test
     public void testLogDisabled_noLogsWritten() {
-        mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, false);
+        mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, false, false);
         assertEquals(mSysuiLog.mTimeline, null);
 
         mSysuiLog.log(new Event("msg"));
@@ -57,7 +57,7 @@
 
     @Test
     public void testLogEnabled_logWritten() {
-        mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, true);
+        mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, true, false);
         assertEquals(mSysuiLog.mTimeline.size(), 0);
 
         mSysuiLog.log(new Event("msg"));
@@ -66,7 +66,7 @@
 
     @Test
     public void testMaxLogs() {
-        mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, true);
+        mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, true, false);
         assertEquals(mSysuiLog.mTimeline.size(), 0);
 
         final String msg = "msg";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index e8f19238..167f361 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -48,6 +48,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.power.PowerUI.WarningsUI;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.StatusBar;
 
 import org.junit.Before;
@@ -87,6 +88,7 @@
     private IThermalEventListener mUsbThermalEventListener;
     private IThermalEventListener mSkinThermalEventListener;
     @Mock private BroadcastDispatcher mBroadcastDispatcher;
+    @Mock private CommandQueue mCommandQueue;
     @Mock private Lazy<StatusBar> mStatusBarLazy;
     @Mock private StatusBar mStatusBar;
 
@@ -686,7 +688,7 @@
     }
 
     private void createPowerUi() {
-        mPowerUI = new PowerUI(mContext, mBroadcastDispatcher, mStatusBarLazy);
+        mPowerUI = new PowerUI(mContext, mBroadcastDispatcher, mCommandQueue, mStatusBarLazy);
         mPowerUI.mThermalService = mThermalServiceMock;
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogBuilderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogBuilderTest.kt
deleted file mode 100644
index 6302f9d..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogBuilderTest.kt
+++ /dev/null
@@ -1,77 +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.privacy
-
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.systemui.SysuiTestCase
-import org.junit.Assert.assertEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class PrivacyDialogBuilderTest : SysuiTestCase() {
-
-    companion object {
-        val TEST_UID = 1
-    }
-
-    @Test
-    fun testGenerateAppsList() {
-        val bar2 = PrivacyItem(Privacy.TYPE_CAMERA, PrivacyApplication(
-                "Bar", TEST_UID, context))
-        val bar3 = PrivacyItem(Privacy.TYPE_LOCATION, PrivacyApplication(
-                "Bar", TEST_UID, context))
-        val foo0 = PrivacyItem(Privacy.TYPE_MICROPHONE, PrivacyApplication(
-                "Foo", TEST_UID, context))
-        val baz1 = PrivacyItem(Privacy.TYPE_CAMERA, PrivacyApplication(
-                "Baz", TEST_UID, context))
-
-        val items = listOf(bar2, foo0, baz1, bar3)
-
-        val textBuilder = PrivacyDialogBuilder(context, items)
-
-        val list = textBuilder.appsAndTypes
-        assertEquals(3, list.size)
-        val appsList = list.map { it.first }
-        val typesList = list.map { it.second }
-        // List is sorted by number of types and then by types
-        assertEquals(listOf("Bar", "Baz", "Foo"), appsList.map { it.packageName })
-        assertEquals(listOf(Privacy.TYPE_CAMERA, Privacy.TYPE_LOCATION), typesList[0])
-        assertEquals(listOf(Privacy.TYPE_CAMERA), typesList[1])
-        assertEquals(listOf(Privacy.TYPE_MICROPHONE), typesList[2])
-    }
-
-    @Test
-    fun testOrder() {
-        // We want location to always go last, so it will go in the "+ other apps"
-        val appCamera = PrivacyItem(PrivacyType.TYPE_CAMERA,
-                PrivacyApplication("Camera", TEST_UID, context))
-        val appMicrophone =
-                PrivacyItem(PrivacyType.TYPE_MICROPHONE,
-                        PrivacyApplication("Microphone", TEST_UID, context))
-        val appLocation =
-                PrivacyItem(PrivacyType.TYPE_LOCATION,
-                        PrivacyApplication("Location", TEST_UID, context))
-
-        val items = listOf(appLocation, appMicrophone, appCamera)
-        val textBuilder = PrivacyDialogBuilder(context, items)
-        val appList = textBuilder.appsAndTypes.map { it.first }.map { it.packageName }
-        assertEquals(listOf("Camera", "Microphone", "Location"), appList)
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
deleted file mode 100644
index 20148e1..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
+++ /dev/null
@@ -1,315 +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.privacy
-
-import android.app.ActivityManager
-import android.app.AppOpsManager
-import android.content.Context
-import android.content.Intent
-import android.content.pm.UserInfo
-import android.os.Handler
-import android.os.UserHandle
-import android.os.UserManager
-import android.provider.DeviceConfig
-import android.provider.Settings.RESET_MODE_PACKAGE_DEFAULTS
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import android.testing.TestableLooper.RunWithLooper
-import androidx.test.filters.SmallTest
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags
-import com.android.systemui.Dependency
-import com.android.systemui.R
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.appops.AppOpItem
-import com.android.systemui.appops.AppOpsController
-import com.android.systemui.broadcast.BroadcastDispatcher
-import org.hamcrest.Matchers.hasItem
-import org.hamcrest.Matchers.not
-import org.hamcrest.Matchers.nullValue
-import org.junit.After
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertThat
-import org.junit.Assert.assertTrue
-import org.junit.Before
-import org.junit.Ignore
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
-import org.mockito.ArgumentMatchers.any
-import org.mockito.ArgumentMatchers.anyBoolean
-import org.mockito.ArgumentMatchers.anyInt
-import org.mockito.ArgumentMatchers.anyList
-import org.mockito.ArgumentMatchers.anyString
-import org.mockito.ArgumentMatchers.eq
-import org.mockito.Captor
-import org.mockito.Mock
-import org.mockito.Mockito.atLeastOnce
-import org.mockito.Mockito.doAnswer
-import org.mockito.Mockito.doReturn
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.never
-import org.mockito.Mockito.reset
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.verifyNoMoreInteractions
-import org.mockito.MockitoAnnotations
-
-@RunWith(AndroidTestingRunner::class)
-@SmallTest
-@RunWithLooper
-@Ignore
-class PrivacyItemControllerTest : SysuiTestCase() {
-
-    companion object {
-        val CURRENT_USER_ID = ActivityManager.getCurrentUser()
-        val TEST_UID = CURRENT_USER_ID * UserHandle.PER_USER_RANGE
-        const val SYSTEM_UID = 1000
-        const val TEST_PACKAGE_NAME = "test"
-        const val DEVICE_SERVICES_STRING = "Device services"
-        const val TAG = "PrivacyItemControllerTest"
-        fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
-    }
-
-    @Mock
-    private lateinit var appOpsController: AppOpsController
-    @Mock
-    private lateinit var callback: PrivacyItemController.Callback
-    @Mock
-    private lateinit var userManager: UserManager
-    @Mock
-    private lateinit var broadcastDispatcher: BroadcastDispatcher
-    @Captor
-    private lateinit var argCaptor: ArgumentCaptor<List<PrivacyItem>>
-    @Captor
-    private lateinit var argCaptorCallback: ArgumentCaptor<AppOpsController.Callback>
-
-    private lateinit var testableLooper: TestableLooper
-    private lateinit var privacyItemController: PrivacyItemController
-    private lateinit var handler: Handler
-
-    fun PrivacyItemController(context: Context) =
-            PrivacyItemController(context, appOpsController, handler, handler, broadcastDispatcher)
-
-    @Before
-    fun setup() {
-        MockitoAnnotations.initMocks(this)
-        testableLooper = TestableLooper.get(this)
-        handler = Handler(testableLooper.looper)
-
-        appOpsController = mDependency.injectMockDependency(AppOpsController::class.java)
-        mDependency.injectTestDependency(Dependency.MAIN_HANDLER, handler)
-        mContext.addMockSystemService(UserManager::class.java, userManager)
-        mContext.getOrCreateTestableResources().addOverride(R.string.device_services,
-                DEVICE_SERVICES_STRING)
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_PRIVACY,
-                SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED,
-                "true", false)
-
-        doReturn(listOf(object : UserInfo() {
-            init {
-                id = CURRENT_USER_ID
-            }
-        })).`when`(userManager).getProfiles(anyInt())
-
-        privacyItemController = PrivacyItemController(mContext)
-    }
-
-    @After
-    fun tearDown() {
-        DeviceConfig.resetToDefaults(RESET_MODE_PACKAGE_DEFAULTS, DeviceConfig.NAMESPACE_PRIVACY)
-    }
-
-    @Test
-    fun testSetListeningTrueByAddingCallback() {
-        privacyItemController.addCallback(callback)
-        testableLooper.processAllMessages()
-        verify(appOpsController).addCallback(eq(PrivacyItemController.OPS),
-                any(AppOpsController.Callback::class.java))
-        testableLooper.processAllMessages()
-        verify(callback).privacyChanged(anyList())
-    }
-
-    @Test
-    fun testSetListeningFalseByRemovingLastCallback() {
-        privacyItemController.addCallback(callback)
-        testableLooper.processAllMessages()
-        verify(appOpsController, never()).removeCallback(any(IntArray::class.java),
-                any(AppOpsController.Callback::class.java))
-        privacyItemController.removeCallback(callback)
-        testableLooper.processAllMessages()
-        verify(appOpsController).removeCallback(eq(PrivacyItemController.OPS),
-                any(AppOpsController.Callback::class.java))
-        verify(callback).privacyChanged(emptyList())
-    }
-
-    @Test
-    fun testDistinctItems() {
-        doReturn(listOf(AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 0),
-                AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 1)))
-                .`when`(appOpsController).getActiveAppOpsForUser(anyInt())
-
-        privacyItemController.addCallback(callback)
-        testableLooper.processAllMessages()
-        verify(callback).privacyChanged(capture(argCaptor))
-        assertEquals(1, argCaptor.value.size)
-    }
-
-    @Test
-    fun testSystemApps() {
-        doReturn(listOf(AppOpItem(AppOpsManager.OP_COARSE_LOCATION, SYSTEM_UID, TEST_PACKAGE_NAME,
-                0))).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
-        privacyItemController.addCallback(callback)
-        testableLooper.processAllMessages()
-        verify(callback).privacyChanged(capture(argCaptor))
-        assertEquals(1, argCaptor.value.size)
-        assertEquals(context.getString(R.string.device_services),
-                argCaptor.value[0].application.applicationName)
-    }
-
-    @Test
-    fun testRegisterReceiver_allUsers() {
-        privacyItemController.addCallback(callback)
-        testableLooper.processAllMessages()
-        verify(broadcastDispatcher, atLeastOnce()).registerReceiver(
-                eq(privacyItemController.userSwitcherReceiver), any(), eq(null), eq(UserHandle.ALL))
-        verify(broadcastDispatcher, never())
-                .unregisterReceiver(eq(privacyItemController.userSwitcherReceiver))
-    }
-
-    @Test
-    fun testReceiver_ACTION_USER_FOREGROUND() {
-        privacyItemController.userSwitcherReceiver.onReceive(context,
-                Intent(Intent.ACTION_USER_FOREGROUND))
-        verify(userManager).getProfiles(anyInt())
-    }
-
-    @Test
-    fun testReceiver_ACTION_MANAGED_PROFILE_ADDED() {
-        privacyItemController.userSwitcherReceiver.onReceive(context,
-                Intent(Intent.ACTION_MANAGED_PROFILE_ADDED))
-        verify(userManager).getProfiles(anyInt())
-    }
-
-    @Test
-    fun testReceiver_ACTION_MANAGED_PROFILE_REMOVED() {
-        privacyItemController.userSwitcherReceiver.onReceive(context,
-                Intent(Intent.ACTION_MANAGED_PROFILE_REMOVED))
-        verify(userManager).getProfiles(anyInt())
-    }
-
-    @Test
-    fun testAddMultipleCallbacks() {
-        val otherCallback = mock(PrivacyItemController.Callback::class.java)
-        privacyItemController.addCallback(callback)
-        testableLooper.processAllMessages()
-        verify(callback).privacyChanged(anyList())
-
-        privacyItemController.addCallback(otherCallback)
-        testableLooper.processAllMessages()
-        verify(otherCallback).privacyChanged(anyList())
-        // Adding a callback should not unnecessarily call previous ones
-        verifyNoMoreInteractions(callback)
-    }
-
-    @Test
-    fun testMultipleCallbacksAreUpdated() {
-        doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
-
-        val otherCallback = mock(PrivacyItemController.Callback::class.java)
-        privacyItemController.addCallback(callback)
-        privacyItemController.addCallback(otherCallback)
-        testableLooper.processAllMessages()
-        reset(callback)
-        reset(otherCallback)
-
-        verify(appOpsController).addCallback(any<IntArray>(), capture(argCaptorCallback))
-        argCaptorCallback.value.onActiveStateChanged(0, TEST_UID, "", true)
-        testableLooper.processAllMessages()
-        verify(callback).privacyChanged(anyList())
-        verify(otherCallback).privacyChanged(anyList())
-    }
-
-    @Test
-    fun testRemoveCallback() {
-        doReturn(emptyList<AppOpItem>()).`when`(appOpsController).getActiveAppOpsForUser(anyInt())
-        val otherCallback = mock(PrivacyItemController.Callback::class.java)
-        privacyItemController.addCallback(callback)
-        privacyItemController.addCallback(otherCallback)
-        testableLooper.processAllMessages()
-        reset(callback)
-        reset(otherCallback)
-
-        verify(appOpsController).addCallback(any<IntArray>(), capture(argCaptorCallback))
-        privacyItemController.removeCallback(callback)
-        argCaptorCallback.value.onActiveStateChanged(0, TEST_UID, "", true)
-        testableLooper.processAllMessages()
-        verify(callback, never()).privacyChanged(anyList())
-        verify(otherCallback).privacyChanged(anyList())
-    }
-
-    @Test
-    fun testListShouldNotHaveNull() {
-        doReturn(listOf(AppOpItem(AppOpsManager.OP_ACTIVATE_VPN, TEST_UID, "", 0),
-                        AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, "", 0)))
-                .`when`(appOpsController).getActiveAppOpsForUser(anyInt())
-        privacyItemController.addCallback(callback)
-        testableLooper.processAllMessages()
-
-        verify(callback).privacyChanged(capture(argCaptor))
-        assertEquals(1, argCaptor.value.size)
-        assertThat(argCaptor.value, not(hasItem(nullValue())))
-    }
-
-    @Test
-    fun testListShouldBeCopy() {
-        val list = listOf(PrivacyItem(PrivacyType.TYPE_CAMERA,
-                PrivacyApplication("", TEST_UID, mContext)))
-        privacyItemController.privacyList = list
-        val privacyList = privacyItemController.privacyList
-        assertEquals(list, privacyList)
-        assertTrue(list !== privacyList)
-    }
-
-    @Test
-    fun testNotListeningWhenIndicatorsDisabled() {
-        val properties = getProperties(
-                DeviceConfig.NAMESPACE_PRIVACY,
-                SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED,
-                false)
-        privacyItemController.devicePropertiesChangedListener.onPropertiesChanged(properties)
-        privacyItemController.addCallback(callback)
-        testableLooper.processAllMessages()
-        verify(appOpsController, never()).addCallback(eq(PrivacyItemController.OPS),
-                any(AppOpsController.Callback::class.java))
-    }
-
-    private fun getProperties(namespace: String, name: String, value: Boolean):
-            DeviceConfig.Properties {
-        val properties = mock<DeviceConfig.Properties>(DeviceConfig.Properties::class.java)
-        doReturn(namespace).`when`(properties).getNamespace()
-        doReturn(setOf(name)).`when`(properties).getKeyset()
-        doAnswer {
-            val key: String = it.getArgument(0)
-            val defaultValue: Boolean = it.getArgument(1)
-            if (name.equals(key, ignoreCase = true)) {
-                value
-            } else {
-                defaultValue
-            }
-        }.`when`(properties).getBoolean(anyString(), anyBoolean())
-        return properties
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
index b41512c..39ce8c1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
@@ -36,13 +36,9 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.os.Handler;
-import android.os.Looper;
 import android.provider.Settings;
 import android.service.quicksettings.Tile;
 import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
 import android.text.TextUtils;
 import android.util.ArraySet;
 
@@ -52,6 +48,8 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -69,7 +67,6 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
-@RunWithLooper
 public class TileQueryHelperTest extends SysuiTestCase {
     private static final String CURRENT_TILES = "wifi,dnd,nfc";
     private static final String ONLY_STOCK_TILES = "wifi,dnd";
@@ -98,14 +95,13 @@
     private ArgumentCaptor<List<TileQueryHelper.TileInfo>> mCaptor;
 
     private QSTile.State mState;
-    private TestableLooper mBGLooper;
     private TileQueryHelper mTileQueryHelper;
-    private Handler mMainHandler;
+    private FakeExecutor mMainExecutor;
+    private FakeExecutor mBgExecutor;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
-        mBGLooper = TestableLooper.get(this);
         mContext.setMockPackageManager(mPackageManager);
 
         mState = new QSTile.State();
@@ -123,9 +119,11 @@
                 }
         ).when(mQSTileHost).createTile(anyString());
 
-        mMainHandler = new Handler(Looper.getMainLooper());
-        mTileQueryHelper = new TileQueryHelper(mContext, mMainHandler,
-                new Handler(mBGLooper.getLooper()));
+        FakeSystemClock clock = new FakeSystemClock();
+        clock.setAutoIncrement(false);
+        mMainExecutor = new FakeExecutor(clock);
+        mBgExecutor = new FakeExecutor(clock);
+        mTileQueryHelper = new TileQueryHelper(mContext, mMainExecutor, mBgExecutor);
         mTileQueryHelper.setListener(mListener);
     }
 
@@ -138,8 +136,7 @@
     public void testIsFinished_trueAfterQuerying() {
         mTileQueryHelper.queryTiles(mQSTileHost);
 
-        mBGLooper.processAllMessages();
-        waitForIdleSync(mMainHandler);
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
 
         assertTrue(mTileQueryHelper.isFinished());
     }
@@ -148,8 +145,7 @@
     public void testQueryTiles_callsListenerTwice() {
         mTileQueryHelper.queryTiles(mQSTileHost);
 
-        mBGLooper.processAllMessages();
-        waitForIdleSync(mMainHandler);
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
 
         verify(mListener, times(2)).onTilesChanged(any());
     }
@@ -163,8 +159,7 @@
 
         mTileQueryHelper.queryTiles(mQSTileHost);
 
-        mBGLooper.processAllMessages();
-        waitForIdleSync(mMainHandler);
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
 
         assertTrue(mTileQueryHelper.isFinished());
     }
@@ -178,8 +173,7 @@
 
         mTileQueryHelper.queryTiles(mQSTileHost);
 
-        mBGLooper.processAllMessages();
-        waitForIdleSync(mMainHandler);
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
 
         verify(mListener, atLeastOnce()).onTilesChanged(mCaptor.capture());
         List<String> specs = new ArrayList<>();
@@ -199,8 +193,7 @@
 
         mTileQueryHelper.queryTiles(mQSTileHost);
 
-        mBGLooper.processAllMessages();
-        waitForIdleSync(mMainHandler);
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
 
         verify(mListener, atLeastOnce()).onTilesChanged(mCaptor.capture());
         List<String> specs = new ArrayList<>();
@@ -220,8 +213,7 @@
 
         mTileQueryHelper.queryTiles(mQSTileHost);
 
-        mBGLooper.processAllMessages();
-        waitForIdleSync(mMainHandler);
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
 
         verify(mListener, atLeastOnce()).onTilesChanged(mCaptor.capture());
         List<String> specs = new ArrayList<>();
@@ -251,8 +243,7 @@
                 "");
 
         mTileQueryHelper.queryTiles(mQSTileHost);
-        mBGLooper.processAllMessages();
-        waitForIdleSync(mMainHandler);
+        FakeExecutor.exhaustExecutors(mMainExecutor, mBgExecutor);
 
         verify(mListener, atLeastOnce()).onTilesChanged(mCaptor.capture());
         List<TileQueryHelper.TileInfo> tileInfos = mCaptor.getValue();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index a754a00d..8aac189 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -30,7 +30,7 @@
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.RemoteInputUriController;
 
 import com.google.android.collect.Sets;
@@ -76,7 +76,7 @@
 
         mRemoteInputManager = new TestableNotificationRemoteInputManager(mContext,
                 mLockscreenUserManager, mSmartReplyController, mEntryManager,
-                () -> mock(ShadeController.class),
+                () -> mock(StatusBar.class),
                 mStateController,
                 Handler.createAsync(Looper.myLooper()),
                 mRemoteInputUriController);
@@ -212,12 +212,12 @@
                 NotificationLockscreenUserManager lockscreenUserManager,
                 SmartReplyController smartReplyController,
                 NotificationEntryManager notificationEntryManager,
-                Lazy<ShadeController> shadeController,
+                Lazy<StatusBar> statusBarLazy,
                 StatusBarStateController statusBarStateController,
                 Handler mainHandler,
                 RemoteInputUriController remoteInputUriController) {
             super(context, lockscreenUserManager, smartReplyController, notificationEntryManager,
-                    shadeController, statusBarStateController, mainHandler,
+                    statusBarLazy, statusBarStateController, mainHandler,
                     remoteInputUriController);
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
index 95ce53c..3f62412 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
@@ -41,7 +41,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.RemoteInputUriController;
 
 import org.junit.Before;
@@ -88,7 +88,7 @@
 
         mRemoteInputManager = new NotificationRemoteInputManager(mContext,
                 mock(NotificationLockscreenUserManager.class), mSmartReplyController,
-                mNotificationEntryManager, () -> mock(ShadeController.class),
+                mNotificationEntryManager, () -> mock(StatusBar.class),
                 mStatusBarStateController,
                 Handler.createAsync(Looper.myLooper()),
                 mRemoteInputUriController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index a98945f..e0dfe7e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -85,6 +85,7 @@
 import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
 import com.android.systemui.statusbar.notification.logging.NotifLog;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.row.RowInflaterTask;
@@ -228,7 +229,8 @@
                         mHeadsUpManager,
                         mock(NotificationFilter.class),
                         mNotifLog,
-                        mock(NotificationSectionsFeatureManager.class)),
+                        mock(NotificationSectionsFeatureManager.class),
+                        mock(PeopleNotificationIdentifier.class)),
                 mEnvironment
         );
         Dependency.get(InitController.class).executePostInitTasks();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
index 68730d1..7fabb0f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
@@ -100,7 +100,7 @@
         when(mEnvironment.isDeviceProvisioned()).thenReturn(true);
         when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
         mRow = new NotificationTestHelper(getContext(), mDependency).createRow();
-        mNotificationFilter = new NotificationFilter();
+        mNotificationFilter = new NotificationFilter(mock(StatusBarStateController.class));
     }
 
     @Test
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 01b2f89..cda1538e 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
@@ -20,7 +20,6 @@
 import android.app.NotificationChannel
 import android.app.NotificationManager.IMPORTANCE_DEFAULT
 import android.app.NotificationManager.IMPORTANCE_LOW
-import android.app.Person
 import android.service.notification.NotificationListenerService.RankingMap
 import android.service.notification.StatusBarNotification
 import android.testing.AndroidTestingRunner
@@ -36,6 +35,7 @@
 import com.android.systemui.statusbar.notification.NotificationFilter
 import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
 import com.android.systemui.statusbar.notification.logging.NotifLog
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
 import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT
 import com.android.systemui.statusbar.phone.NotificationGroupManager
@@ -52,42 +52,39 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
-class NotificationRankingManagerTest
-    : SysuiTestCase() {
+class NotificationRankingManagerTest : SysuiTestCase() {
 
-    private var lazyMedia: Lazy<NotificationMediaManager> = Lazy {
-        mock<NotificationMediaManager>(NotificationMediaManager::class.java)
+    private val lazyMedia: Lazy<NotificationMediaManager> = Lazy {
+        mock(NotificationMediaManager::class.java)
     }
-
-    private val rankingManager = TestableNotificationRankingManager(
-            lazyMedia,
-            mock<NotificationGroupManager>(NotificationGroupManager::class.java),
-            mock<HeadsUpManager>(HeadsUpManager::class.java),
-            mock<NotificationFilter>(NotificationFilter::class.java),
-            mock<NotifLog>(NotifLog::class.java),
-            mock<NotificationSectionsFeatureManager>(NotificationSectionsFeatureManager::class.java)
-    )
+    private lateinit var personNotificationIdentifier: PeopleNotificationIdentifier
+    private lateinit var rankingManager: TestableNotificationRankingManager
 
     @Before
     fun setup() {
+        personNotificationIdentifier =
+                mock(PeopleNotificationIdentifier::class.java)
+        rankingManager = TestableNotificationRankingManager(
+                lazyMedia,
+                mock(NotificationGroupManager::class.java),
+                mock(HeadsUpManager::class.java),
+                mock(NotificationFilter::class.java),
+                mock(NotifLog::class.java),
+                mock(NotificationSectionsFeatureManager::class.java),
+                personNotificationIdentifier
+        )
     }
 
     @Test
     fun testPeopleNotification_isHighPriority() {
-        val person = Person.Builder()
-                .setName("name")
-                .setKey("abc")
-                .setUri("uri")
-                .setBot(true)
-                .build()
-
         val notification = Notification.Builder(mContext, "test")
-                .addPerson(person)
                 .build()
 
         val sbn = StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
                 notification, mContext.user, "", 0)
 
+        `when`(personNotificationIdentifier.isPeopleNotification(sbn)).thenReturn(true)
+
         val e = NotificationEntryBuilder()
                 .setNotification(notification)
                 .setSbn(sbn)
@@ -97,27 +94,9 @@
     }
 
     @Test
-    fun messagingStyleHighPriority() {
-
-        val notif = Notification.Builder(mContext, "test")
-                .setStyle(Notification.MessagingStyle(""))
-                .build()
-
-        val sbn = StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
-                notif, mContext.getUser(), "", 0)
-
-        val e = NotificationEntryBuilder()
-                .setNotification(notif)
-                .setSbn(sbn)
-                .build()
-
-        assertTrue(rankingManager.isHighPriority2(e))
-    }
-
-    @Test
     fun lowForegroundHighPriority() {
         val notification = mock(Notification::class.java)
-        `when`<Boolean>(notification.isForegroundService).thenReturn(true)
+        `when`(notification.isForegroundService).thenReturn(true)
 
         val sbn = StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
                 notification, mContext.user, "", 0)
@@ -136,15 +115,7 @@
 
     @Test
     fun userChangeTrumpsHighPriorityCharacteristics() {
-        val person = Person.Builder()
-                .setName("name")
-                .setKey("abc")
-                .setUri("uri")
-                .setBot(true)
-                .build()
-
         val notification = Notification.Builder(mContext, "test")
-                .addPerson(person)
                 .setStyle(Notification.MessagingStyle(""))
                 .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
                 .build()
@@ -152,6 +123,8 @@
         val sbn = StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
                 notification, mContext.user, "", 0)
 
+        `when`(personNotificationIdentifier.isPeopleNotification(sbn)).thenReturn(true)
+
         val channel = NotificationChannel("a", "a", IMPORTANCE_LOW)
         channel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE)
 
@@ -297,14 +270,16 @@
         headsUpManager: HeadsUpManager,
         filter: NotificationFilter,
         notifLog: NotifLog,
-        sectionsFeatureManager: NotificationSectionsFeatureManager
+        sectionsFeatureManager: NotificationSectionsFeatureManager,
+        peopleNotificationIdentifier: PeopleNotificationIdentifier
     ) : NotificationRankingManager(
         mediaManager,
         groupManager,
         headsUpManager,
         filter,
         notifLog,
-        sectionsFeatureManager
+        sectionsFeatureManager,
+        peopleNotificationIdentifier
     ) {
 
         fun isHighPriority2(e: NotificationEntry): Boolean {
@@ -315,4 +290,4 @@
             rankingMap = r
         }
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
new file mode 100644
index 0000000..87b3783d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
@@ -0,0 +1,243 @@
+/*
+ * 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.systemui.statusbar.notification.collection.coordinator;
+
+import static android.app.Notification.VISIBILITY_PUBLIC;
+import static android.app.Notification.VISIBILITY_SECRET;
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static android.app.NotificationManager.IMPORTANCE_MIN;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+import android.os.UserHandle;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.NotificationEntryBuilder;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.RankingBuilder;
+import com.android.systemui.statusbar.notification.collection.GroupEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class KeyguardCoordinatorTest extends SysuiTestCase {
+    private static final int NOTIF_USER_ID = 0;
+    private static final int CURR_USER_ID = 1;
+
+    @Mock private Handler mMainHandler;
+    @Mock private KeyguardStateController mKeyguardStateController;
+    @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
+    @Mock private BroadcastDispatcher mBroadcastDispatcher;
+    @Mock private StatusBarStateController mStatusBarStateController;
+    @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+
+    private NotificationEntry mEntry;
+    private KeyguardCoordinator mKeyguardNotificationCoordinator;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mKeyguardNotificationCoordinator = new KeyguardCoordinator(
+                mContext, mMainHandler, mKeyguardStateController, mLockscreenUserManager,
+                mBroadcastDispatcher, mStatusBarStateController,
+                mKeyguardUpdateMonitor);
+
+        mEntry = new NotificationEntryBuilder()
+                .setUser(new UserHandle(NOTIF_USER_ID))
+                .build();
+    }
+
+    @Test
+    public void unfilteredState() {
+        // GIVEN an 'unfiltered-keyguard-showing' state
+        setupUnfilteredState();
+
+        // THEN don't filter out the entry
+        assertFalse(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+    }
+
+    @Test
+    public void notificationNotForCurrentProfile() {
+        // GIVEN the notification isn't for the given user
+        setupUnfilteredState();
+        when(mLockscreenUserManager.isCurrentProfile(NOTIF_USER_ID)).thenReturn(false);
+
+        // THEN filter out the entry
+        assertTrue(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+    }
+
+    @Test
+    public void keyguardNotShowing() {
+        // GIVEN the lockscreen isn't showing
+        setupUnfilteredState();
+        when(mKeyguardStateController.isShowing()).thenReturn(false);
+
+        // THEN don't filter out the entry
+        assertFalse(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+    }
+
+    @Test
+    public void doNotShowLockscreenNotifications() {
+        // GIVEN an 'unfiltered-keyguard-showing' state
+        setupUnfilteredState();
+
+        // WHEN we shouldn't show any lockscreen notifications
+        when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false);
+
+        // THEN filter out the entry
+        assertTrue(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+    }
+
+    @Test
+    public void lockdown() {
+        // GIVEN an 'unfiltered-keyguard-showing' state
+        setupUnfilteredState();
+
+        // WHEN the notification's user is in lockdown:
+        when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(true);
+
+        // THEN filter out the entry
+        assertTrue(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+    }
+
+    @Test
+    public void publicMode_settingsDisallow() {
+        // GIVEN an 'unfiltered-keyguard-showing' state
+        setupUnfilteredState();
+
+        // WHEN the notification's user is in public mode and settings are configured to disallow
+        // notifications in public mode
+        when(mLockscreenUserManager.isLockscreenPublicMode(NOTIF_USER_ID)).thenReturn(true);
+        when(mLockscreenUserManager.userAllowsNotificationsInPublic(NOTIF_USER_ID))
+                .thenReturn(false);
+
+        // THEN filter out the entry
+        assertTrue(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+    }
+
+    @Test
+    public void publicMode_notifDisallowed() {
+        // GIVEN an 'unfiltered-keyguard-showing' state
+        setupUnfilteredState();
+
+        // WHEN the notification's user is in public mode and settings are configured to disallow
+        // notifications in public mode
+        when(mLockscreenUserManager.isLockscreenPublicMode(CURR_USER_ID)).thenReturn(true);
+        mEntry.setRanking(new RankingBuilder()
+                .setKey(mEntry.getKey())
+                .setVisibilityOverride(VISIBILITY_SECRET).build());
+
+        // THEN filter out the entry
+        assertTrue(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+    }
+
+    @Test
+    public void doesNotExceedThresholdToShow() {
+        // GIVEN an 'unfiltered-keyguard-showing' state
+        setupUnfilteredState();
+
+        // WHEN the notification doesn't exceed the threshold to show on the lockscreen
+        mEntry.setRanking(new RankingBuilder()
+                .setKey(mEntry.getKey())
+                .setImportance(IMPORTANCE_MIN)
+                .build());
+
+        // THEN filter out the entry
+        assertTrue(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+    }
+
+    @Test
+    public void summaryExceedsThresholdToShow() {
+        // GIVEN an 'unfiltered-keyguard-showing' state
+        setupUnfilteredState();
+
+        // WHEN the notification doesn't exceed the threshold to show on the lockscreen
+        // but its summary does
+        mEntry.setRanking(new RankingBuilder()
+                .setKey(mEntry.getKey())
+                .setImportance(IMPORTANCE_MIN)
+                .build());
+
+        final NotificationEntry summary = new NotificationEntryBuilder().build();
+        summary.setRanking(new RankingBuilder()
+                .setKey(summary.getKey())
+                .setImportance(IMPORTANCE_HIGH)
+                .build());
+        final GroupEntry group = new GroupEntry(mEntry.getSbn().getGroupKey());
+        group.setSummary(summary);
+        mEntry.setParent(group);
+
+        // THEN don't filter out the entry
+        assertFalse(mKeyguardNotificationCoordinator.mNotifFilter.shouldFilterOut(mEntry, 0));
+    }
+
+    /**
+     * setup a state where the notification will not be filtered by the
+     * KeyguardNotificationCoordinator when the keyguard is showing.
+     */
+    private void setupUnfilteredState() {
+        // notification is for current profile
+        when(mLockscreenUserManager.isCurrentProfile(NOTIF_USER_ID)).thenReturn(true);
+
+        // keyguard is showing
+        when(mKeyguardStateController.isShowing()).thenReturn(true);
+
+        // show notifications on the lockscreen
+        when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(true);
+
+        // neither the current user nor the notification's user is in lockdown
+        when(mLockscreenUserManager.getCurrentUserId()).thenReturn(CURR_USER_ID);
+        when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(false);
+        when(mKeyguardUpdateMonitor.isUserInLockdown(CURR_USER_ID)).thenReturn(false);
+
+        // not in public mode
+        when(mLockscreenUserManager.isLockscreenPublicMode(CURR_USER_ID)).thenReturn(false);
+        when(mLockscreenUserManager.isLockscreenPublicMode(NOTIF_USER_ID)).thenReturn(false);
+
+        // entry's ranking - should show on all lockscreens
+        // + priority of the notification exceeds the threshold to be shown on the lockscreen
+        mEntry.setRanking(new RankingBuilder()
+                .setKey(mEntry.getKey())
+                .setVisibilityOverride(VISIBILITY_PUBLIC)
+                .setImportance(IMPORTANCE_HIGH)
+                .build());
+
+        // settings allows notifications in public mode
+        when(mLockscreenUserManager.userAllowsNotificationsInPublic(CURR_USER_ID)).thenReturn(true);
+        when(mLockscreenUserManager.userAllowsNotificationsInPublic(NOTIF_USER_ID))
+                .thenReturn(true);
+
+        // notification doesn't have a summary
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
index ba28879..27e3a66 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
@@ -64,6 +64,7 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper(setAsMainLooper = true)
+@Ignore
 public class NotificationContentInflaterTest extends SysuiTestCase {
 
     private NotificationContentInflater mNotificationInflater;
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 4b3249d..43d39a2 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
@@ -274,7 +274,7 @@
         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
         verify(mNotificationActivityStarter, times(1))
                 .startNotificationGutsIntent(captor.capture(), anyInt(), any());
-        assertEquals(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, captor.getValue().getAction());
+        assertEquals(Settings.ACTION_MANAGE_APP_OVERLAY_PERMISSION, captor.getValue().getAction());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index d20a37a..d2b4a20 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -74,6 +74,7 @@
 import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
 import com.android.systemui.statusbar.notification.logging.NotifLog;
 import com.android.systemui.statusbar.notification.people.PeopleHubSectionFooterViewAdapter;
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.FooterView;
 import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
@@ -164,7 +165,8 @@
                         mHeadsUpManager,
                         mock(NotificationFilter.class),
                         mock(NotifLog.class),
-                        mock(NotificationSectionsFeatureManager.class)
+                        mock(NotificationSectionsFeatureManager.class),
+                        mock(PeopleNotificationIdentifier.class)
                 ),
                 mock(NotificationEntryManager.KeyguardEnvironment.class));
         mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
index 222fcb6..46f6cfe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
@@ -85,7 +85,6 @@
     @Mock private StatusBar mStatusBar;
     @Mock private NotificationIconAreaController mNotificationIconAreaController;
     @Mock private StatusBarWindowViewController mStatusBarWindowViewController;
-    @Mock private StatusBarWindowView mStatusBarWindow;
     @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     @Mock private NotificationPanelView mNotificationPanel;
     @Mock private View mAmbientIndicationContainer;
@@ -101,10 +100,11 @@
                 mKeyguardViewMediator, () -> mAssistManager, mDozeScrimController,
                 mKeyguardUpdateMonitor, mVisualStabilityManager, mPulseExpansionHandler,
                 mStatusBarWindowController, mNotificationWakeUpCoordinator,
-                mStatusBarWindowViewController, mLockscreenLockIconController);
+                mLockscreenLockIconController);
 
-        mDozeServiceHost.initialize(mStatusBar, mNotificationIconAreaController, mStatusBarWindow,
-                mStatusBarKeyguardViewManager, mNotificationPanel, mAmbientIndicationContainer);
+        mDozeServiceHost.initialize(mStatusBar, mNotificationIconAreaController,
+                mStatusBarKeyguardViewManager, mStatusBarWindowViewController, mNotificationPanel,
+                mAmbientIndicationContainer);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index 2068f7c..dfd9941 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -40,6 +40,7 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -125,6 +126,7 @@
         assertTrue(mHeadsUpManager.canRemoveImmediately(mEntry.getKey()));
     }
 
+    @Ignore("b/141538055")
     @Test
     public void testCanRemoveImmediately_notTopEntry() {
         NotificationEntry laterEntry = new NotificationEntryBuilder()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 61e5058..b27e84a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -126,7 +126,7 @@
     @Test
     public void showBouncer_onlyWhenShowing() {
         mStatusBarKeyguardViewManager.hide(0 /* startTime */, 0 /* fadeoutDuration */);
-        mStatusBar.showBouncer(true /* scrimmed */);
+        mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */);
         verify(mBouncer, never()).show(anyBoolean(), anyBoolean());
         verify(mBouncer, never()).show(anyBoolean());
     }
@@ -135,7 +135,7 @@
     public void showBouncer_notWhenBouncerAlreadyShowing() {
         mStatusBarKeyguardViewManager.hide(0 /* startTime */, 0 /* fadeoutDuration */);
         when(mBouncer.isSecure()).thenReturn(true);
-        mStatusBar.showBouncer(true /* scrimmed */);
+        mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */);
         verify(mBouncer, never()).show(anyBoolean(), anyBoolean());
         verify(mBouncer, never()).show(anyBoolean());
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 6f5cfbe..d7c00cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -98,11 +98,13 @@
     @Mock
     private StatusBarStateController mStatusBarStateController;
     @Mock
+    private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+    @Mock
     private NotificationRemoteInputManager mRemoteInputManager;
     @Mock
     private RemoteInputController mRemoteInputController;
     @Mock
-    private ShadeController mShadeController;
+    private StatusBar mStatusBar;
     @Mock
     private KeyguardStateController mKeyguardStateController;
     @Mock
@@ -167,7 +169,8 @@
                 getContext(), mock(CommandQueue.class), () -> mAssistManager,
                 mEntryManager, mock(HeadsUpManagerPhone.class),
                 mActivityStarter, mStatusBarService,
-                mock(StatusBarStateController.class), mock(KeyguardManager.class),
+                mock(StatusBarStateController.class), mStatusBarKeyguardViewManager,
+                mock(KeyguardManager.class),
                 mock(IDreamManager.class), mRemoteInputManager,
                 mock(StatusBarRemoteInputCallback.class), mock(NotificationGroupManager.class),
                 mock(NotificationLockscreenUserManager.class),
@@ -175,7 +178,7 @@
                 mock(NotificationInterruptionStateProvider.class), mock(MetricsLogger.class),
                 mock(LockPatternUtils.class), mHandler, mHandler, mActivityIntentHelper,
                 mBubbleController, mSuperStatusBarViewFactory))
-                .setShadeController(mShadeController)
+                .setStatusBar(mStatusBar)
                 .setNotificationPresenter(mock(NotificationPresenter.class))
                 .setActivityLaunchAnimator(mock(ActivityLaunchAnimator.class))
         .build();
@@ -186,11 +189,12 @@
 
         // set up addAfterKeyguardGoneRunnable to synchronously invoke the Runnable arg
         doAnswer(answerVoid(Runnable::run))
-                .when(mShadeController).addAfterKeyguardGoneRunnable(any(Runnable.class));
+                .when(mStatusBarKeyguardViewManager)
+                .addAfterKeyguardGoneRunnable(any(Runnable.class));
 
         // set up addPostCollapseAction to synchronously invoke the Runnable arg
         doAnswer(answerVoid(Runnable::run))
-                .when(mShadeController).addPostCollapseAction(any(Runnable.class));
+                .when(mStatusBar).addPostCollapseAction(any(Runnable.class));
 
         // set up Handler to synchronously invoke the Runnable arg
         doAnswer(answerVoid(Runnable::run))
@@ -209,13 +213,13 @@
         sbn.getNotification().flags |= Notification.FLAG_AUTO_CANCEL;
 
         when(mKeyguardStateController.isShowing()).thenReturn(true);
-        when(mShadeController.isOccluded()).thenReturn(true);
+        when(mStatusBar.isOccluded()).thenReturn(true);
 
         // When
         mNotificationActivityStarter.onNotificationClicked(sbn, mNotificationRow);
 
         // Then
-        verify(mShadeController, atLeastOnce()).collapsePanel();
+        verify(mStatusBar, atLeastOnce()).collapsePanel();
 
         verify(mContentIntent).sendAndReturnResult(
                 any(Context.class),
@@ -250,7 +254,7 @@
         verify(mBubbleController).expandStackAndSelectBubble(eq(sbn.getKey()));
 
         // This is called regardless, and simply short circuits when there is nothing to do.
-        verify(mShadeController, atLeastOnce()).collapsePanel();
+        verify(mStatusBar, atLeastOnce()).collapsePanel();
 
         verify(mAssistManager).hideAssist();
 
@@ -272,7 +276,7 @@
         // Given
         sbn.getNotification().contentIntent = null;
         when(mKeyguardStateController.isShowing()).thenReturn(true);
-        when(mShadeController.isOccluded()).thenReturn(true);
+        when(mStatusBar.isOccluded()).thenReturn(true);
 
         // When
         mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow);
@@ -280,7 +284,7 @@
         // Then
         verify(mBubbleController).expandStackAndSelectBubble(eq(sbn.getKey()));
 
-        verify(mShadeController, atLeastOnce()).collapsePanel();
+        verify(mStatusBar, atLeastOnce()).collapsePanel();
 
         verify(mAssistManager).hideAssist();
 
@@ -302,7 +306,7 @@
         // Given
         sbn.getNotification().contentIntent = mContentIntent;
         when(mKeyguardStateController.isShowing()).thenReturn(true);
-        when(mShadeController.isOccluded()).thenReturn(true);
+        when(mStatusBar.isOccluded()).thenReturn(true);
 
         // When
         mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow);
@@ -310,7 +314,7 @@
         // Then
         verify(mBubbleController).expandStackAndSelectBubble(eq(sbn.getKey()));
 
-        verify(mShadeController, atLeastOnce()).collapsePanel();
+        verify(mStatusBar, atLeastOnce()).collapsePanel();
 
         verify(mAssistManager).hideAssist();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index 1c02b60..fb6e168 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -39,6 +39,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
@@ -71,10 +72,11 @@
 public class StatusBarNotificationPresenterTest extends SysuiTestCase {
 
 
-    private StatusBarNotificationPresenter mStatusBar;
+    private StatusBarNotificationPresenter mStatusBarNotificationPresenter;
     private CommandQueue mCommandQueue;
     private FakeMetricsLogger mMetricsLogger;
     private ShadeController mShadeController = mock(ShadeController.class);
+    private StatusBar mStatusBar = mock(StatusBar.class);
 
     @Before
     public void setup() {
@@ -105,14 +107,15 @@
 
         StatusBarWindowView statusBarWindowView = mock(StatusBarWindowView.class);
         when(statusBarWindowView.getResources()).thenReturn(mContext.getResources());
-        mStatusBar = new StatusBarNotificationPresenter(mContext,
+        mStatusBarNotificationPresenter = new StatusBarNotificationPresenter(mContext,
                 mock(NotificationPanelView.class), mock(HeadsUpManagerPhone.class),
                 statusBarWindowView, mock(NotificationListContainerViewGroup.class),
                 mock(DozeScrimController.class), mock(ScrimController.class),
                 mock(ActivityLaunchAnimator.class), mock(DynamicPrivacyController.class),
                 mock(NotificationAlertingManager.class),
                 mock(NotificationRowBinderImpl.class), mock(KeyguardStateController.class),
-                mCommandQueue);
+                mock(KeyguardIndicationController.class),
+                mStatusBar, mCommandQueue);
     }
 
     @Test
@@ -129,7 +132,7 @@
         TestableLooper.get(this).processAllMessages();
 
         assertFalse("The panel shouldn't allow heads up while disabled",
-                mStatusBar.canHeadsUp(entry, entry.getSbn()));
+                mStatusBarNotificationPresenter.canHeadsUp(entry, entry.getSbn()));
     }
 
     @Test
@@ -146,13 +149,13 @@
         TestableLooper.get(this).processAllMessages();
 
         assertFalse("The panel shouldn't allow heads up while notitifcation shade disabled",
-                mStatusBar.canHeadsUp(entry, entry.getSbn()));
+                mStatusBarNotificationPresenter.canHeadsUp(entry, entry.getSbn()));
     }
 
     @Test
     public void onActivatedMetrics() {
         ActivatableNotificationView view =  mock(ActivatableNotificationView.class);
-        mStatusBar.onActivated(view);
+        mStatusBarNotificationPresenter.onActivated(view);
 
         MetricsAsserts.assertHasLog("missing lockscreen note tap log",
                 mMetricsLogger.getLogs(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
index 9d76b42..6dfd082 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
@@ -54,6 +54,7 @@
     @Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
     @Mock private KeyguardStateController mKeyguardStateController;
     @Mock private SysuiStatusBarStateController mStatusBarStateController;
+    @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     @Mock private ActivityStarter mActivityStarter;
 
     private int mCurrentUserId = 0;
@@ -71,8 +72,8 @@
 
         mRemoteInputCallback = spy(new StatusBarRemoteInputCallback(mContext,
                 mock(NotificationGroupManager.class), mNotificationLockscreenUserManager,
-                mKeyguardStateController, mStatusBarStateController, mActivityStarter,
-                () -> mShadeController, new CommandQueue(mContext)));
+                mKeyguardStateController, mStatusBarStateController, mStatusBarKeyguardViewManager,
+                mActivityStarter, () -> mShadeController, new CommandQueue(mContext)));
         mRemoteInputCallback.mChallengeReceiver = mRemoteInputCallback.new ChallengeReceiver();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index e78fb9e..be68097 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -145,6 +145,8 @@
 import java.util.ArrayList;
 import java.util.Optional;
 
+import javax.inject.Provider;
+
 import dagger.Lazy;
 
 @SmallTest
@@ -227,6 +229,9 @@
     @Mock private VolumeComponent mVolumeComponent;
     @Mock private CommandQueue mCommandQueue;
     @Mock private Recents mRecents;
+    @Mock private Provider<StatusBarComponent.Builder> mStatusBarComponentBuilderProvider;
+    @Mock private StatusBarComponent.Builder mStatusBarComponentBuilder;
+    @Mock private StatusBarComponent mStatusBarComponent;
     @Mock private PluginManager mPluginManager;
     @Mock private Divider mDivider;
     @Mock private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
@@ -300,6 +305,11 @@
         when(mLockscreenWallpaperLazy.get()).thenReturn(mLockscreenWallpaper);
         when(mBiometricUnlockControllerLazy.get()).thenReturn(mBiometricUnlockController);
 
+        when(mStatusBarComponentBuilderProvider.get()).thenReturn(mStatusBarComponentBuilder);
+        when(mStatusBarComponentBuilder.build()).thenReturn(mStatusBarComponent);
+        when(mStatusBarComponent.getStatusBarWindowViewController()).thenReturn(
+                mStatusBarWindowViewController);
+
         mStatusBar = new StatusBar(
                 mContext,
                 mFeatureFlags,
@@ -354,7 +364,6 @@
                 mNotificationListener,
                 configurationController,
                 mStatusBarWindowController,
-                mStatusBarWindowViewController,
                 mLockscreenLockIconController,
                 mDozeParameters,
                 mScrimController,
@@ -367,6 +376,7 @@
                 mVolumeComponent,
                 mCommandQueue,
                 Optional.of(mRecents),
+                mStatusBarComponentBuilderProvider,
                 mPluginManager,
                 mRemoteInputUriController,
                 Optional.of(mDivider),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
index ee9ea9f..00ea187 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
@@ -36,7 +36,6 @@
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.PulseExpansionHandler;
-import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -74,7 +73,6 @@
     @Mock private StatusBar mStatusBar;
     @Mock private DozeLog mDozeLog;
     @Mock private DozeParameters mDozeParameters;
-    @Mock private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
     @Mock private DockManager mDockManager;
 
     @Before
@@ -82,10 +80,9 @@
         MockitoAnnotations.initMocks(this);
 
         mView = new StatusBarWindowView(getContext(), null);
-        when(mStatusBar.isDozing()).thenReturn(false);
+        when(mStatusBarStateController.isDozing()).thenReturn(false);
         mDependency.injectTestDependency(ShadeController.class, mShadeController);
 
-        when(mSuperStatusBarViewFactory.getStatusBarWindowView()).thenReturn(mView);
         when(mDockManager.isDocked()).thenReturn(false);
 
         mController = new StatusBarWindowViewController(
@@ -105,9 +102,9 @@
                 mDozeLog,
                 mDozeParameters,
                 new CommandQueue(mContext),
-                mSuperStatusBarViewFactory,
                 () -> mShadeController,
-                mDockManager);
+                mDockManager,
+                mView);
         mController.setupExpandedStatusBar();
         mController.setService(mStatusBar);
         mController.setDragDownHelper(mDragDownHelper);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index ab74caa..95b055c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -500,7 +500,7 @@
     public void testUpdateDataNetworkName() {
         setupDefaultSignal();
         String newDataName = "TestDataName";
-        when(mServiceState.getDataOperatorAlphaShort()).thenReturn(newDataName);
+        when(mServiceState.getOperatorAlphaShort()).thenReturn(newDataName);
         updateServiceState();
         assertDataNetworkNameEquals(newDataName);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index 57dcbf2..4103d71 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -26,6 +26,7 @@
 import android.net.ConnectivityManager;
 import android.net.NetworkCapabilities;
 import android.os.Looper;
+import android.telephony.CellSignalStrength;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.SubscriptionInfo;
@@ -180,7 +181,7 @@
 
     @Test
     public void testCdmaSignalRoaming() {
-        for (int testStrength = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        for (int testStrength = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
                 testStrength <= SignalStrength.SIGNAL_STRENGTH_GREAT; testStrength++) {
             setupDefaultSignal();
             setCdma();
@@ -203,7 +204,7 @@
 
     @Test
     public void testQsSignalStrength() {
-        for (int testStrength = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        for (int testStrength = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
                 testStrength <= SignalStrength.SIGNAL_STRENGTH_GREAT; testStrength++) {
             setupDefaultSignal();
             setLevel(testStrength);
@@ -216,7 +217,7 @@
 
     @Test
     public void testCdmaQsSignalStrength() {
-        for (int testStrength = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        for (int testStrength = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
                 testStrength <= SignalStrength.SIGNAL_STRENGTH_GREAT; testStrength++) {
             setupDefaultSignal();
             setCdma();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutor.java b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutor.java
new file mode 100644
index 0000000..f3c0530
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutor.java
@@ -0,0 +1,222 @@
+/*
+ * 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.systemui.util.concurrency;
+
+import com.android.systemui.util.time.FakeSystemClock;
+import com.android.systemui.util.time.FakeSystemClock.ClockTickListener;
+
+import java.util.Collections;
+import java.util.PriorityQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class FakeExecutor implements DelayableExecutor {
+    private final FakeSystemClock mClock;
+    private PriorityQueue<QueuedRunnable> mQueuedRunnables = new PriorityQueue<>();
+    private boolean mIgnoreClockUpdates;
+
+    private ClockTickListener mClockTickListener = new ClockTickListener() {
+        @Override
+        public void onUptimeMillis(long uptimeMillis) {
+            if (!mIgnoreClockUpdates) {
+                runAllReady();
+            }
+        }
+    };
+
+    /**
+     * Initializes a fake executor.
+     *
+     * @param clock FakeSystemClock allowing control over delayed runnables. It is strongly
+     *              recommended that this clock have its auto-increment setting set to false to
+     *              prevent unexpected advancement of the time.
+     */
+    public FakeExecutor(FakeSystemClock clock) {
+        mClock = clock;
+        mClock.addListener(mClockTickListener);
+    }
+
+    /**
+     * Runs a single runnable if it's scheduled to run according to the internal clock.
+     *
+     * If constructed to advance the clock automatically, this will advance the clock enough to
+     * run the next pending item.
+     *
+     * This method does not advance the clock past the item that was run.
+     *
+     * @return Returns true if an item was run.
+     */
+    public boolean runNextReady() {
+        if (!mQueuedRunnables.isEmpty() && mQueuedRunnables.peek().mWhen <= mClock.uptimeMillis()) {
+            mQueuedRunnables.poll().mRunnable.run();
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Runs all Runnables that are scheduled to run according to the internal clock.
+     *
+     * If constructed to advance the clock automatically, this will advance the clock enough to
+     * run all the pending items. This method does not advance the clock past items that were
+     * run. It is equivalent to calling {@link #runNextReady()} in a loop.
+     *
+     * @return Returns the number of items that ran.
+     */
+    public int runAllReady() {
+        int num = 0;
+        while (runNextReady()) {
+            num++;
+        }
+
+        return num;
+    }
+
+    /**
+     * Advances the internal clock to the next item to run.
+     *
+     * The clock will only move forward. If the next item is set to run in the past or there is no
+     * next item, the clock does not change.
+     *
+     * Note that this will cause one or more items to actually run.
+     *
+     * @return The delta in uptimeMillis that the clock advanced, or 0 if the clock did not advance.
+     */
+    public long advanceClockToNext() {
+        if (mQueuedRunnables.isEmpty()) {
+            return 0;
+        }
+
+        long startTime = mClock.uptimeMillis();
+        long nextTime = mQueuedRunnables.peek().mWhen;
+        if (nextTime <= startTime) {
+            return 0;
+        }
+        updateClock(nextTime);
+
+        return nextTime - startTime;
+    }
+
+
+    /**
+     * Advances the internal clock to the last item to run.
+     *
+     * The clock will only move forward. If the last item is set to run in the past or there is no
+     * next item, the clock does not change.
+     *
+     * @return The delta in uptimeMillis that the clock advanced, or 0 if the clock did not advance.
+     */
+    public long advanceClockToLast() {
+        if (mQueuedRunnables.isEmpty()) {
+            return 0;
+        }
+
+        long startTime = mClock.uptimeMillis();
+        long nextTime = Collections.max(mQueuedRunnables).mWhen;
+        if (nextTime <= startTime) {
+            return 0;
+        }
+
+        updateClock(nextTime);
+
+        return nextTime - startTime;
+    }
+
+    /**
+     * Returns the number of un-executed runnables waiting to run.
+     */
+    public int numPending() {
+        return mQueuedRunnables.size();
+    }
+
+    @Override
+    public Runnable executeDelayed(Runnable r, long delay, TimeUnit unit) {
+        if (delay < 0) {
+            delay = 0;
+        }
+        return executeAtTime(r, mClock.uptimeMillis() + unit.toMillis(delay));
+    }
+
+    @Override
+    public Runnable executeAtTime(Runnable r, long uptime, TimeUnit unit) {
+        long uptimeMillis = unit.toMillis(uptime);
+
+        QueuedRunnable container = new QueuedRunnable(r, uptimeMillis);
+
+        mQueuedRunnables.offer(container);
+
+        return () -> mQueuedRunnables.remove(container);
+    }
+
+    @Override
+    public void execute(Runnable command) {
+        executeDelayed(command, 0);
+    }
+
+    /**
+     * Run all Executors in a loop until they all report they have no ready work to do.
+     *
+     * Useful if you have Executors the post work to other Executors, and you simply want to
+     * run them all until they stop posting work.
+     */
+    public static void exhaustExecutors(FakeExecutor ...executors) {
+        boolean didAnything;
+        do {
+            didAnything = false;
+            for (FakeExecutor executor : executors) {
+                didAnything = didAnything || executor.runAllReady() != 0;
+            }
+        } while (didAnything);
+    }
+
+    private void updateClock(long nextTime) {
+        mIgnoreClockUpdates = true;
+        mClock.setUptimeMillis(nextTime);
+        mIgnoreClockUpdates = false;
+    }
+
+    private static class QueuedRunnable implements Comparable<QueuedRunnable> {
+        private static AtomicInteger sCounter = new AtomicInteger();
+
+        Runnable mRunnable;
+        long mWhen;
+        private int mCounter;
+
+        private QueuedRunnable(Runnable r, long when) {
+            mRunnable = r;
+            mWhen = when;
+
+            // PrioirityQueue orders items arbitrarily when equal. We want to ensure that
+            // otherwise-equal elements are ordered according to their insertion order. Because this
+            // class only is constructed right before insertion, we use a static counter to track
+            // insertion order of otherwise equal elements.
+            mCounter = sCounter.incrementAndGet();
+        }
+
+        @Override
+        public int compareTo(QueuedRunnable other) {
+            long diff = mWhen - other.mWhen;
+
+            if (diff == 0) {
+                return mCounter - other.mCounter;
+            }
+
+            return diff > 0 ? 1 : -1;
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java
new file mode 100644
index 0000000..b1716ff
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java
@@ -0,0 +1,336 @@
+/*
+ * 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.systemui.util.concurrency;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import kotlin.jvm.functions.Function4;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class FakeExecutorTest extends SysuiTestCase {
+    @Before
+    public void setUp() throws Exception {
+    }
+
+    /**
+     * Test FakeExecutor that receives non-delayed items to execute.
+     */
+    @Test
+    public void testNoDelay() {
+        FakeSystemClock clock = new FakeSystemClock();
+        clock.setAutoIncrement(false);
+        FakeExecutor fakeExecutor = new FakeExecutor(clock);
+        RunnableImpl runnable = new RunnableImpl();
+
+        assertEquals(0, clock.uptimeMillis());
+        assertEquals(0, runnable.mRunCount);
+
+        // Execute two runnables. They should not run and should be left pending.
+        fakeExecutor.execute(runnable);
+        assertEquals(0, runnable.mRunCount);
+        assertEquals(0, clock.uptimeMillis());
+        assertEquals(1, fakeExecutor.numPending());
+        fakeExecutor.execute(runnable);
+        assertEquals(0, runnable.mRunCount);
+        assertEquals(0, clock.uptimeMillis());
+        assertEquals(2, fakeExecutor.numPending());
+
+        // Run one pending runnable.
+        assertTrue(fakeExecutor.runNextReady());
+        assertEquals(1, runnable.mRunCount);
+        assertEquals(0, clock.uptimeMillis());
+        assertEquals(1, fakeExecutor.numPending());
+        // Run a second pending runnable.
+        assertTrue(fakeExecutor.runNextReady());
+        assertEquals(2, runnable.mRunCount);
+        assertEquals(0, clock.uptimeMillis());
+        assertEquals(0, fakeExecutor.numPending());
+
+        // No more runnables to run.
+        assertFalse(fakeExecutor.runNextReady());
+
+        // Add two more runnables.
+        fakeExecutor.execute(runnable);
+        fakeExecutor.execute(runnable);
+        assertEquals(2, runnable.mRunCount);
+        assertEquals(0, clock.uptimeMillis());
+        assertEquals(2, fakeExecutor.numPending());
+        // Execute all pending runnables in batch.
+        assertEquals(2, fakeExecutor.runAllReady());
+        assertEquals(4, runnable.mRunCount);
+        assertEquals(0, clock.uptimeMillis());
+        assertEquals(0, fakeExecutor.runAllReady());
+    }
+
+    /**
+     * Test FakeExecutor that is told to delay execution on items.
+     */
+    @Test
+    public void testDelayed() {
+        FakeSystemClock clock = new FakeSystemClock();
+        clock.setAutoIncrement(false);
+        FakeExecutor fakeExecutor = new FakeExecutor(clock);
+        RunnableImpl runnable = new RunnableImpl();
+
+        // Add three delayed runnables.
+        fakeExecutor.executeDelayed(runnable, 1);
+        fakeExecutor.executeDelayed(runnable, 50);
+        fakeExecutor.executeDelayed(runnable, 100);
+        assertEquals(0, runnable.mRunCount);
+        assertEquals(0, clock.uptimeMillis());
+        assertEquals(3, fakeExecutor.numPending());
+        // Delayed runnables should not advance the clock and therefore should not run.
+        assertFalse(fakeExecutor.runNextReady());
+        assertEquals(0, fakeExecutor.runAllReady());
+        assertEquals(3, fakeExecutor.numPending());
+
+        // Advance the clock to the next runnable. One runnable should execute.
+        assertEquals(1, fakeExecutor.advanceClockToNext());
+        assertEquals(1, fakeExecutor.runAllReady());
+        assertEquals(2, fakeExecutor.numPending());
+        assertEquals(1, runnable.mRunCount);
+        // Advance the clock to the last runnable.
+        assertEquals(99, fakeExecutor.advanceClockToLast());
+        assertEquals(2, fakeExecutor.runAllReady());
+        // Now all remaining runnables should execute.
+        assertEquals(0, fakeExecutor.numPending());
+        assertEquals(3, runnable.mRunCount);
+    }
+
+    /**
+     * Test FakeExecutor that is told to delay execution on items.
+     */
+    @Test
+    public void testDelayed_AdvanceAndRun() {
+        FakeSystemClock clock = new FakeSystemClock();
+        clock.setAutoIncrement(false);
+        FakeExecutor fakeExecutor = new FakeExecutor(clock);
+        RunnableImpl runnable = new RunnableImpl();
+
+        // Add three delayed runnables.
+        fakeExecutor.executeDelayed(runnable, 1);
+        fakeExecutor.executeDelayed(runnable, 50);
+        fakeExecutor.executeDelayed(runnable, 100);
+        assertEquals(0, runnable.mRunCount);
+        assertEquals(0, clock.uptimeMillis());
+        assertEquals(3, fakeExecutor.numPending());
+        // Delayed runnables should not advance the clock and therefore should not run.
+        assertFalse(fakeExecutor.runNextReady());
+        assertEquals(0, fakeExecutor.runAllReady());
+        assertEquals(3, fakeExecutor.numPending());
+
+        // Advance the clock to the next runnable. Check that it is run.
+        assertEquals(1, fakeExecutor.advanceClockToNext());
+        assertEquals(1, fakeExecutor.runAllReady());
+        assertEquals(1, clock.uptimeMillis());
+        assertEquals(2, fakeExecutor.numPending());
+        assertEquals(1, runnable.mRunCount);
+        assertEquals(49, fakeExecutor.advanceClockToNext());
+        assertEquals(1, fakeExecutor.runAllReady());
+        assertEquals(50, clock.uptimeMillis());
+        assertEquals(1, fakeExecutor.numPending());
+        assertEquals(2, runnable.mRunCount);
+        assertEquals(50, fakeExecutor.advanceClockToNext());
+        assertEquals(1, fakeExecutor.runAllReady());
+        assertEquals(100, clock.uptimeMillis());
+        assertEquals(0, fakeExecutor.numPending());
+        assertEquals(3, runnable.mRunCount);
+
+        // Nothing left to do
+        assertEquals(0, fakeExecutor.advanceClockToNext());
+        assertEquals(0, fakeExecutor.runAllReady());
+        assertEquals(100, clock.uptimeMillis());
+        assertEquals(0, fakeExecutor.numPending());
+        assertEquals(3, runnable.mRunCount);
+    }
+
+    /**
+     * Test execution order.
+     */
+    @Test
+    public void testExecutionOrder() {
+        FakeSystemClock clock = new FakeSystemClock();
+        clock.setAutoIncrement(false);
+        FakeExecutor fakeExecutor = new FakeExecutor(clock);
+        RunnableImpl runnableA = new RunnableImpl();
+        RunnableImpl runnableB = new RunnableImpl();
+        RunnableImpl runnableC = new RunnableImpl();
+        RunnableImpl runnableD = new RunnableImpl();
+
+        Function4<Integer, Integer, Integer, Integer, Void> checkRunCounts =
+                (Integer argA, Integer argB, Integer argC, Integer argD) -> {
+                    assertEquals("RunnableA run count wrong", argA.intValue(), runnableA.mRunCount);
+                    assertEquals("RunnableB run count wrong", argB.intValue(), runnableB.mRunCount);
+                    assertEquals("RunnableC run count wrong", argC.intValue(), runnableC.mRunCount);
+                    assertEquals("RunnableD run count wrong", argD.intValue(), runnableD.mRunCount);
+                    return null;
+                };
+
+        assertEquals(0, clock.uptimeMillis());
+        checkRunCounts.invoke(0, 0, 0, 0);
+
+        fakeExecutor.execute(runnableA);
+        fakeExecutor.execute(runnableB);
+        fakeExecutor.execute(runnableC);
+        fakeExecutor.execute(runnableD);
+
+        fakeExecutor.runNextReady();
+        checkRunCounts.invoke(1, 0, 0, 0);
+        fakeExecutor.runNextReady();
+        checkRunCounts.invoke(1, 1, 0, 0);
+        fakeExecutor.runNextReady();
+        checkRunCounts.invoke(1, 1, 1, 0);
+        fakeExecutor.runNextReady();
+        checkRunCounts.invoke(1, 1, 1, 1);
+
+        fakeExecutor.executeDelayed(runnableA, 100);
+        fakeExecutor.execute(runnableB);
+        fakeExecutor.executeDelayed(runnableC, 50);
+        fakeExecutor.execute(runnableD);
+
+        fakeExecutor.advanceClockToNext();
+        fakeExecutor.runAllReady();
+        checkRunCounts.invoke(1, 2, 1, 2);
+        fakeExecutor.advanceClockToNext();
+        fakeExecutor.runAllReady();
+        checkRunCounts.invoke(1, 2, 2, 2);
+        fakeExecutor.advanceClockToNext();
+        fakeExecutor.runAllReady();
+        checkRunCounts.invoke(2, 2, 2, 2);
+
+        fakeExecutor.execute(runnableA);
+        fakeExecutor.executeAtTime(runnableB, 0);  // this is in the past!
+        fakeExecutor.executeAtTime(runnableC, 1000);
+        fakeExecutor.executeAtTime(runnableD, 500);
+
+        fakeExecutor.advanceClockToNext();
+        fakeExecutor.runAllReady();
+        checkRunCounts.invoke(3, 3, 2, 2);
+        fakeExecutor.advanceClockToNext();
+        fakeExecutor.runAllReady();
+        checkRunCounts.invoke(3, 3, 2, 3);
+        fakeExecutor.advanceClockToNext();
+        fakeExecutor.runAllReady();
+        checkRunCounts.invoke(3, 3, 3, 3);
+    }
+
+    /**
+     * Test removing a single item.
+     */
+    @Test
+    public void testRemoval_single() {
+        FakeSystemClock clock = new FakeSystemClock();
+        clock.setAutoIncrement(false);
+        FakeExecutor fakeExecutor = new FakeExecutor(clock);
+        RunnableImpl runnable = new RunnableImpl();
+        Runnable removeFunction;
+
+        // Nothing to remove.
+        assertEquals(0, runnable.mRunCount);
+        assertEquals(0, fakeExecutor.numPending());
+
+        // Two pending items that have not yet run.
+        // We will try to remove the second item.
+        fakeExecutor.executeDelayed(runnable, 100);
+        removeFunction = fakeExecutor.executeDelayed(runnable, 200);
+        assertEquals(2, fakeExecutor.numPending());
+        assertEquals(0, runnable.mRunCount);
+
+        // Remove the item.
+        removeFunction.run();
+        assertEquals(1, fakeExecutor.numPending());
+        assertEquals(0, runnable.mRunCount);
+
+        // One item to run.
+        fakeExecutor.advanceClockToLast();
+        fakeExecutor.runAllReady();
+        assertEquals(0, fakeExecutor.numPending());
+        assertEquals(1, runnable.mRunCount);
+
+        // Nothing to remove.
+        removeFunction.run();
+        fakeExecutor.runAllReady();
+        assertEquals(0, fakeExecutor.numPending());
+        assertEquals(1, runnable.mRunCount);
+    }
+
+    /**
+     * Test removing multiple items.
+     */
+    @Test
+    public void testRemoval_multi() {
+        FakeSystemClock clock = new FakeSystemClock();
+        clock.setAutoIncrement(false);
+        FakeExecutor fakeExecutor = new FakeExecutor(clock);
+        List<Runnable> removeFunctions = new ArrayList<>();
+        RunnableImpl runnable = new RunnableImpl();
+
+        // Nothing to remove.
+        assertEquals(0, runnable.mRunCount);
+        assertEquals(0, fakeExecutor.numPending());
+
+        // Three pending items that have not yet run.
+        // We will try to remove the first and third items.
+        removeFunctions.add(fakeExecutor.executeDelayed(runnable, 100));
+        fakeExecutor.executeDelayed(runnable, 200);
+        removeFunctions.add(fakeExecutor.executeDelayed(runnable, 300));
+        assertEquals(3, fakeExecutor.numPending());
+        assertEquals(0, runnable.mRunCount);
+
+        // Remove the items.
+        removeFunctions.forEach(Runnable::run);
+        assertEquals(1, fakeExecutor.numPending());
+        assertEquals(0, runnable.mRunCount);
+
+        // One item to run.
+        fakeExecutor.advanceClockToLast();
+        fakeExecutor.runAllReady();
+        assertEquals(0, fakeExecutor.numPending());
+        assertEquals(1, runnable.mRunCount);
+
+        // Nothing to remove.
+        removeFunctions.forEach(Runnable::run);
+        assertEquals(0, fakeExecutor.numPending());
+        assertEquals(1, runnable.mRunCount);
+    }
+
+    private static class RunnableImpl implements Runnable {
+        int mRunCount;
+
+        @Override
+        public void run() {
+            mRunCount++;
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java b/packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java
index 7b5417c..65e5902 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.util.time;
 
+import java.util.ArrayList;
+import java.util.List;
+
 public class FakeSystemClock implements SystemClock {
     private boolean mAutoIncrement = true;
 
@@ -26,11 +29,13 @@
     private long mCurrentThreadTimeMicro;
     private long mCurrentTimeMicro;
 
+    List<ClockTickListener> mListeners = new ArrayList<>();
+
     @Override
     public long uptimeMillis() {
         long value = mUptimeMillis;
         if (mAutoIncrement) {
-            mUptimeMillis++;
+            setUptimeMillis(mUptimeMillis + 1);
         }
         return value;
     }
@@ -39,7 +44,7 @@
     public long elapsedRealtime() {
         long value = mElapsedRealtime;
         if (mAutoIncrement) {
-            mElapsedRealtime++;
+            setElapsedRealtime(mElapsedRealtime + 1);
         }
         return value;
     }
@@ -48,7 +53,7 @@
     public long elapsedRealtimeNanos() {
         long value = mElapsedRealtimeNanos;
         if (mAutoIncrement) {
-            mElapsedRealtimeNanos++;
+            setElapsedRealtimeNanos(mElapsedRealtimeNanos + 1);
         }
         return value;
     }
@@ -57,7 +62,7 @@
     public long currentThreadTimeMillis() {
         long value = mCurrentThreadTimeMillis;
         if (mAutoIncrement) {
-            mCurrentThreadTimeMillis++;
+            setCurrentThreadTimeMillis(mCurrentThreadTimeMillis + 1);
         }
         return value;
     }
@@ -66,7 +71,7 @@
     public long currentThreadTimeMicro() {
         long value = mCurrentThreadTimeMicro;
         if (mAutoIncrement) {
-            mCurrentThreadTimeMicro++;
+            setCurrentThreadTimeMicro(mCurrentThreadTimeMicro + 1);
         }
         return value;
     }
@@ -75,37 +80,90 @@
     public long currentTimeMicro() {
         long value = mCurrentTimeMicro;
         if (mAutoIncrement) {
-            mCurrentTimeMicro++;
+            setCurrentTimeMicro(mCurrentTimeMicro + 1);
         }
         return value;
     }
 
     public void setUptimeMillis(long uptimeMillis) {
         mUptimeMillis = uptimeMillis;
+        for (ClockTickListener listener : mListeners) {
+            listener.onUptimeMillis(mUptimeMillis);
+        }
     }
 
     public void setElapsedRealtime(long elapsedRealtime) {
         mElapsedRealtime = elapsedRealtime;
+        for (ClockTickListener listener : mListeners) {
+            listener.onElapsedRealtime(mElapsedRealtime);
+        }
     }
 
     public void setElapsedRealtimeNanos(long elapsedRealtimeNanos) {
         mElapsedRealtimeNanos = elapsedRealtimeNanos;
+        for (ClockTickListener listener : mListeners) {
+            listener.onElapsedRealtimeNanos(mElapsedRealtimeNanos);
+        }
     }
 
     public void setCurrentThreadTimeMillis(long currentThreadTimeMillis) {
         mCurrentThreadTimeMillis = currentThreadTimeMillis;
+        for (ClockTickListener listener : mListeners) {
+            listener.onCurrentThreadTimeMillis(mCurrentThreadTimeMillis);
+        }
     }
 
     public void setCurrentThreadTimeMicro(long currentThreadTimeMicro) {
         mCurrentThreadTimeMicro = currentThreadTimeMicro;
+        for (ClockTickListener listener : mListeners) {
+            listener.onCurrentThreadTimeMicro(mCurrentThreadTimeMicro);
+        }
     }
 
     public void setCurrentTimeMicro(long currentTimeMicro) {
         mCurrentTimeMicro = currentTimeMicro;
+        for (ClockTickListener listener : mListeners) {
+            listener.onCurrentTimeMicro(mCurrentTimeMicro);
+        }
     }
 
     /** If true, each call to get____ will be one higher than the previous call to that method. */
     public void setAutoIncrement(boolean autoIncrement) {
         mAutoIncrement = autoIncrement;
     }
+
+    public void addListener(ClockTickListener listener) {
+        mListeners.add(listener);
+    }
+
+    public void removeListener(ClockTickListener listener) {
+        mListeners.remove(listener);
+    }
+
+    /** Alert all the listeners about the current time. */
+    public void synchronizeListeners() {
+        for (ClockTickListener listener : mListeners) {
+            listener.onUptimeMillis(mUptimeMillis);
+            listener.onElapsedRealtime(mElapsedRealtime);
+            listener.onElapsedRealtimeNanos(mElapsedRealtimeNanos);
+            listener.onCurrentThreadTimeMillis(mCurrentThreadTimeMillis);
+            listener.onCurrentThreadTimeMicro(mCurrentThreadTimeMicro);
+            listener.onCurrentTimeMicro(mCurrentTimeMicro);
+        }
+    }
+
+
+    public interface ClockTickListener {
+        default void onUptimeMillis(long uptimeMillis) {}
+
+        default void onElapsedRealtime(long elapsedRealtime) {}
+
+        default void onElapsedRealtimeNanos(long elapsedRealtimeNanos) {}
+
+        default void onCurrentThreadTimeMillis(long currentThreadTimeMillis) {}
+
+        default void onCurrentThreadTimeMicro(long currentThreadTimeMicro) {}
+
+        default void onCurrentTimeMicro(long currentTimeMicro) {}
+    }
 }
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index 7b35f4d..7e8721d 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -22,13 +22,12 @@
         ":framework-tethering-shared-srcs",
         ":net-module-utils-srcs",
         ":services-tethering-shared-srcs",
-        ":servicescore-tethering-src",
     ],
     static_libs: [
         "androidx.annotation_annotation",
-        "netd_aidl_interface-java",
+        "netd_aidl_interface-unstable-java",
         "netlink-client",
-        "networkstack-aidl-interfaces-java",
+        "networkstack-aidl-interfaces-unstable-java",
         "android.hardware.tetheroffload.control-V1.0-java",
         "tethering-client",
     ],
@@ -41,20 +40,26 @@
     defaults: ["TetheringAndroidLibraryDefaults"],
 }
 
-cc_library_shared {
+// Due to b/143733063, APK can't access a jni lib that is in APEX (but not in the APK).
+cc_library {
     name: "libtetheroffloadjni",
     srcs: [
         "jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp",
     ],
     shared_libs: [
-        "libnativehelper",
-        "libcutils",
-        "android.hardware.tetheroffload.config@1.0",
+        "libcgrouprc",
+        "libnativehelper_compat_libc++",
+        "libvndksupport",
     ],
     static_libs: [
+        "android.hardware.tetheroffload.config@1.0",
         "liblog",
         "libbase",
+        "libbinderthreadstate",
+        "libcutils",
         "libhidlbase",
+        "libjsoncpp",
+        "libprocessgroup",
         "libutils",
     ],
 
@@ -64,6 +69,8 @@
         "-Wno-unused-parameter",
         "-Wthread-safety",
     ],
+
+    ldflags: ["-Wl,--exclude-libs=ALL,-error-limit=0"],
 }
 
 // Common defaults for compiling the actual APK.
@@ -71,7 +78,12 @@
     name: "TetheringAppDefaults",
     platform_apis: true,
     privileged: true,
+    // Build system doesn't track transitive dependeicies for jni_libs, list all the dependencies
+    // explicitly.
     jni_libs: [
+        "libcgrouprc",
+        "libnativehelper_compat_libc++",
+        "libvndksupport",
         "libtetheroffloadjni",
     ],
     resource_dirs: [
@@ -83,7 +95,16 @@
 }
 
 // Non-updatable tethering running in the system server process for devices not using the module
-// TODO: build in-process tethering APK here.
+android_app {
+    name: "InProcessTethering",
+    defaults: ["TetheringAppDefaults"],
+    static_libs: ["TetheringApiCurrentLib"],
+    certificate: "platform",
+    manifest: "AndroidManifest_InProcess.xml",
+    // InProcessTethering is a replacement for Tethering
+    overrides: ["Tethering"],
+    // TODO: use PlatformNetworkPermissionConfig.
+}
 
 // Updatable tethering packaged as an application
 android_app {
@@ -96,36 +117,3 @@
     // The permission configuration *must* be included to ensure security of the device
     required: ["NetworkPermissionConfig"],
 }
-
-// This group will be removed when tethering migration is done.
-filegroup {
-    name: "tethering-servicescore-srcs",
-    srcs: [
-        "src/com/android/server/connectivity/tethering/EntitlementManager.java",
-        "src/com/android/server/connectivity/tethering/OffloadController.java",
-        "src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java",
-        "src/com/android/server/connectivity/tethering/TetheringConfiguration.java",
-        "src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java",
-    ],
-}
-
-// This group will be removed when tethering migration is done.
-filegroup {
-    name: "tethering-servicesnet-srcs",
-    srcs: [
-        "src/android/net/dhcp/DhcpServerCallbacks.java",
-        "src/android/net/dhcp/DhcpServingParamsParcelExt.java",
-        "src/android/net/ip/IpServer.java",
-        "src/android/net/ip/RouterAdvertisementDaemon.java",
-        "src/android/net/util/InterfaceSet.java",
-        "src/android/net/util/PrefixUtils.java",
-    ],
-}
-
-// This group would be removed when tethering migration is done.
-filegroup {
-    name: "tethering-jni-srcs",
-    srcs: [
-        "jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp",
-    ],
-}
diff --git a/packages/Tethering/AndroidManifest.xml b/packages/Tethering/AndroidManifest.xml
index eb51593..1430ed0 100644
--- a/packages/Tethering/AndroidManifest.xml
+++ b/packages/Tethering/AndroidManifest.xml
@@ -25,5 +25,11 @@
         android:process="com.android.networkstack.process"
         android:extractNativeLibs="false"
         android:persistent="true">
+        <service android:name="com.android.server.connectivity.tethering.TetheringService"
+                 android:permission="android.permission.MAINLINE_NETWORK_STACK">
+            <intent-filter>
+                <action android:name="android.net.ITetheringConnector"/>
+            </intent-filter>
+        </service>
     </application>
 </manifest>
diff --git a/packages/Tethering/AndroidManifest_InProcess.xml b/packages/Tethering/AndroidManifest_InProcess.xml
new file mode 100644
index 0000000..28d405c
--- /dev/null
+++ b/packages/Tethering/AndroidManifest_InProcess.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.tethering.inprocess"
+          android:sharedUserId="android.uid.system"
+          android:process="system">
+    <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
+    <application>
+        <!-- TODO: Using MAINLINE_NETWORK_STACK instead of NETWORK_STACK when tethering run in the
+                   same process with networkstack -->
+        <service android:name="com.android.server.connectivity.tethering.TetheringService"
+                 android:process="system"
+                 android:permission="android.permission.NETWORK_STACK">
+            <intent-filter>
+                <action android:name="android.net.ITetheringConnector.InProcess"/>
+            </intent-filter>
+        </service>
+    </application>
+</manifest>
diff --git a/packages/Tethering/CleanSpec.mk b/packages/Tethering/CleanSpec.mk
new file mode 100644
index 0000000..70db351
--- /dev/null
+++ b/packages/Tethering/CleanSpec.mk
@@ -0,0 +1,52 @@
+# 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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# *****************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER
+# *****************************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/Tethering)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/InProcessTethering)
+
+# ******************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
+# ******************************************************************
diff --git a/packages/Tethering/apex/Android.bp b/packages/Tethering/apex/Android.bp
new file mode 100644
index 0000000..bca01ebd
--- /dev/null
+++ b/packages/Tethering/apex/Android.bp
@@ -0,0 +1,35 @@
+//
+// 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.tethering.apex",
+    apps: ["Tethering"],
+    manifest: "manifest.json",
+    key: "com.android.tethering.apex.key",
+
+    androidManifest: "AndroidManifest.xml",
+}
+
+apex_key {
+    name: "com.android.tethering.apex.key",
+    public_key: "com.android.tethering.apex.avbpubkey",
+    private_key: "com.android.tethering.apex.pem",
+}
+
+android_app_certificate {
+    name: "com.android.tethering.apex.certificate",
+    certificate: "com.android.tethering.apex",
+}
diff --git a/packages/Tethering/apex/AndroidManifest.xml b/packages/Tethering/apex/AndroidManifest.xml
new file mode 100644
index 0000000..7769b79
--- /dev/null
+++ b/packages/Tethering/apex/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+  package="com.android.tethering.apex">
+  <!-- APEX does not have classes.dex -->
+  <application android:hasCode="false" />
+  <!-- b/145383354: Current minSdk is locked to Q for development cycle, lock it to next version
+                    before ship. -->
+  <uses-sdk
+      android:minSdkVersion="29"
+      android:targetSdkVersion="29"
+  />
+</manifest>
diff --git a/packages/Tethering/apex/com.android.tethering.apex.avbpubkey b/packages/Tethering/apex/com.android.tethering.apex.avbpubkey
new file mode 100644
index 0000000..9c87111
--- /dev/null
+++ b/packages/Tethering/apex/com.android.tethering.apex.avbpubkey
Binary files differ
diff --git a/packages/Tethering/apex/com.android.tethering.apex.pem b/packages/Tethering/apex/com.android.tethering.apex.pem
new file mode 100644
index 0000000..a8cd12e
--- /dev/null
+++ b/packages/Tethering/apex/com.android.tethering.apex.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKQIBAAKCAgEAwloHpMmwszNBEgUVion141BTvF/oJ5g5DlQIYBtmht4tSpc3
+6elWXd+dhMzFxf/RkxSNRsU+dhD11cPKGp9nUYQQGrHEf3xEKwAHJKRMq26TkJ3o
+1TwOO70TaRKKA4ThNiM3VFDX2vy1ijArhZDIBTGVJCUl9HOHiO+ZJG5DKCx3KXbO
+QWz3c+Lbprr1L76dwIsl5kuoAFwgG0J+9BZhHEzIG1lVpGG7RRLxc8eDIxNN/oKT
+gPYBcOxFYqOECKGBBvElf6MxdRv6xG7gooALY2/HDMYUjAJSOosfwzeymugCzMhK
+e+6CSTAaEfUzuVZvMc2qnd1ly7zpLo9x+TOdH5LEVZpSwqmu2n5bqrUnSEAJUvMz
+SSw0YbsLWJZuTiTV7lecSITgqsmwuZyDexDmUkDQChzrTixsQV6S8vsh/FanjWoi
+zBlPneX8Q7/LME3hxHyLbrabxX0zWiyj8iM9h/8Y4mpO/MjEmmavglTAP4J8zrKD
+FBsntCoch9I49IpYBuO6NfKw1h7AUpLf8gARAjFjRxiJVcSgGY/Wt4/pBzJ57T5g
+xPvqxfpPQP0OA2CT8LqqzZIR8jXs8/TquvwLkkY2kRRPXx+azd5oU2A0uonrUY31
+Bc1obfmWPuEMz9bO/i06ETHuWPd4RiUNaB8qEmjYuKJfhv72YNcRwhrAYJECAwEA
+AQKCAgAaQn3b5yCH5fn5zFQPxvpBP35A6ph8mRXEeNg03B7rRCPMe0gjw9JWlrs6
+0Uw7p4gSnmlEUaxR2ZLN0kmBdV5JZlWitbg+HXU8diGA8u4lD6jCloN6JEYsDi0M
+OmQJe6/OV83HB7FStmh1BnMq9dgA06U6IAbT07RRbUY85OUQDYoAQTw3HNkGgHV7
+PrGYROIdvO9fAYPuoIP6Cu8KXee7Iii7gUOQFWBvQdL7+M4gNCCKrevuNc8WCeaK
+IFvbqq67WGPfrhYlo6UrW2vgqPpg8h5r/GuUS0/+9wNQpjrssUKHltxxiFV0PBqZ
+qI7XkPUvPoG6GMsDT0AWeW1F5ZJqEGPN67Xek0BCD0cpUli+nHD0yWGVHtkpHU2D
+qUOZdB2COfBuXRdW1LsYNPg8YjTCPsmGhISLTwiTNcZJeTxoK1y0CcVW9d7Af2aD
+lYzCegscQlXkSZiFj9s90Vd3KdD2XKrH/ADxzsOxQJ89ka004efdQa5/MKs9aChG
+/5XrwBEfN4O92OjY7KqXUAwB7CcVzNymOjD6r07LM24zbkRpwwXlkP0wmjsHBXkh
+8p0ISmY9QRdvhBgYmFmoPWZncM0zym9LI8atBs4CijQ7JjuOQ8HgHg+Se2eppWfe
+t8r6TVkDB8JeNAMxjX9q0G7icf3JjlIrgERZfyXLmpduR9NdkQKCAQEA5rp2fSKh
+RwihHNtJhNktFJuLR9OA++vyfjqhWnB8CrLPo3//LGWW/+WBr8EwXi/76hQpeKlf
+u8SmkTtxIHlTP2Brh2koh1Qf8HKzPHGjZeDFOoVPKHPqe3nV+cv3srd1mS0Eq3BA
+ZFQq+l61f2iiTZKxDroCahNEa8VMzirW6nKb5xhyMPHXgncCUdphHbwAGatas6be
+RUFg4ChH8BwX6jYw7leRUy2K6OqEl0fckT4Laitlb/ezKtwmD4PPE95q5hH0v3SO
+wetHWafiNrOXPn2wQqBrI2y+AfbTjNmQiaIPgcFKAQ7V3n+c3XfGZ9Xfv4L8m/wo
+RZ4ika1zur021QKCAQEA16OUBPA7BnWd+RJFri2kJBG5JZElaV9chO2ZHcXUbFR9
+HIPkWN19bJbki8Ca0w8FUQuS/M7JeeFjoZ194NlczbR899GVmb0X2AUKXilMacs3
+IONxIDczx3KFtsge8ewXRAjQvgE7M3NpmmJfPLPog7spMCbUIxbc3jzjiZgB/J1s
+WytlUTUY/Zy4V1wujkoydgK2KcHcEWG2oIy7EP0RwnL1NhTksXOtBH6+MoRMAT+H
+fcBK6yfJBNBRQzJ0PdkCCLdQPN1VtwRlWjPXZ3ey4fWvZ399wSLUkM2V1jB4GcOZ
++DAgtwFKs9+HfOdV42GgFWFcjP+bkM3bcdrQFnmYzQKCAQAQnf1KpePXqddwrJpu
+5vVINquhUKpJeoTMcoyMZu2IF7i8nctS9z4Yz/63GcLSBcKu6STTe99ZNqCIdS+A
+lzxXpCoaZoh0tqpWNuyRvd12yOlrfY5l63NH0U6H3xjH1k6x6XwcnMkGcMlnnsqT
+koWd8KKv3NWvrhOPb3ZIou03lWmFC02uGLzcuJWCL6gu7AtVzfGKXspDUqIXgs8r
+i9ptE9oSUFw3EWCfxcQm4RYRn9ZSny1/EufkflZ/Z47Sb4Jjb4ehAlQFw1wwKNcx
++V07MvIu2j7dHkfQ/GXgDwtJ3lIfljwuN1NP4wD5Mlcnw0+KC3UGBvMfkHQM6eEb
+4eTBAoIBAQDWfZsqHlpX3n431XkB+9wdFJP5ThrMaVJ51mxLNRBKgO/BgV+NFSNA
+9AZ5DCf0cCh1qPGYDYhSd2LGywT+trac1j7Hse0AcxpYgQsDBkk/oic/y3wm80HJ
+zZw7Z2uAb7nkrnATzt24G8CbE+ZvVvScs3oQr06raH5hgGdD4bN4No4lUVECKbKl
+8VFbdBHK7vqqb6AKgQ4JLAygPduE1nTn2bkXBklESS98HSXK0dVYGH0JFFBw/63v
+39Y05ObC7iwbx1tEb1RnKzQ1OQO1o1aHc/35ENNhXOfa8ONtneCYn/ty50xjPCG2
+MU1vbBv+hIjbO3D3vvhaXKk+4svAz0qxAoIBAQC84FJEjKHJHx17jLeoTuDfuxwX
+6bOQrI3nHbtnFRvPrMryWRDtHLv89Zma3o68/n4vTn5+AnvgYMZifOYlTlIPxinH
+tlE+qCD8KBXUlZdrc+5GGM18lp5tF3Ro4LireH+OhiOAWawaSzDIDYdiR6Kz9NU+
+SjcHKjDObeM6iMEukoaRsufMedpUSrnbzMraAJgBZGay1NZs/o8Icl3OySYPZWEK
+MJxVBMXU9QcUp2GEioYd/eNuP9rwyjq/EIUDJbP2vESAe6+FdGbIgvyYTV/gnKaH
+GcvyMNVZbCMp/wCYNonjlu+18m2w+pVs2uuZLqORkrKYhisK83TKxh4YOWJh
+-----END RSA PRIVATE KEY-----
diff --git a/packages/Tethering/apex/com.android.tethering.apex.pk8 b/packages/Tethering/apex/com.android.tethering.apex.pk8
new file mode 100644
index 0000000..5663246
--- /dev/null
+++ b/packages/Tethering/apex/com.android.tethering.apex.pk8
Binary files differ
diff --git a/packages/Tethering/apex/com.android.tethering.apex.x509.pem b/packages/Tethering/apex/com.android.tethering.apex.x509.pem
new file mode 100644
index 0000000..a5e9401
--- /dev/null
+++ b/packages/Tethering/apex/com.android.tethering.apex.x509.pem
@@ -0,0 +1,36 @@
+-----BEGIN CERTIFICATE-----
+MIIGMzCCBBugAwIBAgIUXVtoDaXanhs7ma8VIICambMkj5UwDQYJKoZIhvcNAQEL
+BQAwgacxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
+DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
+b2lkMSMwIQYDVQQDDBpjb20uYW5kcm9pZC50ZXRoZXJpbmcuYXBleDEiMCAGCSqG
+SIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAgFw0xOTExMjgwNjU4MTRaGA80
+NzU3MTAyNDA2NTgxNFowgacxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9y
+bmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAw
+DgYDVQQLDAdBbmRyb2lkMSMwIQYDVQQDDBpjb20uYW5kcm9pZC50ZXRoZXJpbmcu
+YXBleDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCAiIwDQYJ
+KoZIhvcNAQEBBQADggIPADCCAgoCggIBANwzufMBdOj9XlNwiX+bXl/94G0DklWW
+nzob0jPlubCFfRqYkjCf2eOd28Mu/O1pOBcvobnrs9OTpGzcHkz2h58L5/0UMVTS
+tBugwCE49XF5FHawqVHNZE+s5tDmnp2cufhNc5HXHY4oZKh80/WVdbcKxiLjSY2T
+PgRAfB6E6XByKD3t1cSsc3liRVKADoJOVDvmF+xnyvSV/SN38bvTQk9aVs95mj0W
+yov6gzXBnqN7iQlvkhcijZBnFWxvoNbJ5KFy1abYOrm+ueXje4BcNhVOeRMb4E9N
+eo7+9k1GEI7TYG7laNNcp7UJ1IXCJzv/wBFKRg3f1HB3unKfx2rtKerDnVsr3o7V
+KProkgRNKNhhQ6opNguiH1YMzKpWMaC988n4AQPryPdIOmVIxIC5jJrixdxgzDXT
+qeiwFiXis291uyls08B03PQFlY9oWaY9P8s+4hIUjB6rLl+XZXsLDtDFxXeJ97NB
+8XZN1gBJoBoLknFs0C4LKpmJZB/EBao9tXV9dL/5lydRo6HzQDpjW8QX06CTUM6z
+Lr3LVelhqbsuZsV42yBKl+/LfrvNjBLEPdSevt2oMrlJW7m4iSNaMtDtJ2Oy8fA5
+WSIgLWuMbkaFDza3JzwiMzxbtbJHYiy6rY7aVywo3Vqwr1+KO3cq4eLQq62zUjRY
+e6KJwvgE2YmpAgMBAAGjUzBRMB0GA1UdDgQWBBQ8h1oF5JfKFmJCN8nfimbUK+IR
+wjAfBgNVHSMEGDAWgBQ8h1oF5JfKFmJCN8nfimbUK+IRwjAPBgNVHRMBAf8EBTAD
+AQH/MA0GCSqGSIb3DQEBCwUAA4ICAQAP5hIkAxSyt9hRafMKiFlmXcL277bgoxNd
+qGZYbdcCFjfvM2r0QQcM/K7x2ZslFe7mJSzcyMifpm4YQTEo2yYbzKItXQV+eV1K
+9RNksRGFG9umsdWaSHhfQmcmxtr2nu9rGAgxy5OQFtyXmJPUPEM2cb/YeILwYhuQ
+Ux3kaj/fxGltX1JBag7HnMzCTZK++fRo5nqFVOJQgJH8ZpuzGeM9kZvP1+b55046
+PhSnlqmZoKhG4i5POPvvZvaakh/lM3x/N7lIlSaQpCGf7jmldni4L0/GenULVKzH
+iN73aBfh4GEvE0HRcOoH3L7V6kc3WMMLve0chZBHpoVYbzUJEJOUL4yrmwEehqtf
+xm4vlYg3vqtcE3UnU/UGdMb16t77Nz88LlpBY5ierIt0jZMU0M81ppRhr1uiD2Lj
+091sEA0Bxcw/6Q8QNF2eR7SG7Qwipnms+lw6Vcxve+7DdTrdEA0k3XgpdXp8Ya+2
+PAp9SLVp1UHiGq3qD9Jvm34QmlUWAIUTHZs3DSgs1y3K5eyw/cnzTvUUOljc/n2y
+VF0FFZtJ1dVLrzQ80Ik7apEXpBqkgBGV04/L3QYk4C0/sP+1yk6zjeeeAvDtUcHS
+gLtjAfacQl/kwfVQWfrF7VByLcivApC6EUdvT3cURM5DfZRQ4RcKr1D61VYPnNRH
++/NVbMObwQ==
+-----END CERTIFICATE-----
diff --git a/packages/Tethering/apex/manifest.json b/packages/Tethering/apex/manifest.json
new file mode 100644
index 0000000..078302a
--- /dev/null
+++ b/packages/Tethering/apex/manifest.json
@@ -0,0 +1,4 @@
+{
+  "name": "com.android.tethering.apex",
+  "version": 300000000
+}
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
index 5b01b1e..adc5a72 100644
--- a/packages/Tethering/common/TetheringLib/Android.bp
+++ b/packages/Tethering/common/TetheringLib/Android.bp
@@ -18,8 +18,12 @@
 aidl_interface {
     name: "tethering-aidl-interfaces",
     local_include_dir: "src",
+    include_dirs: ["frameworks/base/core/java"], // For framework parcelables.
     srcs: [
+        "src/android/net/ITetherInternalCallback.aidl",
         "src/android/net/ITetheringConnector.aidl",
+        "src/android/net/TetheringConfigurationParcel.aidl",
+        "src/android/net/TetherStatesParcel.aidl",
     ],
     backend: {
         ndk: {
@@ -33,8 +37,15 @@
 
 java_library {
     name: "tethering-client",
-    platform_apis: true,
+    sdk_version: "system_current",
     static_libs: [
         "tethering-aidl-interfaces-java",
     ],
 }
+
+// This is temporary file group which would be removed after TetheringManager is built
+// into tethering-client. Will be done by aosp/1156906.
+filegroup {
+    name: "tethering-manager",
+    srcs: ["src/android/net/TetheringManager.java"],
+}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/ITetherInternalCallback.aidl b/packages/Tethering/common/TetheringLib/src/android/net/ITetherInternalCallback.aidl
new file mode 100644
index 0000000..abb00e8
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/src/android/net/ITetherInternalCallback.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.Network;
+import android.net.TetheringConfigurationParcel;
+import android.net.TetherStatesParcel;
+
+/**
+ * Callback class for receiving tethering changed events
+ * @hide
+ */
+oneway interface ITetherInternalCallback
+{
+    void onUpstreamChanged(in Network network);
+    void onConfigurationChanged(in TetheringConfigurationParcel config);
+    void onTetherStatesChanged(in TetherStatesParcel states);
+    void onCallbackCreated(in Network network, in TetheringConfigurationParcel config,
+            in TetherStatesParcel states);
+}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
index 443481e..bfe502f 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
+++ b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
@@ -15,6 +15,23 @@
  */
 package android.net;
 
+import android.net.ITetherInternalCallback;
+import android.os.ResultReceiver;
+
 /** @hide */
 oneway interface ITetheringConnector {
+    void tether(String iface);
+
+    void untether(String iface);
+
+    void setUsbTethering(boolean enable);
+
+    void startTethering(int type, in ResultReceiver receiver, boolean showProvisioningUi);
+
+    void stopTethering(int type);
+
+    void requestLatestTetheringEntitlementResult(int type, in ResultReceiver receiver,
+            boolean showEntitlementUi);
+
+    void registerTetherInternalCallback(ITetherInternalCallback callback);
 }
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetherStatesParcel.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetherStatesParcel.aidl
new file mode 100644
index 0000000..3d842b3
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetherStatesParcel.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+/**
+ * Status details for tethering downstream interfaces.
+ * {@hide}
+ */
+parcelable TetherStatesParcel {
+    String[] availableList;
+    String[] tetheredList;
+    String[] localOnlyList;
+    String[] erroredIfaceList;
+    // List of Last error code corresponding to each errored iface in erroredIfaceList. */
+    // TODO: Improve this as b/143122247.
+    int[] lastErrorList;
+}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringConfigurationParcel.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConfigurationParcel.aidl
new file mode 100644
index 0000000..89f3813
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConfigurationParcel.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+/**
+ * Configuration details for tethering.
+ * @hide
+ */
+parcelable TetheringConfigurationParcel {
+    int subId;
+    String[] tetherableUsbRegexs;
+    String[] tetherableWifiRegexs;
+    String[] tetherableBluetoothRegexs;
+    boolean isDunRequired;
+    boolean chooseUpstreamAutomatically;
+    int[] preferredUpstreamIfaceTypes;
+    String[] legacyDhcpRanges;
+    String[] defaultIPv4DNS;
+    boolean enableLegacyDhcpServer;
+    String[] provisioningApp;
+    String provisioningAppNoUi;
+    int provisioningCheckPeriod;
+}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
new file mode 100644
index 0000000..eb0d443
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net;
+
+import static android.Manifest.permission.NETWORK_STACK;
+import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.util.SharedLog;
+import android.os.ConditionVariable;
+import android.os.IBinder;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.PrintWriter;
+import java.util.StringJoiner;
+
+/**
+ * Service used to communicate with the tethering, which is running in a separate module.
+ * @hide
+ */
+public class TetheringManager {
+    private static final String TAG = TetheringManager.class.getSimpleName();
+
+    private static TetheringManager sInstance;
+
+    @Nullable
+    private ITetheringConnector mConnector;
+    private TetherInternalCallback mCallback;
+    private Network mTetherUpstream;
+    private TetheringConfigurationParcel mTetheringConfiguration;
+    private TetherStatesParcel mTetherStatesParcel;
+
+    private final RemoteCallbackList<ITetheringEventCallback> mTetheringEventCallbacks =
+            new RemoteCallbackList<>();
+    @GuardedBy("mLog")
+    private final SharedLog mLog = new SharedLog(TAG);
+
+    private TetheringManager() { }
+
+    /**
+     * Get the TetheringManager singleton instance.
+     */
+    public static synchronized TetheringManager getInstance() {
+        if (sInstance == null) {
+            sInstance = new TetheringManager();
+        }
+        return sInstance;
+    }
+
+    private class TetheringConnection implements
+            ConnectivityModuleConnector.ModuleServiceCallback {
+        @Override
+        public void onModuleServiceConnected(@NonNull IBinder service) {
+            logi("Tethering service connected");
+            registerTetheringService(service);
+        }
+    }
+
+    private void registerTetheringService(@NonNull IBinder service) {
+        final ITetheringConnector connector = ITetheringConnector.Stub.asInterface(service);
+
+        log("Tethering service registered");
+
+        // Currently TetheringManager instance is only used by ConnectivityService and mConnector
+        // only expect to assign once when system server start and bind tethering service.
+        // STOPSHIP: Change mConnector to final before TetheringManager put into boot classpath.
+        mConnector = connector;
+        mCallback = new TetherInternalCallback();
+        try {
+            mConnector.registerTetherInternalCallback(mCallback);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    private class TetherInternalCallback extends ITetherInternalCallback.Stub {
+        private final ConditionVariable mWaitForCallback = new ConditionVariable(false);
+        private static final int EVENT_CALLBACK_TIMEOUT_MS = 60_000;
+
+        @Override
+        public void onUpstreamChanged(Network network) {
+            mTetherUpstream = network;
+            reportUpstreamChanged(network);
+        }
+
+        @Override
+        public void onConfigurationChanged(TetheringConfigurationParcel config) {
+            mTetheringConfiguration = config;
+        }
+
+        @Override
+        public void onTetherStatesChanged(TetherStatesParcel states) {
+            mTetherStatesParcel = states;
+        }
+
+        @Override
+        public void onCallbackCreated(Network network, TetheringConfigurationParcel config,
+                TetherStatesParcel states) {
+            mTetherUpstream = network;
+            mTetheringConfiguration = config;
+            mTetherStatesParcel = states;
+            mWaitForCallback.open();
+        }
+
+        boolean awaitCallbackCreation() {
+            return mWaitForCallback.block(EVENT_CALLBACK_TIMEOUT_MS);
+        }
+    }
+
+    private void reportUpstreamChanged(Network network) {
+        final int length = mTetheringEventCallbacks.beginBroadcast();
+        try {
+            for (int i = 0; i < length; i++) {
+                try {
+                    mTetheringEventCallbacks.getBroadcastItem(i).onUpstreamChanged(network);
+                } catch (RemoteException e) {
+                    // Not really very much to do here.
+                }
+            }
+        } finally {
+            mTetheringEventCallbacks.finishBroadcast();
+        }
+    }
+
+    /**
+     * Start the tethering service. Should be called only once on device startup.
+     *
+     * <p>This method will start the tethering service either in the network stack process,
+     * or inside the system server on devices that do not support the tethering module.
+     *
+     * {@hide}
+     */
+    public void start() {
+        // Using MAINLINE_NETWORK_STACK permission after cutting off the dpendency of system server.
+        ConnectivityModuleConnector.getInstance().startModuleService(
+                ITetheringConnector.class.getName(), NETWORK_STACK,
+                new TetheringConnection());
+        log("Tethering service start requested");
+    }
+
+    /**
+     * Attempt to tether the named interface.  This will setup a dhcp server
+     * on the interface, forward and NAT IP v4 packets and forward DNS requests
+     * to the best active upstream network interface.  Note that if no upstream
+     * IP network interface is available, dhcp will still run and traffic will be
+     * allowed between the tethered devices and this device, though upstream net
+     * access will of course fail until an upstream network interface becomes
+     * active. Note: return value do not have any meaning. It is better to use
+     * #getTetherableIfaces() to ensure corresponding interface is available for
+     * tethering before calling #tether().
+     *
+     * @deprecated The only usages should be in PanService and Wifi P2P which
+     * need direct access.
+     *
+     * {@hide}
+     */
+    @Deprecated
+    public int tether(@NonNull String iface) {
+        try {
+            mConnector.tether(iface);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+        return TETHER_ERROR_NO_ERROR;
+    }
+
+    /**
+     * Stop tethering the named interface.
+     *
+     * @deprecated
+     * {@hide}
+     */
+    @Deprecated
+    public int untether(@NonNull String iface) {
+        try {
+            mConnector.untether(iface);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+        return TETHER_ERROR_NO_ERROR;
+    }
+
+    /**
+     * Attempt to both alter the mode of USB and Tethering of USB. WARNING: New client should not
+     * use this API anymore. All clients should use #startTethering or #stopTethering which
+     * encapsulate proper entitlement logic. If the API is used and an entitlement check is needed,
+     * downstream USB tethering will be enabled but will not have any upstream.
+     *
+     * @deprecated
+     * {@hide}
+     */
+    @Deprecated
+    public int setUsbTethering(boolean enable) {
+        try {
+            mConnector.setUsbTethering(enable);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+        return TETHER_ERROR_NO_ERROR;
+    }
+
+    /**
+     * Starts tethering and runs tether provisioning for the given type if needed. If provisioning
+     * fails, stopTethering will be called automatically.
+     *
+     * {@hide}
+     */
+    // TODO: improve the usage of ResultReceiver, b/145096122
+    public void startTethering(int type, @NonNull ResultReceiver receiver,
+            boolean showProvisioningUi) {
+        try {
+            mConnector.startTethering(type, receiver, showProvisioningUi);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Stops tethering for the given type. Also cancels any provisioning rechecks for that type if
+     * applicable.
+     *
+     * {@hide}
+     */
+    public void stopTethering(int type) {
+        try {
+            mConnector.stopTethering(type);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Request the latest value of the tethering entitlement check.
+     *
+     * Note: Allow privileged apps who have TETHER_PRIVILEGED permission to access. If it turns
+     * out some such apps are observed to abuse this API, change to per-UID limits on this API
+     * if it's really needed.
+     */
+    // TODO: improve the usage of ResultReceiver, b/145096122
+    public void requestLatestTetheringEntitlementResult(int type, @NonNull ResultReceiver receiver,
+            boolean showEntitlementUi) {
+        try {
+            mConnector.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Register tethering event callback.
+     *
+     * {@hide}
+     */
+    public void registerTetheringEventCallback(@NonNull ITetheringEventCallback callback) {
+        mTetheringEventCallbacks.register(callback);
+    }
+
+    /**
+     * Unregister tethering event callback.
+     *
+     * {@hide}
+     */
+    public void unregisterTetheringEventCallback(@NonNull ITetheringEventCallback callback) {
+        mTetheringEventCallbacks.unregister(callback);
+    }
+
+    /**
+     * Get a more detailed error code after a Tethering or Untethering
+     * request asynchronously failed.
+     *
+     * {@hide}
+     */
+    public int getLastTetherError(@NonNull String iface) {
+        if (!mCallback.awaitCallbackCreation()) {
+            throw new NullPointerException("callback was not ready yet");
+        }
+        if (mTetherStatesParcel == null) return TETHER_ERROR_NO_ERROR;
+
+        int i = 0;
+        for (String errored : mTetherStatesParcel.erroredIfaceList) {
+            if (iface.equals(errored)) return mTetherStatesParcel.lastErrorList[i];
+
+            i++;
+        }
+        return TETHER_ERROR_NO_ERROR;
+    }
+
+    /**
+     * Get the list of regular expressions that define any tetherable
+     * USB network interfaces.  If USB tethering is not supported by the
+     * device, this list should be empty.
+     *
+     * {@hide}
+     */
+    public @NonNull String[] getTetherableUsbRegexs() {
+        if (!mCallback.awaitCallbackCreation()) {
+            throw new NullPointerException("callback was not ready yet");
+        }
+        return mTetheringConfiguration.tetherableUsbRegexs;
+    }
+
+    /**
+     * Get the list of regular expressions that define any tetherable
+     * Wifi network interfaces.  If Wifi tethering is not supported by the
+     * device, this list should be empty.
+     *
+     * {@hide}
+     */
+    public @NonNull String[] getTetherableWifiRegexs() {
+        if (!mCallback.awaitCallbackCreation()) {
+            throw new NullPointerException("callback was not ready yet");
+        }
+        return mTetheringConfiguration.tetherableWifiRegexs;
+    }
+
+    /**
+     * Get the list of regular expressions that define any tetherable
+     * Bluetooth network interfaces.  If Bluetooth tethering is not supported by the
+     * device, this list should be empty.
+     *
+     * {@hide}
+     */
+    public @NonNull String[] getTetherableBluetoothRegexs() {
+        if (!mCallback.awaitCallbackCreation()) {
+            throw new NullPointerException("callback was not ready yet");
+        }
+        return mTetheringConfiguration.tetherableBluetoothRegexs;
+    }
+
+    /**
+     * Get the set of tetherable, available interfaces.  This list is limited by
+     * device configuration and current interface existence.
+     *
+     * {@hide}
+     */
+    public @NonNull String[] getTetherableIfaces() {
+        if (!mCallback.awaitCallbackCreation()) {
+            throw new NullPointerException("callback was not ready yet");
+        }
+        if (mTetherStatesParcel == null) return new String[0];
+        return mTetherStatesParcel.availableList;
+    }
+
+    /**
+     * Get the set of tethered interfaces.
+     *
+     * {@hide}
+     */
+    public @NonNull String[] getTetheredIfaces() {
+        if (!mCallback.awaitCallbackCreation()) {
+            throw new NullPointerException("callback was not ready yet");
+        }
+        if (mTetherStatesParcel == null) return new String[0];
+        return mTetherStatesParcel.tetheredList;
+    }
+
+    /**
+     * Get the set of interface names which attempted to tether but
+     * failed.
+     *
+     * {@hide}
+     */
+    public @NonNull String[] getTetheringErroredIfaces() {
+        if (!mCallback.awaitCallbackCreation()) {
+            throw new NullPointerException("callback was not ready yet");
+        }
+        if (mTetherStatesParcel == null) return new String[0];
+        return mTetherStatesParcel.erroredIfaceList;
+    }
+
+    /**
+     * Get the set of tethered dhcp ranges.
+     *
+     * @deprecated This API just return the default value which is not used in DhcpServer.
+     * {@hide}
+     */
+    @Deprecated
+    public @NonNull String[] getTetheredDhcpRanges() {
+        if (!mCallback.awaitCallbackCreation()) {
+            throw new NullPointerException("callback was not ready yet");
+        }
+        return mTetheringConfiguration.legacyDhcpRanges;
+    }
+
+    /**
+     * Check if the device allows for tethering.
+     *
+     * {@hide}
+     */
+    public boolean hasTetherableConfiguration() {
+        if (!mCallback.awaitCallbackCreation()) {
+            throw new NullPointerException("callback was not ready yet");
+        }
+        final boolean hasDownstreamConfiguration =
+                (mTetheringConfiguration.tetherableUsbRegexs.length != 0)
+                || (mTetheringConfiguration.tetherableWifiRegexs.length != 0)
+                || (mTetheringConfiguration.tetherableBluetoothRegexs.length != 0);
+        final boolean hasUpstreamConfiguration =
+                (mTetheringConfiguration.preferredUpstreamIfaceTypes.length != 0)
+                || mTetheringConfiguration.chooseUpstreamAutomatically;
+
+        return hasDownstreamConfiguration && hasUpstreamConfiguration;
+    }
+
+    /**
+     * Log a message in the local log.
+     */
+    private void log(@NonNull String message) {
+        synchronized (mLog) {
+            mLog.log(message);
+        }
+    }
+
+    /**
+     * Log a condition that should never happen.
+     */
+    private void logWtf(@NonNull String message, @Nullable Throwable e) {
+        Slog.wtf(TAG, message);
+        synchronized (mLog) {
+            mLog.e(message, e);
+        }
+    }
+
+    /**
+     * Log a ERROR level message in the local and system logs.
+     */
+    private void loge(@NonNull String message, @Nullable Throwable e) {
+        synchronized (mLog) {
+            mLog.e(message, e);
+        }
+    }
+
+    /**
+     * Log a INFO level message in the local and system logs.
+     */
+    private void logi(@NonNull String message) {
+        synchronized (mLog) {
+            mLog.i(message);
+        }
+    }
+
+    /**
+     * Dump TetheringManager logs to the specified {@link PrintWriter}.
+     */
+    public void dump(@NonNull PrintWriter pw) {
+        // dump is thread-safe on SharedLog
+        mLog.dump(null, pw, null);
+
+        pw.print("subId: ");
+        pw.println(mTetheringConfiguration.subId);
+
+        dumpStringArray(pw, "tetherableUsbRegexs",
+                mTetheringConfiguration.tetherableUsbRegexs);
+        dumpStringArray(pw, "tetherableWifiRegexs",
+                mTetheringConfiguration.tetherableWifiRegexs);
+        dumpStringArray(pw, "tetherableBluetoothRegexs",
+                mTetheringConfiguration.tetherableBluetoothRegexs);
+
+        pw.print("isDunRequired: ");
+        pw.println(mTetheringConfiguration.isDunRequired);
+
+        pw.print("chooseUpstreamAutomatically: ");
+        pw.println(mTetheringConfiguration.chooseUpstreamAutomatically);
+
+        dumpStringArray(pw, "legacyDhcpRanges", mTetheringConfiguration.legacyDhcpRanges);
+        dumpStringArray(pw, "defaultIPv4DNS", mTetheringConfiguration.defaultIPv4DNS);
+
+        dumpStringArray(pw, "provisioningApp", mTetheringConfiguration.provisioningApp);
+        pw.print("provisioningAppNoUi: ");
+        pw.println(mTetheringConfiguration.provisioningAppNoUi);
+
+        pw.print("enableLegacyDhcpServer: ");
+        pw.println(mTetheringConfiguration.enableLegacyDhcpServer);
+
+        pw.println();
+    }
+
+    private static void dumpStringArray(@NonNull PrintWriter pw, @NonNull String label,
+            @Nullable String[] values) {
+        pw.print(label);
+        pw.print(": ");
+
+        if (values != null) {
+            final StringJoiner sj = new StringJoiner(", ", "[", "]");
+            for (String value : values) sj.add(value);
+
+            pw.print(sj.toString());
+        } else {
+            pw.print("null");
+        }
+
+        pw.println();
+    }
+}
diff --git a/packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp b/packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp
index 3eaf488..663154a 100644
--- a/packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp
+++ b/packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp
@@ -145,4 +145,18 @@
             gMethods, NELEM(gMethods));
 }
 
+extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
+    JNIEnv *env;
+    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+        ALOGE("ERROR: GetEnv failed");
+        return JNI_ERR;
+    }
+
+    if (register_android_server_connectivity_tethering_OffloadHardwareInterface(env) < 0) {
+        return JNI_ERR;
+    }
+
+    return JNI_VERSION_1_6;
+}
+
 }; // namespace android
diff --git a/core/res/res/drawable-hdpi/stat_sys_tether_bluetooth.png b/packages/Tethering/res/drawable-hdpi/stat_sys_tether_bluetooth.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_tether_bluetooth.png
rename to packages/Tethering/res/drawable-hdpi/stat_sys_tether_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_tether_general.png b/packages/Tethering/res/drawable-hdpi/stat_sys_tether_general.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_tether_general.png
rename to packages/Tethering/res/drawable-hdpi/stat_sys_tether_general.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_tether_usb.png b/packages/Tethering/res/drawable-hdpi/stat_sys_tether_usb.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_tether_usb.png
rename to packages/Tethering/res/drawable-hdpi/stat_sys_tether_usb.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/stat_sys_tether_bluetooth.png b/packages/Tethering/res/drawable-ldpi/stat_sys_tether_bluetooth.png
similarity index 100%
rename from core/res/res/drawable-ldpi/stat_sys_tether_bluetooth.png
rename to packages/Tethering/res/drawable-ldpi/stat_sys_tether_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/stat_sys_tether_general.png b/packages/Tethering/res/drawable-ldpi/stat_sys_tether_general.png
similarity index 100%
rename from core/res/res/drawable-ldpi/stat_sys_tether_general.png
rename to packages/Tethering/res/drawable-ldpi/stat_sys_tether_general.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/stat_sys_tether_usb.png b/packages/Tethering/res/drawable-ldpi/stat_sys_tether_usb.png
similarity index 100%
rename from core/res/res/drawable-ldpi/stat_sys_tether_usb.png
rename to packages/Tethering/res/drawable-ldpi/stat_sys_tether_usb.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_tether_bluetooth.png b/packages/Tethering/res/drawable-mdpi/stat_sys_tether_bluetooth.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_tether_bluetooth.png
rename to packages/Tethering/res/drawable-mdpi/stat_sys_tether_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_tether_general.png b/packages/Tethering/res/drawable-mdpi/stat_sys_tether_general.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_tether_general.png
rename to packages/Tethering/res/drawable-mdpi/stat_sys_tether_general.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_tether_usb.png b/packages/Tethering/res/drawable-mdpi/stat_sys_tether_usb.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_tether_usb.png
rename to packages/Tethering/res/drawable-mdpi/stat_sys_tether_usb.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_tether_bluetooth.png b/packages/Tethering/res/drawable-xhdpi/stat_sys_tether_bluetooth.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/stat_sys_tether_bluetooth.png
rename to packages/Tethering/res/drawable-xhdpi/stat_sys_tether_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_tether_general.png b/packages/Tethering/res/drawable-xhdpi/stat_sys_tether_general.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/stat_sys_tether_general.png
rename to packages/Tethering/res/drawable-xhdpi/stat_sys_tether_general.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_tether_usb.png b/packages/Tethering/res/drawable-xhdpi/stat_sys_tether_usb.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/stat_sys_tether_usb.png
rename to packages/Tethering/res/drawable-xhdpi/stat_sys_tether_usb.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_tether_bluetooth.png b/packages/Tethering/res/drawable-xxhdpi/stat_sys_tether_bluetooth.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/stat_sys_tether_bluetooth.png
rename to packages/Tethering/res/drawable-xxhdpi/stat_sys_tether_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_tether_general.png b/packages/Tethering/res/drawable-xxhdpi/stat_sys_tether_general.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/stat_sys_tether_general.png
rename to packages/Tethering/res/drawable-xxhdpi/stat_sys_tether_general.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_tether_usb.png b/packages/Tethering/res/drawable-xxhdpi/stat_sys_tether_usb.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/stat_sys_tether_usb.png
rename to packages/Tethering/res/drawable-xxhdpi/stat_sys_tether_usb.png
Binary files differ
diff --git a/packages/Tethering/res/values-af/strings.xml b/packages/Tethering/res/values-af/strings.xml
new file mode 100644
index 0000000..1258805
--- /dev/null
+++ b/packages/Tethering/res/values-af/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Verbinding of Wi-Fi-warmkol aktief"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Tik om op te stel."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Verbinding is gedeaktiveer"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Kontak jou administrateur vir besonderhede"</string>
+</resources>
diff --git a/packages/Tethering/res/values-am/strings.xml b/packages/Tethering/res/values-am/strings.xml
new file mode 100644
index 0000000..9c36192
--- /dev/null
+++ b/packages/Tethering/res/values-am/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"መሰካት ወይም ገባሪ ድረስ ነጥብ"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"ለማዋቀር መታ ያድርጉ።"</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"እንደ ሞደም መሰካት ተሰናክሏል"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"ለዝርዝሮች የእርስዎን አስተዳዳሪ ያነጋግሩ"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ar/strings.xml b/packages/Tethering/res/values-ar/strings.xml
new file mode 100644
index 0000000..9f84ce4
--- /dev/null
+++ b/packages/Tethering/res/values-ar/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"النطاق أو نقطة الاتصال نشطة"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"انقر للإعداد."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"تم إيقاف التوصيل"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"اتصل بالمشرف للحصول على التفاصيل"</string>
+</resources>
diff --git a/packages/Tethering/res/values-as/strings.xml b/packages/Tethering/res/values-as/strings.xml
new file mode 100644
index 0000000..8855822
--- /dev/null
+++ b/packages/Tethering/res/values-as/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"টেডাৰিং বা হটস্প\'ট সক্ৰিয় অৱস্থাত আছে"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"ছেট আপ কৰিবলৈ টিপক।"</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"টেডাৰিং অক্ষম কৰি থোৱা হৈছে"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"সবিশেষ জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক"</string>
+</resources>
diff --git a/packages/Tethering/res/values-az/strings.xml b/packages/Tethering/res/values-az/strings.xml
new file mode 100644
index 0000000..eba50eb
--- /dev/null
+++ b/packages/Tethering/res/values-az/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Tezerinq və ya hotspot aktivdir"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Quraşdırmaq üçün tıklayın."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Birləşmə deaktivdir"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Məlumat üçün adminlə əlaqə saxlayın"</string>
+</resources>
diff --git a/packages/Tethering/res/values-b+sr+Latn/strings.xml b/packages/Tethering/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..5b0e488
--- /dev/null
+++ b/packages/Tethering/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Aktivno povezivanje sa internetom preko mobilnog uređaja ili hotspot"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Dodirnite da biste podesili."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Privezivanje je onemogućeno"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Potražite detalje od administratora"</string>
+</resources>
diff --git a/packages/Tethering/res/values-be/strings.xml b/packages/Tethering/res/values-be/strings.xml
new file mode 100644
index 0000000..5966c71
--- /dev/null
+++ b/packages/Tethering/res/values-be/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"USB-мадэм або хот-спот Wi-Fi актыўныя"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Дакраніцеся, каб наладзіць."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Рэжым мадэма адключаны"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Звярніцеся да адміністратара па падрабязную інфармацыю"</string>
+</resources>
diff --git a/packages/Tethering/res/values-bg/strings.xml b/packages/Tethering/res/values-bg/strings.xml
new file mode 100644
index 0000000..ed58d73
--- /dev/null
+++ b/packages/Tethering/res/values-bg/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Има активна споделена връзка или безжична точка за достъп"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Докоснете, за да настроите."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Функцията за тетъринг е деактивирана"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Свържете се с администратора си за подробности"</string>
+</resources>
diff --git a/packages/Tethering/res/values-bn/strings.xml b/packages/Tethering/res/values-bn/strings.xml
new file mode 100644
index 0000000..8d9880a
--- /dev/null
+++ b/packages/Tethering/res/values-bn/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"টিথারিং বা হটস্পট সক্রিয় আছে"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"সেট-আপ করার জন্য আলতো চাপুন৷"</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"টিথারিং অক্ষম করা আছে"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"বিশদ বিবরণের জন্য প্রশাসকের সাথে যোগাযোগ করুন"</string>
+</resources>
diff --git a/packages/Tethering/res/values-bs/strings.xml b/packages/Tethering/res/values-bs/strings.xml
new file mode 100644
index 0000000..2361b9d
--- /dev/null
+++ b/packages/Tethering/res/values-bs/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Uređaj dijeli vezu ili djeluje kao pristupna tačka"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Dodirnite za postavke"</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Povezivanje putem mobitela je onemogućeno"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Kontaktirajte svog administratora za dodatne detalje"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ca/strings.xml b/packages/Tethering/res/values-ca/strings.xml
new file mode 100644
index 0000000..6752b51
--- /dev/null
+++ b/packages/Tethering/res/values-ca/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Compartició de xarxa o punt d\'accés Wi-Fi activat"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Toca per configurar."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"La compartició de xarxa està desactivada"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Contacta amb el teu administrador per obtenir més informació"</string>
+</resources>
diff --git a/packages/Tethering/res/values-cs/strings.xml b/packages/Tethering/res/values-cs/strings.xml
new file mode 100644
index 0000000..5fdd53a
--- /dev/null
+++ b/packages/Tethering/res/values-cs/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Sdílené připojení nebo hotspot je aktivní."</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Klepnutím zahájíte nastavení."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering je zakázán"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"O podrobnosti požádejte administrátora"</string>
+</resources>
diff --git a/packages/Tethering/res/values-da/strings.xml b/packages/Tethering/res/values-da/strings.xml
new file mode 100644
index 0000000..2775dfa
--- /dev/null
+++ b/packages/Tethering/res/values-da/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Netdeling eller hotspot er aktivt"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Tryk for at konfigurere"</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Netdeling er deaktiveret"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Kontakt din administrator for at få oplysninger"</string>
+</resources>
diff --git a/packages/Tethering/res/values-de/strings.xml b/packages/Tethering/res/values-de/strings.xml
new file mode 100644
index 0000000..9046cd5
--- /dev/null
+++ b/packages/Tethering/res/values-de/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering oder Hotspot aktiv"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Zum Einrichten tippen."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering ist deaktiviert"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Bitte wende dich für weitere Informationen an den Administrator"</string>
+</resources>
diff --git a/packages/Tethering/res/values-el/strings.xml b/packages/Tethering/res/values-el/strings.xml
new file mode 100644
index 0000000..3b9f537
--- /dev/null
+++ b/packages/Tethering/res/values-el/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Πρόσδεση ή σύνδεση σημείου πρόσβασης ενεργή"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Πατήστε για ρύθμιση."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Η σύνδεση είναι απενεργοποιημένη"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Επικοινωνήστε με τον διαχειριστή σας για λεπτομέρειες"</string>
+</resources>
diff --git a/packages/Tethering/res/values-en-rAU/strings.xml b/packages/Tethering/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..56b88a5
--- /dev/null
+++ b/packages/Tethering/res/values-en-rAU/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering or hotspot active"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Tap to set up."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering is disabled"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Contact your admin for details"</string>
+</resources>
diff --git a/packages/Tethering/res/values-en-rCA/strings.xml b/packages/Tethering/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..56b88a5
--- /dev/null
+++ b/packages/Tethering/res/values-en-rCA/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering or hotspot active"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Tap to set up."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering is disabled"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Contact your admin for details"</string>
+</resources>
diff --git a/packages/Tethering/res/values-en-rGB/strings.xml b/packages/Tethering/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..56b88a5
--- /dev/null
+++ b/packages/Tethering/res/values-en-rGB/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering or hotspot active"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Tap to set up."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering is disabled"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Contact your admin for details"</string>
+</resources>
diff --git a/packages/Tethering/res/values-en-rIN/strings.xml b/packages/Tethering/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..56b88a5
--- /dev/null
+++ b/packages/Tethering/res/values-en-rIN/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering or hotspot active"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Tap to set up."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering is disabled"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Contact your admin for details"</string>
+</resources>
diff --git a/packages/Tethering/res/values-en-rXC/strings.xml b/packages/Tethering/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..7f47fc8
--- /dev/null
+++ b/packages/Tethering/res/values-en-rXC/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‏‏‎‏‎‎‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‏‏‎‏‎‎‏‎Tethering or hotspot active‎‏‎‎‏‎"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‎‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‏‎‎‎‏‎Tap to set up.‎‏‎‎‏‎"</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‎‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‎‎‏‎‏‎‏‏‎Tethering is disabled‎‏‎‎‏‎"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‎‏‎‎‏‏‎‎‎‎‎‎‎‏‎‎‏‎‏‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‏‏‎Contact your admin for details‎‏‎‎‏‎"</string>
+</resources>
diff --git a/packages/Tethering/res/values-es-rUS/strings.xml b/packages/Tethering/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..e4618b8
--- /dev/null
+++ b/packages/Tethering/res/values-es-rUS/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Anclaje a red o zona activa conectados"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Presiona para configurar."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Se inhabilitó la conexión mediante dispositivo portátil"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Para obtener más información, comunícate con el administrador"</string>
+</resources>
diff --git a/packages/Tethering/res/values-es/strings.xml b/packages/Tethering/res/values-es/strings.xml
new file mode 100644
index 0000000..8dc1575
--- /dev/null
+++ b/packages/Tethering/res/values-es/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Compartir conexión/Zona Wi-Fi activada"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Toca para configurar."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"La conexión compartida está inhabilitada"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Ponte en contacto con el administrador para obtener más información"</string>
+</resources>
diff --git a/packages/Tethering/res/values-et/strings.xml b/packages/Tethering/res/values-et/strings.xml
new file mode 100644
index 0000000..872c8a7
--- /dev/null
+++ b/packages/Tethering/res/values-et/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Jagamine või kuumkoht on aktiivne"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Puudutage seadistamiseks."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Jagamine on keelatud"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Lisateabe saamiseks võtke ühendust oma administraatoriga"</string>
+</resources>
diff --git a/packages/Tethering/res/values-eu/strings.xml b/packages/Tethering/res/values-eu/strings.xml
new file mode 100644
index 0000000..6c4605e
--- /dev/null
+++ b/packages/Tethering/res/values-eu/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Konexioa partekatzea edo sare publikoa aktibo"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Sakatu konfiguratzeko."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Desgaituta dago konexioa partekatzeko aukera"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Xehetasunak lortzeko, jarri administratzailearekin harremanetan"</string>
+</resources>
diff --git a/packages/Tethering/res/values-fa/strings.xml b/packages/Tethering/res/values-fa/strings.xml
new file mode 100644
index 0000000..bc2ee23
--- /dev/null
+++ b/packages/Tethering/res/values-fa/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"اشتراک‌گذاری اینترنت یا نقطه اتصال فعال"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"برای راه‌اندازی ضربه بزنید."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"اشتراک‌گذاری اینترنت غیرفعال است"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"برای جزئیات، با سرپرستتان تماس بگیرید"</string>
+</resources>
diff --git a/packages/Tethering/res/values-fi/strings.xml b/packages/Tethering/res/values-fi/strings.xml
new file mode 100644
index 0000000..ff0fca6
--- /dev/null
+++ b/packages/Tethering/res/values-fi/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Internetin jakaminen tai yhteyspiste käytössä"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Määritä napauttamalla."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Yhteyden jakaminen poistettu käytöstä"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Kysy lisätietoja järjestelmänvalvojalta."</string>
+</resources>
diff --git a/packages/Tethering/res/values-fr-rCA/strings.xml b/packages/Tethering/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..1f5df0e
--- /dev/null
+++ b/packages/Tethering/res/values-fr-rCA/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Partage de connexion ou point d\'accès sans fil activé"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Touchez pour configurer."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Le partage de connexion est désactivé"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Communiquez avec votre administrateur pour obtenir plus de détails"</string>
+</resources>
diff --git a/packages/Tethering/res/values-fr/strings.xml b/packages/Tethering/res/values-fr/strings.xml
new file mode 100644
index 0000000..daf7c9d
--- /dev/null
+++ b/packages/Tethering/res/values-fr/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Partage de connexion ou point d\'accès sans fil activé"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Appuyez ici pour configurer."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Le partage de connexion est désactivé"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Pour en savoir plus, contactez votre administrateur"</string>
+</resources>
diff --git a/packages/Tethering/res/values-gl/strings.xml b/packages/Tethering/res/values-gl/strings.xml
new file mode 100644
index 0000000..0d16a1d
--- /dev/null
+++ b/packages/Tethering/res/values-gl/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Conexión compartida ou zona wifi activada"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Tocar para configurar."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"A conexión compartida está desactivada"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Contacta co administrador para obter información"</string>
+</resources>
diff --git a/packages/Tethering/res/values-gu/strings.xml b/packages/Tethering/res/values-gu/strings.xml
new file mode 100644
index 0000000..9d6b02f
--- /dev/null
+++ b/packages/Tethering/res/values-gu/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"ટિથરિંગ અથવા હૉટસ્પૉટ સક્રિય"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"સેટ કરવા માટે ટૅપ કરો."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"ટિથરિંગ અક્ષમ કરેલ છે"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"વિગતો માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો"</string>
+</resources>
diff --git a/packages/Tethering/res/values-hi/strings.xml b/packages/Tethering/res/values-hi/strings.xml
new file mode 100644
index 0000000..9c29d9a
--- /dev/null
+++ b/packages/Tethering/res/values-hi/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"टेदरिंग या हॉटस्‍पॉट सक्रिय"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"सेट करने के लिए टैप करें."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"टेदरिंग अक्षम है"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"जानकारी के लिए अपने एडमिन से संपर्क करें"</string>
+</resources>
diff --git a/packages/Tethering/res/values-hr/strings.xml b/packages/Tethering/res/values-hr/strings.xml
new file mode 100644
index 0000000..d0d25bb
--- /dev/null
+++ b/packages/Tethering/res/values-hr/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Ograničenje ili aktivan hotspot"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Dodirnite da biste postavili."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Modemsko je povezivanje onemogućeno"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Obratite se administratoru da biste saznali pojedinosti"</string>
+</resources>
diff --git a/packages/Tethering/res/values-hu/strings.xml b/packages/Tethering/res/values-hu/strings.xml
new file mode 100644
index 0000000..3129659
--- /dev/null
+++ b/packages/Tethering/res/values-hu/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Megosztás vagy aktív hotspot"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Koppintson a beállításhoz."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Az internetmegosztás le van tiltva"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"A részletekért forduljon rendszergazdájához"</string>
+</resources>
diff --git a/packages/Tethering/res/values-hy/strings.xml b/packages/Tethering/res/values-hy/strings.xml
new file mode 100644
index 0000000..8ba6435
--- /dev/null
+++ b/packages/Tethering/res/values-hy/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Մոդեմի ռեժիմը միացված է"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Հպեք՝ կարգավորելու համար:"</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Մոդեմի ռեժիմն անջատված է"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Մանրամասների համար դիմեք ձեր ադմինիստրատորին"</string>
+</resources>
diff --git a/packages/Tethering/res/values-in/strings.xml b/packages/Tethering/res/values-in/strings.xml
new file mode 100644
index 0000000..1e093ab
--- /dev/null
+++ b/packages/Tethering/res/values-in/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering (Penambatan) atau hotspot aktif"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Ketuk untuk menyiapkan."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering dinonaktifkan"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Hubungi admin untuk mengetahui detailnya"</string>
+</resources>
diff --git a/packages/Tethering/res/values-is/strings.xml b/packages/Tethering/res/values-is/strings.xml
new file mode 100644
index 0000000..f5769d5
--- /dev/null
+++ b/packages/Tethering/res/values-is/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Kveikt á tjóðrun eða aðgangsstað"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Ýttu til að setja upp."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Slökkt er á tjóðrun"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Hafðu samband við kerfisstjórann til að fá upplýsingar"</string>
+</resources>
diff --git a/packages/Tethering/res/values-it/strings.xml b/packages/Tethering/res/values-it/strings.xml
new file mode 100644
index 0000000..e0b3724
--- /dev/null
+++ b/packages/Tethering/res/values-it/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering oppure hotspot attivo"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Tocca per impostare."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering disattivato"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Contatta il tuo amministratore per avere informazioni dettagliate"</string>
+</resources>
diff --git a/packages/Tethering/res/values-iw/strings.xml b/packages/Tethering/res/values-iw/strings.xml
new file mode 100644
index 0000000..c002c44
--- /dev/null
+++ b/packages/Tethering/res/values-iw/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"שיתוף אינטרנט פעיל"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"הקש כדי להגדיר."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"שיתוף האינטרנט בין ניידים מושבת"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"לפרטים, יש לפנות למנהל המערכת"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ja/strings.xml b/packages/Tethering/res/values-ja/strings.xml
new file mode 100644
index 0000000..314bde0
--- /dev/null
+++ b/packages/Tethering/res/values-ja/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"テザリングまたはアクセスポイントが有効です"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"タップしてセットアップします。"</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"テザリングは無効に設定されています"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"詳しくは、管理者にお問い合わせください"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ka/strings.xml b/packages/Tethering/res/values-ka/strings.xml
new file mode 100644
index 0000000..7bbd81d
--- /dev/null
+++ b/packages/Tethering/res/values-ka/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"ტეტერინგი ან უსადენო ქსელი აქტიურია"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"შეეხეთ დასაყენებლად."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"ტეტერინგი გათიშულია"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს"</string>
+</resources>
diff --git a/packages/Tethering/res/values-kk/strings.xml b/packages/Tethering/res/values-kk/strings.xml
new file mode 100644
index 0000000..7fd87a1
--- /dev/null
+++ b/packages/Tethering/res/values-kk/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Тетеринг немесе хотспот қосулы"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Реттеу үшін түртіңіз."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Тетеринг өшірілді"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Мәліметтерді әкімшіден алыңыз"</string>
+</resources>
diff --git a/packages/Tethering/res/values-km/strings.xml b/packages/Tethering/res/values-km/strings.xml
new file mode 100644
index 0000000..2f85224
--- /dev/null
+++ b/packages/Tethering/res/values-km/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"ភ្ជាប់ ឬ​ហតស្ពត​សកម្ម"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"ប៉ះដើម្បីកំណត់"</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"ការភ្ជាប់​ត្រូវបានបិទ"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"ទាក់ទងអ្នកគ្រប់គ្រង​របស់អ្នកសម្រាប់​ព័ត៌មានលម្អិត"</string>
+</resources>
diff --git a/packages/Tethering/res/values-kn/strings.xml b/packages/Tethering/res/values-kn/strings.xml
new file mode 100644
index 0000000..f11a83ea
--- /dev/null
+++ b/packages/Tethering/res/values-kn/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"ಟೆಥರಿಂಗ್ ಅಥವಾ ಹಾಟ್‌ಸ್ಪಾಟ್ ಸಕ್ರಿಯವಾಗಿದೆ"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"ಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"ಟೆಥರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"ವಿವರಗಳಿಗಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ko/strings.xml b/packages/Tethering/res/values-ko/strings.xml
new file mode 100644
index 0000000..57f24f5
--- /dev/null
+++ b/packages/Tethering/res/values-ko/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"테더링 또는 핫스팟 사용"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"설정하려면 탭하세요."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"테더링이 사용 중지됨"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"자세한 정보는 관리자에게 문의하세요."</string>
+</resources>
diff --git a/packages/Tethering/res/values-ky/strings.xml b/packages/Tethering/res/values-ky/strings.xml
new file mode 100644
index 0000000..7985485
--- /dev/null
+++ b/packages/Tethering/res/values-ky/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Жалгаштыруу же хотспот жандырылган"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Жөндөө үчүн таптап коюңуз."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Жалгаштыруу функциясы өчүрүлгөн"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Кеңири маалымат үчүн администраторуңузга кайрылыңыз"</string>
+</resources>
diff --git a/packages/Tethering/res/values-lo/strings.xml b/packages/Tethering/res/values-lo/strings.xml
new file mode 100644
index 0000000..78f1585
--- /dev/null
+++ b/packages/Tethering/res/values-lo/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"ເປີດ​ການ​ປ່ອຍ​ສັນຍານ ຫຼື​ຮັອດສະປອດ​ແລ້ວ"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"ແຕະເພື່ອຕັ້ງຄ່າ."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"ການປ່ອຍສັນຍານຖືກປິດໄວ້"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບລາຍລະອຽດ"</string>
+</resources>
diff --git a/packages/Tethering/res/values-lt/strings.xml b/packages/Tethering/res/values-lt/strings.xml
new file mode 100644
index 0000000..ebff8ac
--- /dev/null
+++ b/packages/Tethering/res/values-lt/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Susietas ar aktyvus"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Palieskite, kad nustatytumėte."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Įrenginio kaip modemo naudojimas išjungtas"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Jei reikia išsamios informacijos, susisiekite su administratoriumi"</string>
+</resources>
diff --git a/packages/Tethering/res/values-lv/strings.xml b/packages/Tethering/res/values-lv/strings.xml
new file mode 100644
index 0000000..54d0048
--- /dev/null
+++ b/packages/Tethering/res/values-lv/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Piesaiste vai tīklājs ir aktīvs."</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Pieskarieties, lai iestatītu."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Piesaiste ir atspējota"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Lai iegūtu detalizētu informāciju, sazinieties ar savu administratoru."</string>
+</resources>
diff --git a/packages/Tethering/res/values-mk/strings.xml b/packages/Tethering/res/values-mk/strings.xml
new file mode 100644
index 0000000..0fab8aa
--- /dev/null
+++ b/packages/Tethering/res/values-mk/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Поврзувањето или точката на пристап се активни"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Допрете за поставување."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Врзувањето е оневозможено"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Контактирајте со администраторот за детали"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ml/strings.xml b/packages/Tethering/res/values-ml/strings.xml
new file mode 100644
index 0000000..fd7e556
--- /dev/null
+++ b/packages/Tethering/res/values-ml/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"ടെതറിംഗ് അല്ലെങ്കിൽ ഹോട്ട്സ്‌പോട്ട് സജീവമാണ്"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"സജ്ജമാക്കാൻ ടാപ്പുചെയ്യുക."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"ടെതറിംഗ് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"വിശദവിവരങ്ങൾക്ക് നിങ്ങളുടെ അഡ്മിനെ ബന്ധപ്പെടുക"</string>
+</resources>
diff --git a/packages/Tethering/res/values-mn/strings.xml b/packages/Tethering/res/values-mn/strings.xml
new file mode 100644
index 0000000..4596577
--- /dev/null
+++ b/packages/Tethering/res/values-mn/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Модем болгох эсвэл идэвхтэй цэг болгох"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Тохируулахын тулд товшино уу."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Модем болгох боломжгүй байна"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Дэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу"</string>
+</resources>
diff --git a/packages/Tethering/res/values-mr/strings.xml b/packages/Tethering/res/values-mr/strings.xml
new file mode 100644
index 0000000..85c9ade
--- /dev/null
+++ b/packages/Tethering/res/values-mr/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"टेदरिंग किंवा हॉटस्पॉट सक्रिय"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"सेट करण्यासाठी टॅप करा."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"टेदरिंग बंद आहे"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"तपशीलांसाठी तुमच्या प्रशासकाशी संपर्क साधा"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ms/strings.xml b/packages/Tethering/res/values-ms/strings.xml
new file mode 100644
index 0000000..ec6bdbd
--- /dev/null
+++ b/packages/Tethering/res/values-ms/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Penambatan atau titik panas aktif"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Ketik untuk membuat persediaan."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Penambatan dilumpuhkan"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Hubungi pentadbir anda untuk maklumat lanjut"</string>
+</resources>
diff --git a/packages/Tethering/res/values-my/strings.xml b/packages/Tethering/res/values-my/strings.xml
new file mode 100644
index 0000000..83978b6
--- /dev/null
+++ b/packages/Tethering/res/values-my/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"တဆင့်ပြန်လည်လွှင့်ခြင်း သို့မဟုတ် ဟော့စပေါ့ ဖွင့်ထားသည်"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"စနစ်ထည့်သွင်းရန် တို့ပါ။"</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"မိုဘိုင်းဖုန်းကို မိုဒမ်အဖြစ်သုံးခြင်းအား ပိတ်ထားသည်"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"အသေးစိတ်အချက်အလက်များအတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ"</string>
+</resources>
diff --git a/packages/Tethering/res/values-nb/strings.xml b/packages/Tethering/res/values-nb/strings.xml
new file mode 100644
index 0000000..9abf32d
--- /dev/null
+++ b/packages/Tethering/res/values-nb/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Internettdeling eller trådløs sone er aktiv"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Trykk for å konfigurere."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Internettdeling er slått av"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Ta kontakt med administratoren din for å få mer informasjon"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ne/strings.xml b/packages/Tethering/res/values-ne/strings.xml
new file mode 100644
index 0000000..c886929
--- /dev/null
+++ b/packages/Tethering/res/values-ne/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"टेथर गर्ने वा हटस्पट सक्रिय"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"सेटअप गर्न ट्याप गर्नुहोस्।"</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"टेदरिङलाई असक्षम पारिएको छ"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"विवरणहरूका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्"</string>
+</resources>
diff --git a/packages/Tethering/res/values-nl/strings.xml b/packages/Tethering/res/values-nl/strings.xml
new file mode 100644
index 0000000..0ec4bff
--- /dev/null
+++ b/packages/Tethering/res/values-nl/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering of hotspot actief"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Tik om in te stellen."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering is uitgeschakeld"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Neem contact op met je beheerder voor meer informatie"</string>
+</resources>
diff --git a/packages/Tethering/res/values-or/strings.xml b/packages/Tethering/res/values-or/strings.xml
new file mode 100644
index 0000000..4576857
--- /dev/null
+++ b/packages/Tethering/res/values-or/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"ଟିଥରିଙ୍ଗ କିମ୍ୱା ହଟସ୍ପଟ୍‌ ସକ୍ରିୟ ଅଛି"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"ସେଟଅପ୍‍ କରିବାକୁ ଟାପ୍‍ କରନ୍ତୁ।"</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"ଟିଥରିଙ୍ଗ ଅକ୍ଷମ କରାଯାଇଛି"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"ବିବରଣୀ ପାଇଁ ନିଜ ଆଡମିନ୍‌ଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ"</string>
+</resources>
diff --git a/packages/Tethering/res/values-pa/strings.xml b/packages/Tethering/res/values-pa/strings.xml
new file mode 100644
index 0000000..deddf2e
--- /dev/null
+++ b/packages/Tethering/res/values-pa/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"ਟੈਦਰਿੰਗ ਜਾਂ ਹੌਟਸਪੌਟ ਕਿਰਿਆਸ਼ੀਲ"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"ਸਥਾਪਤ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"ਟੈਦਰਿੰਗ ਨੂੰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"ਵੇਰਵਿਆਂ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ"</string>
+</resources>
diff --git a/packages/Tethering/res/values-pl/strings.xml b/packages/Tethering/res/values-pl/strings.xml
new file mode 100644
index 0000000..48d8468
--- /dev/null
+++ b/packages/Tethering/res/values-pl/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Aktywny tethering lub punkt dostępu"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Kliknij, by skonfigurować."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering został wyłączony"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Aby uzyskać szczegółowe informacje, skontaktuj się z administratorem"</string>
+</resources>
diff --git a/packages/Tethering/res/values-pt-rBR/strings.xml b/packages/Tethering/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..32c22b8
--- /dev/null
+++ b/packages/Tethering/res/values-pt-rBR/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Ponto de acesso ou tethering ativo"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Toque para configurar."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering desativado"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Fale com seu administrador para saber detalhes"</string>
+</resources>
diff --git a/packages/Tethering/res/values-pt-rPT/strings.xml b/packages/Tethering/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..641e22f
--- /dev/null
+++ b/packages/Tethering/res/values-pt-rPT/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Ligação ponto a ponto ou hotspot activos"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Toque para configurar."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"A ligação (à Internet) via telemóvel está desativada."</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Contacte o gestor para obter detalhes."</string>
+</resources>
diff --git a/packages/Tethering/res/values-pt/strings.xml b/packages/Tethering/res/values-pt/strings.xml
new file mode 100644
index 0000000..32c22b8
--- /dev/null
+++ b/packages/Tethering/res/values-pt/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Ponto de acesso ou tethering ativo"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Toque para configurar."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering desativado"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Fale com seu administrador para saber detalhes"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ro/strings.xml b/packages/Tethering/res/values-ro/strings.xml
new file mode 100644
index 0000000..f861f73
--- /dev/null
+++ b/packages/Tethering/res/values-ro/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering sau hotspot activ"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Atingeți ca să configurați."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tetheringul este dezactivat"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Contactați administratorul pentru detalii"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ru/strings.xml b/packages/Tethering/res/values-ru/strings.xml
new file mode 100644
index 0000000..027cb41
--- /dev/null
+++ b/packages/Tethering/res/values-ru/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Включен режим модема"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Нажмите, чтобы настроить."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Включить режим модема нельзя"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Обратитесь к администратору, чтобы узнать подробности."</string>
+</resources>
diff --git a/packages/Tethering/res/values-si/strings.xml b/packages/Tethering/res/values-si/strings.xml
new file mode 100644
index 0000000..7d8599f
--- /dev/null
+++ b/packages/Tethering/res/values-si/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"ටෙදරින් හෝ හොට්ස්පොට් සක්‍රීයයි"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"පිහිටුවීමට තට්ටු කරන්න."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"ටෙදරින් අබල කර ඇත"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"විස්තර සඳහා ඔබගේ පරිපාලක අමතන්න"</string>
+</resources>
diff --git a/packages/Tethering/res/values-sk/strings.xml b/packages/Tethering/res/values-sk/strings.xml
new file mode 100644
index 0000000..a8fe297
--- /dev/null
+++ b/packages/Tethering/res/values-sk/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering alebo prístupový bod je aktívny"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Klepnutím prejdete na nastavenie."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering je deaktivovaný"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"O podrobnosti požiadajte svojho správcu"</string>
+</resources>
diff --git a/packages/Tethering/res/values-sl/strings.xml b/packages/Tethering/res/values-sl/strings.xml
new file mode 100644
index 0000000..b5e5e38
--- /dev/null
+++ b/packages/Tethering/res/values-sl/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Aktivna povezava z internetom ali dostopna točka sta aktivni"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Dotaknite se, če želite nastaviti."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Povezava z internetom prek mobilnega telefona je onemogočena"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Za podrobnosti se obrnite na skrbnika"</string>
+</resources>
diff --git a/packages/Tethering/res/values-sq/strings.xml b/packages/Tethering/res/values-sq/strings.xml
new file mode 100644
index 0000000..fdd4906
--- /dev/null
+++ b/packages/Tethering/res/values-sq/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Lidhja e çiftimit ose ajo e qasjes në zona publike interneti është aktive"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Trokit për ta konfiguruar."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Lidhja e çiftimit është çaktivizuar"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Kontakto me administratorin për detaje"</string>
+</resources>
diff --git a/packages/Tethering/res/values-sr/strings.xml b/packages/Tethering/res/values-sr/strings.xml
new file mode 100644
index 0000000..9fab34589
--- /dev/null
+++ b/packages/Tethering/res/values-sr/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Активно повезивање са интернетом преко мобилног уређаја или хотспот"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Додирните да бисте подесили."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Привезивање је онемогућено"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Потражите детаље од администратора"</string>
+</resources>
diff --git a/packages/Tethering/res/values-sv/strings.xml b/packages/Tethering/res/values-sv/strings.xml
new file mode 100644
index 0000000..10eeb0f
--- /dev/null
+++ b/packages/Tethering/res/values-sv/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Internetdelning eller surfzon aktiverad"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Tryck om du vill konfigurera."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Internetdelning har inaktiverats"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Kontakta administratören om du vill veta mer"</string>
+</resources>
diff --git a/packages/Tethering/res/values-sw/strings.xml b/packages/Tethering/res/values-sw/strings.xml
new file mode 100644
index 0000000..3353963
--- /dev/null
+++ b/packages/Tethering/res/values-sw/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Kushiriki au kusambaza intaneti kumewashwa"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Gusa ili uweke mipangilio."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Umezima kipengele cha kusambaza mtandao"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Wasiliana na msimamizi wako ili upate maelezo zaidi"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ta/strings.xml b/packages/Tethering/res/values-ta/strings.xml
new file mode 100644
index 0000000..b1e5cc2
--- /dev/null
+++ b/packages/Tethering/res/values-ta/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"டெதெரிங்/ஹாட்ஸ்பாட் இயங்குகிறது"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"அமைக்க, தட்டவும்."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"இணைப்பு முறை முடக்கப்பட்டுள்ளது"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"விவரங்களுக்கு, உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்"</string>
+</resources>
diff --git a/packages/Tethering/res/values-te/strings.xml b/packages/Tethering/res/values-te/strings.xml
new file mode 100644
index 0000000..aae40de
--- /dev/null
+++ b/packages/Tethering/res/values-te/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"టీథర్ చేయబడినది లేదా హాట్‌స్పాట్ సక్రియంగా ఉండేది"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"సెటప్ చేయడానికి నొక్కండి."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"టెథెరింగ్ నిలిపివేయబడింది"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"వివరాల కోసం మీ నిర్వాహకులను సంప్రదించండి"</string>
+</resources>
diff --git a/packages/Tethering/res/values-th/strings.xml b/packages/Tethering/res/values-th/strings.xml
new file mode 100644
index 0000000..1b80056
--- /dev/null
+++ b/packages/Tethering/res/values-th/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"การปล่อยสัญญาณหรือฮอตสปอตทำงานอยู่"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"แตะเพื่อตั้งค่า"</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"ปิดใช้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือแล้ว"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"ติดต่อผู้ดูแลระบบเพื่อขอรายละเอียด"</string>
+</resources>
diff --git a/packages/Tethering/res/values-tl/strings.xml b/packages/Tethering/res/values-tl/strings.xml
new file mode 100644
index 0000000..12863f9
--- /dev/null
+++ b/packages/Tethering/res/values-tl/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Pagsasama o aktibong hotspot"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"I-tap upang i-set up."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Naka-disable ang pag-tether"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Makipag-ugnayan sa iyong admin para sa mga detalye"</string>
+</resources>
diff --git a/packages/Tethering/res/values-tr/strings.xml b/packages/Tethering/res/values-tr/strings.xml
new file mode 100644
index 0000000..bfcf1ac
--- /dev/null
+++ b/packages/Tethering/res/values-tr/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering veya hotspot etkin"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Ayarlamak için dokunun."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering devre dışı bırakıldı"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Ayrıntılı bilgi için yöneticinize başvurun"</string>
+</resources>
diff --git a/packages/Tethering/res/values-uk/strings.xml b/packages/Tethering/res/values-uk/strings.xml
new file mode 100644
index 0000000..8e159c07
--- /dev/null
+++ b/packages/Tethering/res/values-uk/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Прив\'язка чи точка дост. активна"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Торкніться, щоб налаштувати."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Використання телефона в режимі модема вимкнено"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Щоб дізнатися більше, зв’яжіться з адміністратором"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ur/strings.xml b/packages/Tethering/res/values-ur/strings.xml
new file mode 100644
index 0000000..89195d4
--- /dev/null
+++ b/packages/Tethering/res/values-ur/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"ٹیدرنگ یا ہاٹ اسپاٹ فعال"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"سیٹ اپ کرنے کیلئے تھپتھپائیں۔"</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"ٹیدرنگ غیر فعال ہے"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"تفصیلات کے لئے اپنے منتظم سے رابطہ کریں"</string>
+</resources>
diff --git a/packages/Tethering/res/values-uz/strings.xml b/packages/Tethering/res/values-uz/strings.xml
new file mode 100644
index 0000000..0ac4d4a
--- /dev/null
+++ b/packages/Tethering/res/values-uz/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Modem rejimi yoniq"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Sozlash uchun bosing."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Modem rejimi faolsizlantirildi"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Tafsilotlari uchun administratoringizga murojaat qiling"</string>
+</resources>
diff --git a/packages/Tethering/res/values-vi/strings.xml b/packages/Tethering/res/values-vi/strings.xml
new file mode 100644
index 0000000..85a4db8
--- /dev/null
+++ b/packages/Tethering/res/values-vi/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Chức năng điểm truy cập Internet hoặc điểm phát sóng đang hoạt động"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Nhấn để thiết lập."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Đã tắt tính năng chia sẻ kết nối"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Hãy liên hệ với quản trị viên của bạn để biết chi tiết"</string>
+</resources>
diff --git a/packages/Tethering/res/values-zh-rCN/strings.xml b/packages/Tethering/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..ff1fe03
--- /dev/null
+++ b/packages/Tethering/res/values-zh-rCN/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"网络共享或热点已启用"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"点按即可进行设置。"</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"网络共享已停用"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"请与您的管理员联系以了解详情"</string>
+</resources>
diff --git a/packages/Tethering/res/values-zh-rHK/strings.xml b/packages/Tethering/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..0de39fa
--- /dev/null
+++ b/packages/Tethering/res/values-zh-rHK/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"已啟用網絡共享或熱點"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"輕按即可設定。"</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"網絡共享已停用"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"請聯絡您的管理員以瞭解詳情"</string>
+</resources>
diff --git a/packages/Tethering/res/values-zh-rTW/strings.xml b/packages/Tethering/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..9a117bb
--- /dev/null
+++ b/packages/Tethering/res/values-zh-rTW/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"網路共用或無線基地台已啟用"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"輕觸即可進行設定。"</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"數據連線已停用"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"詳情請洽你的管理員"</string>
+</resources>
diff --git a/packages/Tethering/res/values-zu/strings.xml b/packages/Tethering/res/values-zu/strings.xml
new file mode 100644
index 0000000..8fe10d8
--- /dev/null
+++ b/packages/Tethering/res/values-zu/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Ukusebenzisa njengemodemu noma i-hotspot ephathekayo kuvuliwe"</string>
+    <string name="tethered_notification_message" msgid="2113628520792055377">"Thepha ukuze usethe."</string>
+    <string name="disable_tether_notification_title" msgid="7526977944111313195">"Ukusebenzisa ifoni njengemodemu kukhutshaziwe"</string>
+    <string name="disable_tether_notification_message" msgid="2913366428516852495">"Xhumana nomphathi wakho ukuze uthole imininingwane"</string>
+</resources>
diff --git a/packages/Tethering/res/values/strings.xml b/packages/Tethering/res/values/strings.xml
new file mode 100644
index 0000000..ca866a9
--- /dev/null
+++ b/packages/Tethering/res/values/strings.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <!-- Shown when the device is tethered -->
+    <!-- Strings for tethered notification title [CHAR LIMIT=200] -->
+    <string name="tethered_notification_title">Tethering or hotspot active</string>
+    <!-- Strings for tethered notification message [CHAR LIMIT=200] -->
+    <string name="tethered_notification_message">Tap to set up.</string>
+
+    <!-- This notification is shown when tethering has been disabled on a user's device.
+    The device is managed by the user's employer. Tethering can't be turned on unless the
+    IT administrator allows it. The noun "admin" is another reference for "IT administrator." -->
+    <!-- Strings for tether disabling notification title  [CHAR LIMIT=200] -->
+    <string name="disable_tether_notification_title">Tethering is disabled</string>
+    <!-- Strings for tether disabling notification message  [CHAR LIMIT=200] -->
+    <string name="disable_tether_notification_message">Contact your admin for details</string>
+</resources>
\ No newline at end of file
diff --git a/packages/Tethering/src/android/net/util/BaseNetdUnsolicitedEventListener.java b/packages/Tethering/src/android/net/util/BaseNetdUnsolicitedEventListener.java
new file mode 100644
index 0000000..3218c0b
--- /dev/null
+++ b/packages/Tethering/src/android/net/util/BaseNetdUnsolicitedEventListener.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net.util;
+
+import android.net.INetdUnsolicitedEventListener;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Base {@link INetdUnsolicitedEventListener} that provides no-op implementations which can be
+ * overridden.
+ */
+public class BaseNetdUnsolicitedEventListener extends INetdUnsolicitedEventListener.Stub {
+
+    @Override
+    public void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs,
+            int uid) { }
+
+    @Override
+    public void onQuotaLimitReached(@NonNull String alertName, @NonNull String ifName) { }
+
+    @Override
+    public void onInterfaceDnsServerInfo(@NonNull String ifName, long lifetimeS,
+            @NonNull String[] servers) { }
+
+    @Override
+    public void onInterfaceAddressUpdated(@NonNull String addr, String ifName, int flags,
+            int scope) { }
+
+    @Override
+    public void onInterfaceAddressRemoved(@NonNull String addr, @NonNull String ifName, int flags,
+            int scope) { }
+
+    @Override
+    public void onInterfaceAdded(@NonNull String ifName) { }
+
+    @Override
+    public void onInterfaceRemoved(@NonNull String ifName) { }
+
+    @Override
+    public void onInterfaceChanged(@NonNull String ifName, boolean up) { }
+
+    @Override
+    public void onInterfaceLinkStateChanged(@NonNull String ifName, boolean up) { }
+
+    @Override
+    public void onRouteChanged(boolean updated, @NonNull String route, @NonNull String gateway,
+            @NonNull String ifName) { }
+
+    @Override
+    public void onStrictCleartextDetected(int uid, @NonNull String hex) { }
+
+    @Override
+    public int getInterfaceVersion() {
+        return INetdUnsolicitedEventListener.VERSION;
+    }
+}
diff --git a/packages/Tethering/src/android/net/util/VersionedBroadcastListener.java b/packages/Tethering/src/android/net/util/VersionedBroadcastListener.java
new file mode 100644
index 0000000..e2804ab
--- /dev/null
+++ b/packages/Tethering/src/android/net/util/VersionedBroadcastListener.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.util;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.util.Log;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
+
+
+/**
+ * A utility class that runs the provided callback on the provided handler when
+ * intents matching the provided filter arrive. Intents received by a stale
+ * receiver are safely ignored.
+ *
+ * Calls to startListening() and stopListening() must happen on the same thread.
+ *
+ * @hide
+ */
+public class VersionedBroadcastListener {
+    private static final boolean DBG = false;
+
+    private final String mTag;
+    private final Context mContext;
+    private final Handler mHandler;
+    private final IntentFilter mFilter;
+    private final Consumer<Intent> mCallback;
+    private final AtomicInteger mGenerationNumber;
+    private BroadcastReceiver mReceiver;
+
+    public VersionedBroadcastListener(String tag, Context ctx, Handler handler,
+            IntentFilter filter, Consumer<Intent> callback) {
+        mTag = tag;
+        mContext = ctx;
+        mHandler = handler;
+        mFilter = filter;
+        mCallback = callback;
+        mGenerationNumber = new AtomicInteger(0);
+    }
+
+    /** Start listening to intent broadcast. */
+    public void startListening() {
+        if (DBG) Log.d(mTag, "startListening");
+        if (mReceiver != null) return;
+
+        mReceiver = new Receiver(mTag, mGenerationNumber, mCallback);
+        mContext.registerReceiver(mReceiver, mFilter, null, mHandler);
+    }
+
+    /** Stop listening to intent broadcast. */
+    public void stopListening() {
+        if (DBG) Log.d(mTag, "stopListening");
+        if (mReceiver == null) return;
+
+        mGenerationNumber.incrementAndGet();
+        mContext.unregisterReceiver(mReceiver);
+        mReceiver = null;
+    }
+
+    private static class Receiver extends BroadcastReceiver {
+        public final String tag;
+        public final AtomicInteger atomicGenerationNumber;
+        public final Consumer<Intent> callback;
+        // Used to verify this receiver is still current.
+        public final int generationNumber;
+
+        Receiver(String tag, AtomicInteger atomicGenerationNumber, Consumer<Intent> callback) {
+            this.tag = tag;
+            this.atomicGenerationNumber = atomicGenerationNumber;
+            this.callback = callback;
+            generationNumber = atomicGenerationNumber.incrementAndGet();
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final int currentGenerationNumber = atomicGenerationNumber.get();
+
+            if (DBG) {
+                Log.d(tag, "receiver generationNumber=" + generationNumber
+                        + ", current generationNumber=" + currentGenerationNumber);
+            }
+            if (generationNumber != currentGenerationNumber) return;
+
+            callback.accept(intent);
+        }
+    }
+}
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
index 6b0f1de..ba5d08d 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
@@ -47,6 +47,7 @@
 import android.os.PersistableBundle;
 import android.os.ResultReceiver;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.telephony.CarrierConfigManager;
@@ -55,7 +56,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.StateMachine;
-import com.android.server.connectivity.MockableSystemProperties;
 
 import java.io.PrintWriter;
 
@@ -94,7 +94,6 @@
     private final ArraySet<Integer> mCurrentTethers;
     private final Context mContext;
     private final int mPermissionChangeMessageCode;
-    private final MockableSystemProperties mSystemProperties;
     private final SharedLog mLog;
     private final SparseIntArray mEntitlementCacheValue;
     private final EntitlementHandler mHandler;
@@ -110,12 +109,12 @@
     private TetheringConfigurationFetcher mFetcher;
 
     public EntitlementManager(Context ctx, StateMachine tetherMasterSM, SharedLog log,
-            int permissionChangeMessageCode, MockableSystemProperties systemProperties) {
+            int permissionChangeMessageCode) {
+
         mContext = ctx;
         mLog = log.forSubComponent(TAG);
         mCurrentTethers = new ArraySet<Integer>();
         mCellularPermitted = new SparseIntArray();
-        mSystemProperties = systemProperties;
         mEntitlementCacheValue = new SparseIntArray();
         mTetherMasterSM = tetherMasterSM;
         mPermissionChangeMessageCode = permissionChangeMessageCode;
@@ -287,7 +286,7 @@
      */
     @VisibleForTesting
     protected boolean isTetherProvisioningRequired(final TetheringConfiguration config) {
-        if (mSystemProperties.getBoolean(DISABLE_PROVISIONING_SYSPROP_KEY, false)
+        if (SystemProperties.getBoolean(DISABLE_PROVISIONING_SYSPROP_KEY, false)
                 || config.provisioningApp.length == 0) {
             return false;
         }
@@ -526,8 +525,8 @@
                     handleMaybeRunProvisioning(config);
                     break;
                 case EVENT_GET_ENTITLEMENT_VALUE:
-                    handleGetLatestTetheringEntitlementValue(msg.arg1, (ResultReceiver) msg.obj,
-                            toBool(msg.arg2));
+                    handleRequestLatestTetheringEntitlementValue(msg.arg1,
+                            (ResultReceiver) msg.obj, toBool(msg.arg2));
                     break;
                 default:
                     mLog.log("Unknown event: " + msg.what);
@@ -651,15 +650,15 @@
     }
 
     /** Get the last value of the tethering entitlement check. */
-    public void getLatestTetheringEntitlementResult(int downstream, ResultReceiver receiver,
+    public void requestLatestTetheringEntitlementResult(int downstream, ResultReceiver receiver,
             boolean showEntitlementUi) {
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_GET_ENTITLEMENT_VALUE,
                 downstream, encodeBool(showEntitlementUi), receiver));
 
     }
 
-    private void handleGetLatestTetheringEntitlementValue(int downstream, ResultReceiver receiver,
-            boolean showEntitlementUi) {
+    private void handleRequestLatestTetheringEntitlementValue(int downstream,
+            ResultReceiver receiver, boolean showEntitlementUi) {
         final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
         if (!isTetherProvisioningRequired(config)) {
             receiver.send(TETHER_ERROR_NO_ERROR, null);
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java b/packages/Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
new file mode 100644
index 0000000..edfe3ca
--- /dev/null
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.tethering;
+
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkState;
+import android.net.RouteInfo;
+import android.net.ip.IpServer;
+import android.net.util.NetworkConstants;
+import android.net.util.SharedLog;
+import android.util.Log;
+
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.Random;
+
+
+/**
+ * IPv6 tethering is rather different from IPv4 owing to the absence of NAT.
+ * This coordinator is responsible for evaluating the dedicated prefixes
+ * assigned to the device and deciding how to divvy them up among downstream
+ * interfaces.
+ *
+ * @hide
+ */
+public class IPv6TetheringCoordinator {
+    private static final String TAG = IPv6TetheringCoordinator.class.getSimpleName();
+    private static final boolean DBG = false;
+    private static final boolean VDBG = false;
+
+    private static class Downstream {
+        public final IpServer ipServer;
+        public final int mode;  // IpServer.STATE_*
+        // Used to append to a ULA /48, constructing a ULA /64 for local use.
+        public final short subnetId;
+
+        Downstream(IpServer ipServer, int mode, short subnetId) {
+            this.ipServer = ipServer;
+            this.mode = mode;
+            this.subnetId = subnetId;
+        }
+    }
+
+    private final ArrayList<IpServer> mNotifyList;
+    private final SharedLog mLog;
+    // NOTE: mActiveDownstreams is a list and not a hash data structure because
+    // we keep active downstreams in arrival order.  This is done so /64s can
+    // be parceled out on a "first come, first served" basis and a /64 used by
+    // a downstream that is no longer active can be redistributed to any next
+    // waiting active downstream (again, in arrival order).
+    private final LinkedList<Downstream> mActiveDownstreams;
+    private final byte[] mUniqueLocalPrefix;
+    private short mNextSubnetId;
+    private NetworkState mUpstreamNetworkState;
+
+    public IPv6TetheringCoordinator(ArrayList<IpServer> notifyList, SharedLog log) {
+        mNotifyList = notifyList;
+        mLog = log.forSubComponent(TAG);
+        mActiveDownstreams = new LinkedList<>();
+        mUniqueLocalPrefix = generateUniqueLocalPrefix();
+        mNextSubnetId = 0;
+    }
+
+    /** Add active downstream to ipv6 tethering candidate list. */
+    public void addActiveDownstream(IpServer downstream, int mode) {
+        if (findDownstream(downstream) == null) {
+            // Adding a new downstream appends it to the list. Adding a
+            // downstream a second time without first removing it has no effect.
+            // We never change the mode of a downstream except by first removing
+            // it and then re-adding it (with its new mode specified);
+            if (mActiveDownstreams.offer(new Downstream(downstream, mode, mNextSubnetId))) {
+                // Make sure subnet IDs are always positive. They are appended
+                // to a ULA /48 to make a ULA /64 for local use.
+                mNextSubnetId = (short) Math.max(0, mNextSubnetId + 1);
+            }
+            updateIPv6TetheringInterfaces();
+        }
+    }
+
+    /** Remove downstream from ipv6 tethering candidate list. */
+    public void removeActiveDownstream(IpServer downstream) {
+        stopIPv6TetheringOn(downstream);
+        if (mActiveDownstreams.remove(findDownstream(downstream))) {
+            updateIPv6TetheringInterfaces();
+        }
+
+        // When tethering is stopping we can reset the subnet counter.
+        if (mNotifyList.isEmpty()) {
+            if (!mActiveDownstreams.isEmpty()) {
+                Log.wtf(TAG, "Tethering notify list empty, IPv6 downstreams non-empty.");
+            }
+            mNextSubnetId = 0;
+        }
+    }
+
+    /**
+     * Call when upstream NetworkState may be changed.
+     * If upstream has ipv6 for tethering, update this new NetworkState
+     * to IpServer. Otherwise stop ipv6 tethering on downstream interfaces.
+     */
+    public void updateUpstreamNetworkState(NetworkState ns) {
+        if (VDBG) {
+            Log.d(TAG, "updateUpstreamNetworkState: " + toDebugString(ns));
+        }
+        if (TetheringInterfaceUtils.getIPv6Interface(ns) == null) {
+            stopIPv6TetheringOnAllInterfaces();
+            setUpstreamNetworkState(null);
+            return;
+        }
+
+        if (mUpstreamNetworkState != null
+                && !ns.network.equals(mUpstreamNetworkState.network)) {
+            stopIPv6TetheringOnAllInterfaces();
+        }
+
+        setUpstreamNetworkState(ns);
+        updateIPv6TetheringInterfaces();
+    }
+
+    private void stopIPv6TetheringOnAllInterfaces() {
+        for (IpServer ipServer : mNotifyList) {
+            stopIPv6TetheringOn(ipServer);
+        }
+    }
+
+    private void setUpstreamNetworkState(NetworkState ns) {
+        if (ns == null) {
+            mUpstreamNetworkState = null;
+        } else {
+            // Make a deep copy of the parts we need.
+            mUpstreamNetworkState = new NetworkState(
+                    null,
+                    new LinkProperties(ns.linkProperties),
+                    new NetworkCapabilities(ns.networkCapabilities),
+                    new Network(ns.network),
+                    null,
+                    null);
+        }
+
+        mLog.log("setUpstreamNetworkState: " + toDebugString(mUpstreamNetworkState));
+    }
+
+    private void updateIPv6TetheringInterfaces() {
+        for (IpServer ipServer : mNotifyList) {
+            final LinkProperties lp = getInterfaceIPv6LinkProperties(ipServer);
+            ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, lp);
+            break;
+        }
+    }
+
+    private LinkProperties getInterfaceIPv6LinkProperties(IpServer ipServer) {
+        final Downstream ds = findDownstream(ipServer);
+        if (ds == null) return null;
+
+        if (ds.mode == IpServer.STATE_LOCAL_ONLY) {
+            // Build a Unique Locally-assigned Prefix configuration.
+            return getUniqueLocalConfig(mUniqueLocalPrefix, ds.subnetId);
+        }
+
+        // This downstream is in IpServer.STATE_TETHERED mode.
+        if (mUpstreamNetworkState == null || mUpstreamNetworkState.linkProperties == null) {
+            return null;
+        }
+
+        // NOTE: Here, in future, we would have policies to decide how to divvy
+        // up the available dedicated prefixes among downstream interfaces.
+        // At this time we have no such mechanism--we only support tethering
+        // IPv6 toward the oldest (first requested) active downstream.
+
+        final Downstream currentActive = mActiveDownstreams.peek();
+        if (currentActive != null && currentActive.ipServer == ipServer) {
+            final LinkProperties lp = getIPv6OnlyLinkProperties(
+                    mUpstreamNetworkState.linkProperties);
+            if (lp.hasIpv6DefaultRoute() && lp.hasGlobalIpv6Address()) {
+                return lp;
+            }
+        }
+
+        return null;
+    }
+
+    Downstream findDownstream(IpServer ipServer) {
+        for (Downstream ds : mActiveDownstreams) {
+            if (ds.ipServer == ipServer) return ds;
+        }
+        return null;
+    }
+
+    private static LinkProperties getIPv6OnlyLinkProperties(LinkProperties lp) {
+        final LinkProperties v6only = new LinkProperties();
+        if (lp == null) {
+            return v6only;
+        }
+
+        // NOTE: At this time we don't copy over any information about any
+        // stacked links. No current stacked link configuration has IPv6.
+
+        v6only.setInterfaceName(lp.getInterfaceName());
+
+        v6only.setMtu(lp.getMtu());
+
+        for (LinkAddress linkAddr : lp.getLinkAddresses()) {
+            if (linkAddr.isGlobalPreferred() && linkAddr.getPrefixLength() == 64) {
+                v6only.addLinkAddress(linkAddr);
+            }
+        }
+
+        for (RouteInfo routeInfo : lp.getRoutes()) {
+            final IpPrefix destination = routeInfo.getDestination();
+            if ((destination.getAddress() instanceof Inet6Address)
+                    && (destination.getPrefixLength() <= 64)) {
+                v6only.addRoute(routeInfo);
+            }
+        }
+
+        for (InetAddress dnsServer : lp.getDnsServers()) {
+            if (isIPv6GlobalAddress(dnsServer)) {
+                // For now we include ULAs.
+                v6only.addDnsServer(dnsServer);
+            }
+        }
+
+        v6only.setDomains(lp.getDomains());
+
+        return v6only;
+    }
+
+    // TODO: Delete this and switch to LinkAddress#isGlobalPreferred once we
+    // announce our own IPv6 address as DNS server.
+    private static boolean isIPv6GlobalAddress(InetAddress ip) {
+        return (ip instanceof Inet6Address)
+               && !ip.isAnyLocalAddress()
+               && !ip.isLoopbackAddress()
+               && !ip.isLinkLocalAddress()
+               && !ip.isSiteLocalAddress()
+               && !ip.isMulticastAddress();
+    }
+
+    private static LinkProperties getUniqueLocalConfig(byte[] ulp, short subnetId) {
+        final LinkProperties lp = new LinkProperties();
+
+        final IpPrefix local48 = makeUniqueLocalPrefix(ulp, (short) 0, 48);
+        lp.addRoute(new RouteInfo(local48, null, null));
+
+        final IpPrefix local64 = makeUniqueLocalPrefix(ulp, subnetId, 64);
+        // Because this is a locally-generated ULA, we don't have an upstream
+        // address. But because the downstream IP address management code gets
+        // its prefix from the upstream's IP address, we create a fake one here.
+        lp.addLinkAddress(new LinkAddress(local64.getAddress(), 64));
+
+        lp.setMtu(NetworkConstants.ETHER_MTU);
+        return lp;
+    }
+
+    private static IpPrefix makeUniqueLocalPrefix(byte[] in6addr, short subnetId, int prefixlen) {
+        final byte[] bytes = Arrays.copyOf(in6addr, in6addr.length);
+        bytes[7] = (byte) (subnetId >> 8);
+        bytes[8] = (byte) subnetId;
+        return new IpPrefix(bytes, prefixlen);
+    }
+
+    // Generates a Unique Locally-assigned Prefix:
+    //
+    //     https://tools.ietf.org/html/rfc4193#section-3.1
+    //
+    // The result is a /48 that can be used for local-only communications.
+    private static byte[] generateUniqueLocalPrefix() {
+        final byte[] ulp = new byte[6];  // 6 = 48bits / 8bits/byte
+        (new Random()).nextBytes(ulp);
+
+        final byte[] in6addr = Arrays.copyOf(ulp, NetworkConstants.IPV6_ADDR_LEN);
+        in6addr[0] = (byte) 0xfd;  // fc00::/7 and L=1
+
+        return in6addr;
+    }
+
+    private static String toDebugString(NetworkState ns) {
+        if (ns == null) {
+            return "NetworkState{null}";
+        }
+        return String.format("NetworkState{%s, %s, %s}",
+                ns.network,
+                ns.networkCapabilities,
+                ns.linkProperties);
+    }
+
+    private static void stopIPv6TetheringOn(IpServer ipServer) {
+        ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null);
+    }
+}
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
index 01339a4..00a6773 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
@@ -107,6 +107,8 @@
     public OffloadHardwareInterface(Handler h, SharedLog log) {
         mHandler = h;
         mLog = log.forSubComponent(TAG);
+
+        System.loadLibrary("tetheroffloadjni");
     }
 
     /** Get default value indicating whether offload is supported. */
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
new file mode 100644
index 0000000..7c78ef8
--- /dev/null
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -0,0 +1,2041 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.tethering;
+
+import static android.hardware.usb.UsbManager.USB_CONFIGURED;
+import static android.hardware.usb.UsbManager.USB_CONNECTED;
+import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
+import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
+import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
+import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY;
+import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER;
+import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER;
+import static android.net.ConnectivityManager.EXTRA_ERRORED_TETHER;
+import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
+import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
+import static android.net.ConnectivityManager.TETHERING_INVALID;
+import static android.net.ConnectivityManager.TETHERING_USB;
+import static android.net.ConnectivityManager.TETHERING_WIFI;
+import static android.net.ConnectivityManager.TETHERING_WIFI_P2P;
+import static android.net.ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
+import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
+import static android.net.ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL;
+import static android.net.ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
+import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
+import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
+import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
+import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
+import static android.net.wifi.WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR;
+import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY;
+import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
+import static android.net.wifi.WifiManager.IFACE_IP_MODE_UNSPECIFIED;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
+import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothPan;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothProfile.ServiceListener;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.hardware.usb.UsbManager;
+import android.net.INetd;
+import android.net.INetworkPolicyManager;
+import android.net.INetworkStatsService;
+import android.net.ITetherInternalCallback;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkInfo;
+import android.net.NetworkState;
+import android.net.NetworkUtils;
+import android.net.TetherStatesParcel;
+import android.net.TetheringConfigurationParcel;
+import android.net.ip.IpServer;
+import android.net.util.BaseNetdUnsolicitedEventListener;
+import android.net.util.InterfaceSet;
+import android.net.util.PrefixUtils;
+import android.net.util.SharedLog;
+import android.net.util.VersionedBroadcastListener;
+import android.net.wifi.WifiManager;
+import android.net.wifi.p2p.WifiP2pGroup;
+import android.net.wifi.p2p.WifiP2pInfo;
+import android.net.wifi.p2p.WifiP2pManager;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.INetworkManagementService;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.MessageUtils;
+import com.android.internal.util.Protocol;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+import com.android.tethering.R;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ *
+ * This class holds much of the business logic to allow Android devices
+ * to act as IP gateways via USB, BT, and WiFi interfaces.
+ */
+public class Tethering {
+
+    private static final String TAG = Tethering.class.getSimpleName();
+    private static final boolean DBG = false;
+    private static final boolean VDBG = false;
+
+    private static final Class[] sMessageClasses = {
+            Tethering.class, TetherMasterSM.class, IpServer.class
+    };
+    private static final SparseArray<String> sMagicDecoderRing =
+            MessageUtils.findMessageNames(sMessageClasses);
+
+    private static class TetherState {
+        public final IpServer ipServer;
+        public int lastState;
+        public int lastError;
+
+        TetherState(IpServer ipServer) {
+            this.ipServer = ipServer;
+            // Assume all state machines start out available and with no errors.
+            lastState = IpServer.STATE_AVAILABLE;
+            lastError = TETHER_ERROR_NO_ERROR;
+        }
+
+        public boolean isCurrentlyServing() {
+            switch (lastState) {
+                case IpServer.STATE_TETHERED:
+                case IpServer.STATE_LOCAL_ONLY:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+    }
+
+    private final SharedLog mLog = new SharedLog(TAG);
+
+    // used to synchronize public access to members
+    private final Object mPublicSync;
+    private final Context mContext;
+    private final ArrayMap<String, TetherState> mTetherStates;
+    private final BroadcastReceiver mStateReceiver;
+    // Stopship: replace mNMService before production.
+    private final INetworkManagementService mNMService;
+    private final INetworkStatsService mStatsService;
+    private final INetworkPolicyManager mPolicyManager;
+    private final Looper mLooper;
+    private final StateMachine mTetherMasterSM;
+    private final OffloadController mOffloadController;
+    private final UpstreamNetworkMonitor mUpstreamNetworkMonitor;
+    // TODO: Figure out how to merge this and other downstream-tracking objects
+    // into a single coherent structure.
+    private final HashSet<IpServer> mForwardedDownstreams;
+    private final VersionedBroadcastListener mCarrierConfigChange;
+    private final TetheringDependencies mDeps;
+    private final EntitlementManager mEntitlementMgr;
+    private final Handler mHandler;
+    private final PhoneStateListener mPhoneStateListener;
+    private final INetd mNetd;
+    private final NetdCallback mNetdCallback;
+    private final UserRestrictionActionListener mTetheringRestriction;
+    private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID;
+    // All the usage of mTetherInternalCallback should run in the same thread.
+    private ITetherInternalCallback mTetherInternalCallback = null;
+
+    private volatile TetheringConfiguration mConfig;
+    private InterfaceSet mCurrentUpstreamIfaceSet;
+    private Notification.Builder mTetheredNotificationBuilder;
+    private int mLastNotificationId;
+
+    private boolean mRndisEnabled;       // track the RNDIS function enabled state
+    // True iff. WiFi tethering should be started when soft AP is ready.
+    private boolean mWifiTetherRequested;
+    private Network mTetherUpstream;
+    private TetherStatesParcel mTetherStatesParcel;
+
+    public Tethering(TetheringDependencies deps) {
+        mLog.mark("Tethering.constructed");
+        mDeps = deps;
+        mContext = mDeps.getContext();
+        mNMService = mDeps.getINetworkManagementService();
+        mStatsService = mDeps.getINetworkStatsService();
+        mPolicyManager = mDeps.getINetworkPolicyManager();
+        mNetd = mDeps.getINetd(mContext);
+        mLooper = mDeps.getTetheringLooper();
+
+        mPublicSync = new Object();
+
+        mTetherStates = new ArrayMap<>();
+
+        mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper, deps);
+        mTetherMasterSM.start();
+
+        mHandler = mTetherMasterSM.getHandler();
+        mOffloadController = new OffloadController(mHandler,
+                mDeps.getOffloadHardwareInterface(mHandler, mLog),
+                mContext.getContentResolver(), mNMService,
+                mLog);
+        mUpstreamNetworkMonitor = deps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog,
+                TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
+        mForwardedDownstreams = new HashSet<>();
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(ACTION_CARRIER_CONFIG_CHANGED);
+        // EntitlementManager will send EVENT_UPSTREAM_PERMISSION_CHANGED when cellular upstream
+        // permission is changed according to entitlement check result.
+        mEntitlementMgr = mDeps.getEntitlementManager(mContext, mTetherMasterSM, mLog,
+                TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED);
+        mEntitlementMgr.setOnUiEntitlementFailedListener((int downstream) -> {
+            mLog.log("OBSERVED UiEnitlementFailed");
+            stopTethering(downstream);
+        });
+        mEntitlementMgr.setTetheringConfigurationFetcher(() -> {
+            return mConfig;
+        });
+
+        mCarrierConfigChange = new VersionedBroadcastListener(
+                "CarrierConfigChangeListener", mContext, mHandler, filter,
+                (Intent ignored) -> {
+                    mLog.log("OBSERVED carrier config change");
+                    updateConfiguration();
+                    mEntitlementMgr.reevaluateSimCardProvisioning(mConfig);
+                });
+
+        mPhoneStateListener = new PhoneStateListener(mLooper) {
+            @Override
+            public void onActiveDataSubscriptionIdChanged(int subId) {
+                mLog.log("OBSERVED active data subscription change, from " + mActiveDataSubId
+                        + " to " + subId);
+                if (subId == mActiveDataSubId) return;
+
+                mActiveDataSubId = subId;
+                updateConfiguration();
+                // To avoid launching unexpected provisioning checks, ignore re-provisioning when
+                // no CarrierConfig loaded yet. Assume reevaluateSimCardProvisioning() will be
+                // triggered again when CarrierConfig is loaded.
+                if (mEntitlementMgr.getCarrierConfig(mConfig) != null) {
+                    mEntitlementMgr.reevaluateSimCardProvisioning(mConfig);
+                } else {
+                    mLog.log("IGNORED reevaluate provisioning due to no carrier config loaded");
+                }
+            }
+        };
+
+        mStateReceiver = new StateReceiver();
+
+        mNetdCallback = new NetdCallback();
+        try {
+            mNetd.registerUnsolicitedEventListener(mNetdCallback);
+        } catch (RemoteException e) {
+            mLog.e("Unable to register netd UnsolicitedEventListener");
+        }
+
+        final UserManager userManager = (UserManager) mContext.getSystemService(
+                    Context.USER_SERVICE);
+        mTetheringRestriction = new UserRestrictionActionListener(userManager, this);
+
+        // Load tethering configuration.
+        updateConfiguration();
+
+        startStateMachineUpdaters(mHandler);
+        startTrackDefaultNetwork();
+    }
+
+    private void startStateMachineUpdaters(Handler handler) {
+        mCarrierConfigChange.startListening();
+        mContext.getSystemService(TelephonyManager.class).listen(
+                mPhoneStateListener, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(UsbManager.ACTION_USB_STATE);
+        filter.addAction(CONNECTIVITY_ACTION);
+        filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
+        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+        filter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
+        filter.addAction(UserManager.ACTION_USER_RESTRICTIONS_CHANGED);
+        mContext.registerReceiver(mStateReceiver, filter, null, handler);
+
+        filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_MEDIA_SHARED);
+        filter.addAction(Intent.ACTION_MEDIA_UNSHARED);
+        filter.addDataScheme("file");
+        mContext.registerReceiver(mStateReceiver, filter, null, handler);
+
+    }
+
+    private WifiManager getWifiManager() {
+        return (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+    }
+
+    // NOTE: This is always invoked on the mLooper thread.
+    private void updateConfiguration() {
+        mConfig = mDeps.generateTetheringConfiguration(mContext, mLog, mActiveDataSubId);
+        mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired);
+        reportConfigurationChanged(mConfig.toStableParcelable());
+    }
+
+    private void maybeDunSettingChanged() {
+        final boolean isDunRequired = TetheringConfiguration.checkDunRequired(
+                mContext, mActiveDataSubId);
+        if (isDunRequired == mConfig.isDunRequired) return;
+        updateConfiguration();
+    }
+
+    private class NetdCallback extends BaseNetdUnsolicitedEventListener {
+        @Override
+        public void onInterfaceChanged(String ifName, boolean up) {
+            mHandler.post(() -> interfaceStatusChanged(ifName, up));
+        }
+
+        @Override
+        public void onInterfaceLinkStateChanged(String ifName, boolean up) {
+            mHandler.post(() -> interfaceLinkStateChanged(ifName, up));
+        }
+
+        @Override
+        public void onInterfaceAdded(String ifName) {
+            mHandler.post(() -> interfaceAdded(ifName));
+        }
+
+        @Override
+        public void onInterfaceRemoved(String ifName) {
+            mHandler.post(() -> interfaceRemoved(ifName));
+        }
+    }
+
+    void interfaceStatusChanged(String iface, boolean up) {
+        // Never called directly: only called from interfaceLinkStateChanged.
+        // See NetlinkHandler.cpp: notifyInterfaceChanged.
+        if (VDBG) Log.d(TAG, "interfaceStatusChanged " + iface + ", " + up);
+        synchronized (mPublicSync) {
+            if (up) {
+                maybeTrackNewInterfaceLocked(iface);
+            } else {
+                if (ifaceNameToType(iface) == TETHERING_BLUETOOTH) {
+                    stopTrackingInterfaceLocked(iface);
+                } else {
+                    // Ignore usb0 down after enabling RNDIS.
+                    // We will handle disconnect in interfaceRemoved.
+                    // Similarly, ignore interface down for WiFi.  We monitor WiFi AP status
+                    // through the WifiManager.WIFI_AP_STATE_CHANGED_ACTION intent.
+                    if (VDBG) Log.d(TAG, "ignore interface down for " + iface);
+                }
+            }
+        }
+    }
+
+    void interfaceLinkStateChanged(String iface, boolean up) {
+        interfaceStatusChanged(iface, up);
+    }
+
+    private int ifaceNameToType(String iface) {
+        final TetheringConfiguration cfg = mConfig;
+
+        if (cfg.isWifi(iface)) {
+            return TETHERING_WIFI;
+        } else if (cfg.isWifiP2p(iface)) {
+            return TETHERING_WIFI_P2P;
+        } else if (cfg.isUsb(iface)) {
+            return TETHERING_USB;
+        } else if (cfg.isBluetooth(iface)) {
+            return TETHERING_BLUETOOTH;
+        }
+        return TETHERING_INVALID;
+    }
+
+    void interfaceAdded(String iface) {
+        if (VDBG) Log.d(TAG, "interfaceAdded " + iface);
+        synchronized (mPublicSync) {
+            maybeTrackNewInterfaceLocked(iface);
+        }
+    }
+
+
+    void interfaceRemoved(String iface) {
+        if (VDBG) Log.d(TAG, "interfaceRemoved " + iface);
+        synchronized (mPublicSync) {
+            stopTrackingInterfaceLocked(iface);
+        }
+    }
+
+    void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
+        mEntitlementMgr.startProvisioningIfNeeded(type, showProvisioningUi);
+        enableTetheringInternal(type, true /* enabled */, receiver);
+    }
+
+    void stopTethering(int type) {
+        enableTetheringInternal(type, false /* disabled */, null);
+        mEntitlementMgr.stopProvisioningIfNeeded(type);
+    }
+
+    /**
+     * Enables or disables tethering for the given type. If provisioning is required, it will
+     * schedule provisioning rechecks for the specified interface.
+     */
+    private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) {
+        int result;
+        switch (type) {
+            case TETHERING_WIFI:
+                result = setWifiTethering(enable);
+                sendTetherResult(receiver, result);
+                break;
+            case TETHERING_USB:
+                result = setUsbTethering(enable);
+                sendTetherResult(receiver, result);
+                break;
+            case TETHERING_BLUETOOTH:
+                setBluetoothTethering(enable, receiver);
+                break;
+            default:
+                Log.w(TAG, "Invalid tether type.");
+                sendTetherResult(receiver, TETHER_ERROR_UNKNOWN_IFACE);
+        }
+    }
+
+    private void sendTetherResult(ResultReceiver receiver, int result) {
+        if (receiver != null) {
+            receiver.send(result, null);
+        }
+    }
+
+    private int setWifiTethering(final boolean enable) {
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (mPublicSync) {
+                final WifiManager mgr = getWifiManager();
+                if (mgr == null) {
+                    mLog.e("setWifiTethering: failed to get WifiManager!");
+                    return TETHER_ERROR_SERVICE_UNAVAIL;
+                }
+                if ((enable && mgr.startSoftAp(null /* use existing wifi config */))
+                        || (!enable && mgr.stopSoftAp())) {
+                    mWifiTetherRequested = enable;
+                    return TETHER_ERROR_NO_ERROR;
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+
+        return TETHER_ERROR_MASTER_ERROR;
+    }
+
+    private void setBluetoothTethering(final boolean enable, final ResultReceiver receiver) {
+        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (adapter == null || !adapter.isEnabled()) {
+            Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: "
+                    + (adapter == null));
+            sendTetherResult(receiver, TETHER_ERROR_SERVICE_UNAVAIL);
+            return;
+        }
+
+        adapter.getProfileProxy(mContext, new ServiceListener() {
+            @Override
+            public void onServiceDisconnected(int profile) { }
+
+            @Override
+            public void onServiceConnected(int profile, BluetoothProfile proxy) {
+                // Clear identify is fine because caller already pass tethering permission at
+                // ConnectivityService#startTethering()(or stopTethering) before the control comes
+                // here. Bluetooth will check tethering permission again that there is
+                // Context#getOpPackageName() under BluetoothPan#setBluetoothTethering() to get
+                // caller's package name for permission check.
+                // Calling BluetoothPan#setBluetoothTethering() here means the package name always
+                // be system server. If calling identity is not cleared, that package's uid might
+                // not match calling uid and end up in permission denied.
+                final long identityToken = Binder.clearCallingIdentity();
+                try {
+                    ((BluetoothPan) proxy).setBluetoothTethering(enable);
+                } finally {
+                    Binder.restoreCallingIdentity(identityToken);
+                }
+                // TODO: Enabling bluetooth tethering can fail asynchronously here.
+                // We should figure out a way to bubble up that failure instead of sending success.
+                final int result = (((BluetoothPan) proxy).isTetheringOn() == enable)
+                        ? TETHER_ERROR_NO_ERROR
+                        : TETHER_ERROR_MASTER_ERROR;
+                sendTetherResult(receiver, result);
+                adapter.closeProfileProxy(BluetoothProfile.PAN, proxy);
+            }
+        }, BluetoothProfile.PAN);
+    }
+
+    int tether(String iface) {
+        return tether(iface, IpServer.STATE_TETHERED);
+    }
+
+    private int tether(String iface, int requestedState) {
+        if (DBG) Log.d(TAG, "Tethering " + iface);
+        synchronized (mPublicSync) {
+            TetherState tetherState = mTetherStates.get(iface);
+            if (tetherState == null) {
+                Log.e(TAG, "Tried to Tether an unknown iface: " + iface + ", ignoring");
+                return TETHER_ERROR_UNKNOWN_IFACE;
+            }
+            // Ignore the error status of the interface.  If the interface is available,
+            // the errors are referring to past tethering attempts anyway.
+            if (tetherState.lastState != IpServer.STATE_AVAILABLE) {
+                Log.e(TAG, "Tried to Tether an unavailable iface: " + iface + ", ignoring");
+                return TETHER_ERROR_UNAVAIL_IFACE;
+            }
+            // NOTE: If a CMD_TETHER_REQUESTED message is already in the TISM's
+            // queue but not yet processed, this will be a no-op and it will not
+            // return an error.
+            //
+            // TODO: reexamine the threading and messaging model.
+            tetherState.ipServer.sendMessage(IpServer.CMD_TETHER_REQUESTED, requestedState);
+            return TETHER_ERROR_NO_ERROR;
+        }
+    }
+
+    int untether(String iface) {
+        if (DBG) Log.d(TAG, "Untethering " + iface);
+        synchronized (mPublicSync) {
+            TetherState tetherState = mTetherStates.get(iface);
+            if (tetherState == null) {
+                Log.e(TAG, "Tried to Untether an unknown iface :" + iface + ", ignoring");
+                return TETHER_ERROR_UNKNOWN_IFACE;
+            }
+            if (!tetherState.isCurrentlyServing()) {
+                Log.e(TAG, "Tried to untether an inactive iface :" + iface + ", ignoring");
+                return TETHER_ERROR_UNAVAIL_IFACE;
+            }
+            tetherState.ipServer.sendMessage(IpServer.CMD_TETHER_UNREQUESTED);
+            return TETHER_ERROR_NO_ERROR;
+        }
+    }
+
+    void untetherAll() {
+        stopTethering(TETHERING_WIFI);
+        stopTethering(TETHERING_WIFI_P2P);
+        stopTethering(TETHERING_USB);
+        stopTethering(TETHERING_BLUETOOTH);
+    }
+
+    int getLastTetherError(String iface) {
+        synchronized (mPublicSync) {
+            TetherState tetherState = mTetherStates.get(iface);
+            if (tetherState == null) {
+                Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface
+                        + ", ignoring");
+                return TETHER_ERROR_UNKNOWN_IFACE;
+            }
+            return tetherState.lastError;
+        }
+    }
+
+    // TODO: Figure out how to update for local hotspot mode interfaces.
+    private void sendTetherStateChangedBroadcast() {
+        if (!mDeps.isTetheringSupported()) return;
+
+        final ArrayList<String> availableList = new ArrayList<>();
+        final ArrayList<String> tetherList = new ArrayList<>();
+        final ArrayList<String> localOnlyList = new ArrayList<>();
+        final ArrayList<String> erroredList = new ArrayList<>();
+        final ArrayList<Integer> lastErrorList = new ArrayList<>();
+
+        boolean wifiTethered = false;
+        boolean usbTethered = false;
+        boolean bluetoothTethered = false;
+
+        final TetheringConfiguration cfg = mConfig;
+        final TetherStatesParcel mTetherStatesParcel = new TetherStatesParcel();
+
+        synchronized (mPublicSync) {
+            for (int i = 0; i < mTetherStates.size(); i++) {
+                TetherState tetherState = mTetherStates.valueAt(i);
+                String iface = mTetherStates.keyAt(i);
+                if (tetherState.lastError != TETHER_ERROR_NO_ERROR) {
+                    erroredList.add(iface);
+                    lastErrorList.add(tetherState.lastError);
+                } else if (tetherState.lastState == IpServer.STATE_AVAILABLE) {
+                    availableList.add(iface);
+                } else if (tetherState.lastState == IpServer.STATE_LOCAL_ONLY) {
+                    localOnlyList.add(iface);
+                } else if (tetherState.lastState == IpServer.STATE_TETHERED) {
+                    if (cfg.isUsb(iface)) {
+                        usbTethered = true;
+                    } else if (cfg.isWifi(iface)) {
+                        wifiTethered = true;
+                    } else if (cfg.isBluetooth(iface)) {
+                        bluetoothTethered = true;
+                    }
+                    tetherList.add(iface);
+                }
+            }
+        }
+
+        mTetherStatesParcel.availableList = availableList.toArray(new String[0]);
+        mTetherStatesParcel.tetheredList = tetherList.toArray(new String[0]);
+        mTetherStatesParcel.localOnlyList = localOnlyList.toArray(new String[0]);
+        mTetherStatesParcel.erroredIfaceList = erroredList.toArray(new String[0]);
+        mTetherStatesParcel.lastErrorList = new int[lastErrorList.size()];
+        Iterator<Integer> iterator = lastErrorList.iterator();
+        for (int i = 0; i < lastErrorList.size(); i++) {
+            mTetherStatesParcel.lastErrorList[i] = iterator.next().intValue();
+        }
+        reportTetherStateChanged(mTetherStatesParcel);
+
+        final Intent bcast = new Intent(ACTION_TETHER_STATE_CHANGED);
+        bcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
+                | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+        bcast.putStringArrayListExtra(EXTRA_AVAILABLE_TETHER, availableList);
+        bcast.putStringArrayListExtra(EXTRA_ACTIVE_LOCAL_ONLY, localOnlyList);
+        bcast.putStringArrayListExtra(EXTRA_ACTIVE_TETHER, tetherList);
+        bcast.putStringArrayListExtra(EXTRA_ERRORED_TETHER, erroredList);
+        mContext.sendStickyBroadcastAsUser(bcast, UserHandle.ALL);
+        if (DBG) {
+            Log.d(TAG, String.format(
+                    "sendTetherStateChangedBroadcast %s=[%s] %s=[%s] %s=[%s] %s=[%s]",
+                    "avail", TextUtils.join(",", availableList),
+                    "local_only", TextUtils.join(",", localOnlyList),
+                    "tether", TextUtils.join(",", tetherList),
+                    "error", TextUtils.join(",", erroredList)));
+        }
+
+        if (usbTethered) {
+            if (wifiTethered || bluetoothTethered) {
+                showTetheredNotification(SystemMessage.NOTE_TETHER_GENERAL);
+            } else {
+                showTetheredNotification(SystemMessage.NOTE_TETHER_USB);
+            }
+        } else if (wifiTethered) {
+            if (bluetoothTethered) {
+                showTetheredNotification(SystemMessage.NOTE_TETHER_GENERAL);
+            } else {
+                /* We now have a status bar icon for WifiTethering, so drop the notification */
+                clearTetheredNotification();
+            }
+        } else if (bluetoothTethered) {
+            showTetheredNotification(SystemMessage.NOTE_TETHER_BLUETOOTH);
+        } else {
+            clearTetheredNotification();
+        }
+    }
+
+    private void showTetheredNotification(int id) {
+        showTetheredNotification(id, true);
+    }
+
+    @VisibleForTesting
+    protected void showTetheredNotification(int id, boolean tetheringOn) {
+        NotificationManager notificationManager =
+                (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+        if (notificationManager == null) {
+            return;
+        }
+        int icon = 0;
+        switch(id) {
+            case SystemMessage.NOTE_TETHER_USB:
+                icon = R.drawable.stat_sys_tether_usb;
+                break;
+            case SystemMessage.NOTE_TETHER_BLUETOOTH:
+                icon = R.drawable.stat_sys_tether_bluetooth;
+                break;
+            case SystemMessage.NOTE_TETHER_GENERAL:
+            default:
+                icon = R.drawable.stat_sys_tether_general;
+                break;
+        }
+
+        if (mLastNotificationId != 0) {
+            if (mLastNotificationId == icon) {
+                return;
+            }
+            notificationManager.cancelAsUser(null, mLastNotificationId,
+                    UserHandle.ALL);
+            mLastNotificationId = 0;
+        }
+
+        Intent intent = new Intent();
+        intent.setClassName("com.android.settings", "com.android.settings.TetherSettings");
+        intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
+
+        PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0, intent, 0,
+                null, UserHandle.CURRENT);
+
+        Resources r = mContext.getResources();
+        final CharSequence title;
+        final CharSequence message;
+
+        if (tetheringOn) {
+            title = r.getText(R.string.tethered_notification_title);
+            message = r.getText(R.string.tethered_notification_message);
+        } else {
+            title = r.getText(R.string.disable_tether_notification_title);
+            message = r.getText(R.string.disable_tether_notification_message);
+        }
+
+        if (mTetheredNotificationBuilder == null) {
+            mTetheredNotificationBuilder = new Notification.Builder(mContext,
+                    SystemNotificationChannels.NETWORK_STATUS);
+            mTetheredNotificationBuilder.setWhen(0)
+                    .setOngoing(true)
+                    .setColor(mContext.getColor(
+                            com.android.internal.R.color.system_notification_accent_color))
+                    .setVisibility(Notification.VISIBILITY_PUBLIC)
+                    .setCategory(Notification.CATEGORY_STATUS);
+        }
+        mTetheredNotificationBuilder.setSmallIcon(icon)
+                .setContentTitle(title)
+                .setContentText(message)
+                .setContentIntent(pi);
+        mLastNotificationId = id;
+
+        notificationManager.notifyAsUser(null, mLastNotificationId,
+                mTetheredNotificationBuilder.buildInto(new Notification()), UserHandle.ALL);
+    }
+
+    @VisibleForTesting
+    protected void clearTetheredNotification() {
+        NotificationManager notificationManager =
+                (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+        if (notificationManager != null && mLastNotificationId != 0) {
+            notificationManager.cancelAsUser(null, mLastNotificationId,
+                    UserHandle.ALL);
+            mLastNotificationId = 0;
+        }
+    }
+
+    private class StateReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context content, Intent intent) {
+            final String action = intent.getAction();
+            if (action == null) return;
+
+            if (action.equals(UsbManager.ACTION_USB_STATE)) {
+                handleUsbAction(intent);
+            } else if (action.equals(CONNECTIVITY_ACTION)) {
+                handleConnectivityAction(intent);
+            } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
+                handleWifiApAction(intent);
+            } else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) {
+                handleWifiP2pAction(intent);
+            } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
+                mLog.log("OBSERVED configuration changed");
+                updateConfiguration();
+            } else if (action.equals(UserManager.ACTION_USER_RESTRICTIONS_CHANGED)) {
+                mLog.log("OBSERVED user restrictions changed");
+                handleUserRestrictionAction();
+            }
+        }
+
+        private void handleConnectivityAction(Intent intent) {
+            final NetworkInfo networkInfo =
+                    (NetworkInfo) intent.getParcelableExtra(EXTRA_NETWORK_INFO);
+            if (networkInfo == null
+                    || networkInfo.getDetailedState() == NetworkInfo.DetailedState.FAILED) {
+                return;
+            }
+
+            if (VDBG) Log.d(TAG, "Tethering got CONNECTIVITY_ACTION: " + networkInfo.toString());
+            mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);
+        }
+
+        private void handleUsbAction(Intent intent) {
+            final boolean usbConnected = intent.getBooleanExtra(USB_CONNECTED, false);
+            final boolean usbConfigured = intent.getBooleanExtra(USB_CONFIGURED, false);
+            final boolean rndisEnabled = intent.getBooleanExtra(USB_FUNCTION_RNDIS, false);
+
+            mLog.log(String.format("USB bcast connected:%s configured:%s rndis:%s",
+                    usbConnected, usbConfigured, rndisEnabled));
+
+            // There are three types of ACTION_USB_STATE:
+            //
+            //     - DISCONNECTED (USB_CONNECTED and USB_CONFIGURED are 0)
+            //       Meaning: USB connection has ended either because of
+            //       software reset or hard unplug.
+            //
+            //     - CONNECTED (USB_CONNECTED is 1, USB_CONFIGURED is 0)
+            //       Meaning: the first stage of USB protocol handshake has
+            //       occurred but it is not complete.
+            //
+            //     - CONFIGURED (USB_CONNECTED and USB_CONFIGURED are 1)
+            //       Meaning: the USB handshake is completely done and all the
+            //       functions are ready to use.
+            //
+            // For more explanation, see b/62552150 .
+            synchronized (Tethering.this.mPublicSync) {
+                if (!usbConnected && mRndisEnabled) {
+                    // Turn off tethering if it was enabled and there is a disconnect.
+                    tetherMatchingInterfaces(IpServer.STATE_AVAILABLE, TETHERING_USB);
+                    mEntitlementMgr.stopProvisioningIfNeeded(TETHERING_USB);
+                } else if (usbConfigured && rndisEnabled) {
+                    // Tether if rndis is enabled and usb is configured.
+                    tetherMatchingInterfaces(IpServer.STATE_TETHERED, TETHERING_USB);
+                }
+                mRndisEnabled = usbConfigured && rndisEnabled;
+            }
+        }
+
+        private void handleWifiApAction(Intent intent) {
+            final int curState = intent.getIntExtra(EXTRA_WIFI_AP_STATE, WIFI_AP_STATE_DISABLED);
+            final String ifname = intent.getStringExtra(EXTRA_WIFI_AP_INTERFACE_NAME);
+            final int ipmode = intent.getIntExtra(EXTRA_WIFI_AP_MODE, IFACE_IP_MODE_UNSPECIFIED);
+
+            synchronized (Tethering.this.mPublicSync) {
+                switch (curState) {
+                    case WifiManager.WIFI_AP_STATE_ENABLING:
+                        // We can see this state on the way to both enabled and failure states.
+                        break;
+                    case WifiManager.WIFI_AP_STATE_ENABLED:
+                        enableWifiIpServingLocked(ifname, ipmode);
+                        break;
+                    case WifiManager.WIFI_AP_STATE_DISABLED:
+                    case WifiManager.WIFI_AP_STATE_DISABLING:
+                    case WifiManager.WIFI_AP_STATE_FAILED:
+                    default:
+                        disableWifiIpServingLocked(ifname, curState);
+                        break;
+                }
+            }
+        }
+
+        private void handleWifiP2pAction(Intent intent) {
+            if (mConfig.isWifiP2pLegacyTetheringMode()) return;
+
+            final WifiP2pInfo p2pInfo =
+                    (WifiP2pInfo) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO);
+            final WifiP2pGroup group =
+                    (WifiP2pGroup) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP);
+
+            if (VDBG) {
+                Log.d(TAG, "WifiP2pAction: P2pInfo: " + p2pInfo + " Group: " + group);
+            }
+
+            if (p2pInfo == null) return;
+            // When a p2p group is disconnected, p2pInfo would be cleared.
+            // group is still valid for detecting whether this device is group owner.
+            if (group == null || !group.isGroupOwner()
+                    || TextUtils.isEmpty(group.getInterface())) return;
+
+            synchronized (Tethering.this.mPublicSync) {
+                // Enter below only if this device is Group Owner with a valid interface.
+                if (p2pInfo.groupFormed) {
+                    TetherState tetherState = mTetherStates.get(group.getInterface());
+                    if (tetherState == null
+                            || (tetherState.lastState != IpServer.STATE_TETHERED
+                                && tetherState.lastState != IpServer.STATE_LOCAL_ONLY)) {
+                        enableWifiIpServingLocked(group.getInterface(), IFACE_IP_MODE_LOCAL_ONLY);
+                    }
+                } else {
+                    disableWifiP2pIpServingLocked(group.getInterface());
+                }
+            }
+        }
+
+        private void handleUserRestrictionAction() {
+            mTetheringRestriction.onUserRestrictionsChanged();
+        }
+    }
+
+    @VisibleForTesting
+    protected static class UserRestrictionActionListener {
+        private final UserManager mUserManager;
+        private final Tethering mWrapper;
+        public boolean mDisallowTethering;
+
+        public UserRestrictionActionListener(UserManager um, Tethering wrapper) {
+            mUserManager = um;
+            mWrapper = wrapper;
+            mDisallowTethering = false;
+        }
+
+        public void onUserRestrictionsChanged() {
+            // getUserRestrictions gets restriction for this process' user, which is the primary
+            // user. This is fine because DISALLOW_CONFIG_TETHERING can only be set on the primary
+            // user. See UserManager.DISALLOW_CONFIG_TETHERING.
+            final Bundle restrictions = mUserManager.getUserRestrictions();
+            final boolean newlyDisallowed =
+                    restrictions.getBoolean(UserManager.DISALLOW_CONFIG_TETHERING);
+            final boolean prevDisallowed = mDisallowTethering;
+            mDisallowTethering = newlyDisallowed;
+
+            final boolean tetheringDisallowedChanged = (newlyDisallowed != prevDisallowed);
+            if (!tetheringDisallowedChanged) {
+                return;
+            }
+
+            mWrapper.clearTetheredNotification();
+            final boolean isTetheringActiveOnDevice = (mWrapper.getTetheredIfaces().length != 0);
+
+            if (newlyDisallowed && isTetheringActiveOnDevice) {
+                mWrapper.showTetheredNotification(
+                        R.drawable.stat_sys_tether_general, false);
+                mWrapper.untetherAll();
+            }
+        }
+    }
+
+    private void disableWifiIpServingLockedCommon(int tetheringType, String ifname, int apState) {
+        mLog.log("Canceling WiFi tethering request -"
+                + " type=" + tetheringType
+                + " interface=" + ifname
+                + " state=" + apState);
+
+        if (!TextUtils.isEmpty(ifname)) {
+            final TetherState ts = mTetherStates.get(ifname);
+            if (ts != null) {
+                ts.ipServer.unwanted();
+                return;
+            }
+        }
+
+        for (int i = 0; i < mTetherStates.size(); i++) {
+            final IpServer ipServer = mTetherStates.valueAt(i).ipServer;
+            if (ipServer.interfaceType() == tetheringType) {
+                ipServer.unwanted();
+                return;
+            }
+        }
+
+        mLog.log("Error disabling Wi-Fi IP serving; "
+                + (TextUtils.isEmpty(ifname) ? "no interface name specified"
+                                           : "specified interface: " + ifname));
+    }
+
+    private void disableWifiIpServingLocked(String ifname, int apState) {
+        // Regardless of whether we requested this transition, the AP has gone
+        // down.  Don't try to tether again unless we're requested to do so.
+        // TODO: Remove this altogether, once Wi-Fi reliably gives us an
+        // interface name with every broadcast.
+        mWifiTetherRequested = false;
+
+        disableWifiIpServingLockedCommon(TETHERING_WIFI, ifname, apState);
+    }
+
+    private void disableWifiP2pIpServingLocked(String ifname) {
+        disableWifiIpServingLockedCommon(TETHERING_WIFI_P2P, ifname, /* dummy */ 0);
+    }
+
+    private void enableWifiIpServingLocked(String ifname, int wifiIpMode) {
+        // Map wifiIpMode values to IpServer.Callback serving states, inferring
+        // from mWifiTetherRequested as a final "best guess".
+        final int ipServingMode;
+        switch (wifiIpMode) {
+            case IFACE_IP_MODE_TETHERED:
+                ipServingMode = IpServer.STATE_TETHERED;
+                break;
+            case IFACE_IP_MODE_LOCAL_ONLY:
+                ipServingMode = IpServer.STATE_LOCAL_ONLY;
+                break;
+            default:
+                mLog.e("Cannot enable IP serving in unknown WiFi mode: " + wifiIpMode);
+                return;
+        }
+
+        if (!TextUtils.isEmpty(ifname)) {
+            maybeTrackNewInterfaceLocked(ifname);
+            changeInterfaceState(ifname, ipServingMode);
+        } else {
+            mLog.e(String.format(
+                    "Cannot enable IP serving in mode %s on missing interface name",
+                    ipServingMode));
+        }
+    }
+
+    // TODO: Consider renaming to something more accurate in its description.
+    // This method:
+    //     - allows requesting either tethering or local hotspot serving states
+    //     - handles both enabling and disabling serving states
+    //     - only tethers the first matching interface in listInterfaces()
+    //       order of a given type
+    private void tetherMatchingInterfaces(int requestedState, int interfaceType) {
+        if (VDBG) {
+            Log.d(TAG, "tetherMatchingInterfaces(" + requestedState + ", " + interfaceType + ")");
+        }
+
+        String[] ifaces = null;
+        try {
+            ifaces = mNMService.listInterfaces();
+        } catch (Exception e) {
+            Log.e(TAG, "Error listing Interfaces", e);
+            return;
+        }
+        String chosenIface = null;
+        if (ifaces != null) {
+            for (String iface : ifaces) {
+                if (ifaceNameToType(iface) == interfaceType) {
+                    chosenIface = iface;
+                    break;
+                }
+            }
+        }
+        if (chosenIface == null) {
+            Log.e(TAG, "could not find iface of type " + interfaceType);
+            return;
+        }
+
+        changeInterfaceState(chosenIface, requestedState);
+    }
+
+    private void changeInterfaceState(String ifname, int requestedState) {
+        final int result;
+        switch (requestedState) {
+            case IpServer.STATE_UNAVAILABLE:
+            case IpServer.STATE_AVAILABLE:
+                result = untether(ifname);
+                break;
+            case IpServer.STATE_TETHERED:
+            case IpServer.STATE_LOCAL_ONLY:
+                result = tether(ifname, requestedState);
+                break;
+            default:
+                Log.wtf(TAG, "Unknown interface state: " + requestedState);
+                return;
+        }
+        if (result != TETHER_ERROR_NO_ERROR) {
+            Log.e(TAG, "unable start or stop tethering on iface " + ifname);
+            return;
+        }
+    }
+
+    TetheringConfiguration getTetheringConfiguration() {
+        return mConfig;
+    }
+
+    boolean hasTetherableConfiguration() {
+        final TetheringConfiguration cfg = mConfig;
+        final boolean hasDownstreamConfiguration =
+                (cfg.tetherableUsbRegexs.length != 0)
+                || (cfg.tetherableWifiRegexs.length != 0)
+                || (cfg.tetherableBluetoothRegexs.length != 0);
+        final boolean hasUpstreamConfiguration = !cfg.preferredUpstreamIfaceTypes.isEmpty()
+                || cfg.chooseUpstreamAutomatically;
+
+        return hasDownstreamConfiguration && hasUpstreamConfiguration;
+    }
+
+    // TODO - update callers to use getTetheringConfiguration(),
+    // which has only final members.
+    String[] getTetherableUsbRegexs() {
+        return copy(mConfig.tetherableUsbRegexs);
+    }
+
+    String[] getTetherableWifiRegexs() {
+        return copy(mConfig.tetherableWifiRegexs);
+    }
+
+    String[] getTetherableBluetoothRegexs() {
+        return copy(mConfig.tetherableBluetoothRegexs);
+    }
+
+    int setUsbTethering(boolean enable) {
+        if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")");
+        UsbManager usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
+        if (usbManager == null) {
+            mLog.e("setUsbTethering: failed to get UsbManager!");
+            return TETHER_ERROR_SERVICE_UNAVAIL;
+        }
+
+        synchronized (mPublicSync) {
+            usbManager.setCurrentFunctions(enable ? UsbManager.FUNCTION_RNDIS
+                    : UsbManager.FUNCTION_NONE);
+        }
+        return TETHER_ERROR_NO_ERROR;
+    }
+
+    // TODO review API - figure out how to delete these entirely.
+    String[] getTetheredIfaces() {
+        ArrayList<String> list = new ArrayList<String>();
+        synchronized (mPublicSync) {
+            for (int i = 0; i < mTetherStates.size(); i++) {
+                TetherState tetherState = mTetherStates.valueAt(i);
+                if (tetherState.lastState == IpServer.STATE_TETHERED) {
+                    list.add(mTetherStates.keyAt(i));
+                }
+            }
+        }
+        return list.toArray(new String[list.size()]);
+    }
+
+    String[] getTetherableIfaces() {
+        ArrayList<String> list = new ArrayList<String>();
+        synchronized (mPublicSync) {
+            for (int i = 0; i < mTetherStates.size(); i++) {
+                TetherState tetherState = mTetherStates.valueAt(i);
+                if (tetherState.lastState == IpServer.STATE_AVAILABLE) {
+                    list.add(mTetherStates.keyAt(i));
+                }
+            }
+        }
+        return list.toArray(new String[list.size()]);
+    }
+
+    String[] getTetheredDhcpRanges() {
+        // TODO: this is only valid for the old DHCP server. Latest search suggests it is only used
+        // by WifiP2pServiceImpl to start dnsmasq: remove/deprecate after migrating callers.
+        return mConfig.legacyDhcpRanges;
+    }
+
+    String[] getErroredIfaces() {
+        ArrayList<String> list = new ArrayList<String>();
+        synchronized (mPublicSync) {
+            for (int i = 0; i < mTetherStates.size(); i++) {
+                TetherState tetherState = mTetherStates.valueAt(i);
+                if (tetherState.lastError != TETHER_ERROR_NO_ERROR) {
+                    list.add(mTetherStates.keyAt(i));
+                }
+            }
+        }
+        return list.toArray(new String[list.size()]);
+    }
+
+    private void logMessage(State state, int what) {
+        mLog.log(state.getName() + " got " + sMagicDecoderRing.get(what, Integer.toString(what)));
+    }
+
+    private boolean upstreamWanted() {
+        if (!mForwardedDownstreams.isEmpty()) return true;
+
+        synchronized (mPublicSync) {
+            return mWifiTetherRequested;
+        }
+    }
+
+    // Needed because the canonical source of upstream truth is just the
+    // upstream interface set, |mCurrentUpstreamIfaceSet|.
+    private boolean pertainsToCurrentUpstream(NetworkState ns) {
+        if (ns != null && ns.linkProperties != null && mCurrentUpstreamIfaceSet != null) {
+            for (String ifname : ns.linkProperties.getAllInterfaceNames()) {
+                if (mCurrentUpstreamIfaceSet.ifnames.contains(ifname)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    class TetherMasterSM extends StateMachine {
+        private static final int BASE_MASTER                    = Protocol.BASE_TETHERING;
+        // an interface SM has requested Tethering/Local Hotspot
+        static final int EVENT_IFACE_SERVING_STATE_ACTIVE       = BASE_MASTER + 1;
+        // an interface SM has unrequested Tethering/Local Hotspot
+        static final int EVENT_IFACE_SERVING_STATE_INACTIVE     = BASE_MASTER + 2;
+        // upstream connection change - do the right thing
+        static final int CMD_UPSTREAM_CHANGED                   = BASE_MASTER + 3;
+        // we don't have a valid upstream conn, check again after a delay
+        static final int CMD_RETRY_UPSTREAM                     = BASE_MASTER + 4;
+        // Events from NetworkCallbacks that we process on the master state
+        // machine thread on behalf of the UpstreamNetworkMonitor.
+        static final int EVENT_UPSTREAM_CALLBACK                = BASE_MASTER + 5;
+        // we treated the error and want now to clear it
+        static final int CMD_CLEAR_ERROR                        = BASE_MASTER + 6;
+        static final int EVENT_IFACE_UPDATE_LINKPROPERTIES      = BASE_MASTER + 7;
+        // Events from EntitlementManager to choose upstream again.
+        static final int EVENT_UPSTREAM_PERMISSION_CHANGED      = BASE_MASTER + 8;
+
+        private final State mInitialState;
+        private final State mTetherModeAliveState;
+
+        private final State mSetIpForwardingEnabledErrorState;
+        private final State mSetIpForwardingDisabledErrorState;
+        private final State mStartTetheringErrorState;
+        private final State mStopTetheringErrorState;
+        private final State mSetDnsForwardersErrorState;
+
+        // This list is a little subtle.  It contains all the interfaces that currently are
+        // requesting tethering, regardless of whether these interfaces are still members of
+        // mTetherStates.  This allows us to maintain the following predicates:
+        //
+        // 1) mTetherStates contains the set of all currently existing, tetherable, link state up
+        //    interfaces.
+        // 2) mNotifyList contains all state machines that may have outstanding tethering state
+        //    that needs to be torn down.
+        //
+        // Because we excise interfaces immediately from mTetherStates, we must maintain mNotifyList
+        // so that the garbage collector does not clean up the state machine before it has a chance
+        // to tear itself down.
+        private final ArrayList<IpServer> mNotifyList;
+        private final IPv6TetheringCoordinator mIPv6TetheringCoordinator;
+        private final OffloadWrapper mOffload;
+
+        private static final int UPSTREAM_SETTLE_TIME_MS     = 10000;
+
+        TetherMasterSM(String name, Looper looper, TetheringDependencies deps) {
+            super(name, looper);
+
+            mInitialState = new InitialState();
+            mTetherModeAliveState = new TetherModeAliveState();
+            mSetIpForwardingEnabledErrorState = new SetIpForwardingEnabledErrorState();
+            mSetIpForwardingDisabledErrorState = new SetIpForwardingDisabledErrorState();
+            mStartTetheringErrorState = new StartTetheringErrorState();
+            mStopTetheringErrorState = new StopTetheringErrorState();
+            mSetDnsForwardersErrorState = new SetDnsForwardersErrorState();
+
+            addState(mInitialState);
+            addState(mTetherModeAliveState);
+            addState(mSetIpForwardingEnabledErrorState);
+            addState(mSetIpForwardingDisabledErrorState);
+            addState(mStartTetheringErrorState);
+            addState(mStopTetheringErrorState);
+            addState(mSetDnsForwardersErrorState);
+
+            mNotifyList = new ArrayList<>();
+            mIPv6TetheringCoordinator = deps.getIPv6TetheringCoordinator(mNotifyList, mLog);
+            mOffload = new OffloadWrapper();
+
+            setInitialState(mInitialState);
+        }
+
+        class InitialState extends State {
+            @Override
+            public boolean processMessage(Message message) {
+                logMessage(this, message.what);
+                switch (message.what) {
+                    case EVENT_IFACE_SERVING_STATE_ACTIVE: {
+                        final IpServer who = (IpServer) message.obj;
+                        if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
+                        handleInterfaceServingStateActive(message.arg1, who);
+                        transitionTo(mTetherModeAliveState);
+                        break;
+                    }
+                    case EVENT_IFACE_SERVING_STATE_INACTIVE: {
+                        final IpServer who = (IpServer) message.obj;
+                        if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
+                        handleInterfaceServingStateInactive(who);
+                        break;
+                    }
+                    case EVENT_IFACE_UPDATE_LINKPROPERTIES:
+                        // Silently ignore these for now.
+                        break;
+                    default:
+                        return NOT_HANDLED;
+                }
+                return HANDLED;
+            }
+        }
+
+        protected boolean turnOnMasterTetherSettings() {
+            final TetheringConfiguration cfg = mConfig;
+            try {
+                mNMService.setIpForwardingEnabled(true);
+            } catch (Exception e) {
+                mLog.e(e);
+                transitionTo(mSetIpForwardingEnabledErrorState);
+                return false;
+            }
+            // TODO: Randomize DHCPv4 ranges, especially in hotspot mode.
+            // Legacy DHCP server is disabled if passed an empty ranges array
+            final String[] dhcpRanges = cfg.enableLegacyDhcpServer
+                    ? cfg.legacyDhcpRanges
+                    : new String[0];
+            try {
+                // TODO: Find a more accurate method name (startDHCPv4()?).
+                mNMService.startTethering(dhcpRanges);
+            } catch (Exception e) {
+                try {
+                    mNMService.stopTethering();
+                    mNMService.startTethering(dhcpRanges);
+                } catch (Exception ee) {
+                    mLog.e(ee);
+                    transitionTo(mStartTetheringErrorState);
+                    return false;
+                }
+            }
+            mLog.log("SET master tether settings: ON");
+            return true;
+        }
+
+        protected boolean turnOffMasterTetherSettings() {
+            try {
+                mNMService.stopTethering();
+            } catch (Exception e) {
+                mLog.e(e);
+                transitionTo(mStopTetheringErrorState);
+                return false;
+            }
+            try {
+                mNMService.setIpForwardingEnabled(false);
+            } catch (Exception e) {
+                mLog.e(e);
+                transitionTo(mSetIpForwardingDisabledErrorState);
+                return false;
+            }
+            transitionTo(mInitialState);
+            mLog.log("SET master tether settings: OFF");
+            return true;
+        }
+
+        protected void chooseUpstreamType(boolean tryCell) {
+            // We rebuild configuration on ACTION_CONFIGURATION_CHANGED, but we
+            // do not currently know how to watch for changes in DUN settings.
+            maybeDunSettingChanged();
+
+            final TetheringConfiguration config = mConfig;
+            final NetworkState ns = (config.chooseUpstreamAutomatically)
+                    ? mUpstreamNetworkMonitor.getCurrentPreferredUpstream()
+                    : mUpstreamNetworkMonitor.selectPreferredUpstreamType(
+                            config.preferredUpstreamIfaceTypes);
+            if (ns == null) {
+                if (tryCell) {
+                    mUpstreamNetworkMonitor.registerMobileNetworkRequest();
+                    // We think mobile should be coming up; don't set a retry.
+                } else {
+                    sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
+                }
+            }
+            setUpstreamNetwork(ns);
+            final Network newUpstream = (ns != null) ? ns.network : null;
+            if (mTetherUpstream != newUpstream) {
+                mTetherUpstream = newUpstream;
+                mUpstreamNetworkMonitor.setCurrentUpstream(mTetherUpstream);
+                reportUpstreamChanged(mTetherUpstream);
+            }
+        }
+
+        protected void setUpstreamNetwork(NetworkState ns) {
+            InterfaceSet ifaces = null;
+            if (ns != null) {
+                // Find the interface with the default IPv4 route. It may be the
+                // interface described by linkProperties, or one of the interfaces
+                // stacked on top of it.
+                mLog.i("Looking for default routes on: " + ns.linkProperties);
+                ifaces = TetheringInterfaceUtils.getTetheringInterfaces(ns);
+                mLog.i("Found upstream interface(s): " + ifaces);
+            }
+
+            if (ifaces != null) {
+                setDnsForwarders(ns.network, ns.linkProperties);
+            }
+            notifyDownstreamsOfNewUpstreamIface(ifaces);
+            if (ns != null && pertainsToCurrentUpstream(ns)) {
+                // If we already have NetworkState for this network update it immediately.
+                handleNewUpstreamNetworkState(ns);
+            } else if (mCurrentUpstreamIfaceSet == null) {
+                // There are no available upstream networks.
+                handleNewUpstreamNetworkState(null);
+            }
+        }
+
+        protected void setDnsForwarders(final Network network, final LinkProperties lp) {
+            // TODO: Set v4 and/or v6 DNS per available connectivity.
+            String[] dnsServers = mConfig.defaultIPv4DNS;
+            final Collection<InetAddress> dnses = lp.getDnsServers();
+            // TODO: Properly support the absence of DNS servers.
+            if (dnses != null && !dnses.isEmpty()) {
+                // TODO: remove this invocation of NetworkUtils.makeStrings().
+                dnsServers = NetworkUtils.makeStrings(dnses);
+            }
+            try {
+                mNMService.setDnsForwarders(network, dnsServers);
+                mLog.log(String.format(
+                        "SET DNS forwarders: network=%s dnsServers=%s",
+                        network, Arrays.toString(dnsServers)));
+            } catch (Exception e) {
+                // TODO: Investigate how this can fail and what exactly
+                // happens if/when such failures occur.
+                mLog.e("setting DNS forwarders failed, " + e);
+                transitionTo(mSetDnsForwardersErrorState);
+            }
+        }
+
+        protected void notifyDownstreamsOfNewUpstreamIface(InterfaceSet ifaces) {
+            mCurrentUpstreamIfaceSet = ifaces;
+            for (IpServer ipServer : mNotifyList) {
+                ipServer.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED, ifaces);
+            }
+        }
+
+        protected void handleNewUpstreamNetworkState(NetworkState ns) {
+            mIPv6TetheringCoordinator.updateUpstreamNetworkState(ns);
+            mOffload.updateUpstreamNetworkState(ns);
+        }
+
+        private void handleInterfaceServingStateActive(int mode, IpServer who) {
+            if (mNotifyList.indexOf(who) < 0) {
+                mNotifyList.add(who);
+                mIPv6TetheringCoordinator.addActiveDownstream(who, mode);
+            }
+
+            if (mode == IpServer.STATE_TETHERED) {
+                // No need to notify OffloadController just yet as there are no
+                // "offload-able" prefixes to pass along. This will handled
+                // when the TISM informs Tethering of its LinkProperties.
+                mForwardedDownstreams.add(who);
+            } else {
+                mOffload.excludeDownstreamInterface(who.interfaceName());
+                mForwardedDownstreams.remove(who);
+            }
+
+            // If this is a Wi-Fi interface, notify WifiManager of the active serving state.
+            if (who.interfaceType() == TETHERING_WIFI) {
+                final WifiManager mgr = getWifiManager();
+                final String iface = who.interfaceName();
+                switch (mode) {
+                    case IpServer.STATE_TETHERED:
+                        mgr.updateInterfaceIpState(iface, IFACE_IP_MODE_TETHERED);
+                        break;
+                    case IpServer.STATE_LOCAL_ONLY:
+                        mgr.updateInterfaceIpState(iface, IFACE_IP_MODE_LOCAL_ONLY);
+                        break;
+                    default:
+                        Log.wtf(TAG, "Unknown active serving mode: " + mode);
+                        break;
+                }
+            }
+        }
+
+        private void handleInterfaceServingStateInactive(IpServer who) {
+            mNotifyList.remove(who);
+            mIPv6TetheringCoordinator.removeActiveDownstream(who);
+            mOffload.excludeDownstreamInterface(who.interfaceName());
+            mForwardedDownstreams.remove(who);
+
+            // If this is a Wi-Fi interface, tell WifiManager of any errors
+            // or the inactive serving state.
+            if (who.interfaceType() == TETHERING_WIFI) {
+                if (who.lastError() != TETHER_ERROR_NO_ERROR) {
+                    getWifiManager().updateInterfaceIpState(
+                            who.interfaceName(), IFACE_IP_MODE_CONFIGURATION_ERROR);
+                } else {
+                    getWifiManager().updateInterfaceIpState(
+                            who.interfaceName(), IFACE_IP_MODE_UNSPECIFIED);
+                }
+            }
+        }
+
+        private void handleUpstreamNetworkMonitorCallback(int arg1, Object o) {
+            if (arg1 == UpstreamNetworkMonitor.NOTIFY_LOCAL_PREFIXES) {
+                mOffload.sendOffloadExemptPrefixes((Set<IpPrefix>) o);
+                return;
+            }
+
+            final NetworkState ns = (NetworkState) o;
+
+            if (ns == null || !pertainsToCurrentUpstream(ns)) {
+                // TODO: In future, this is where upstream evaluation and selection
+                // could be handled for notifications which include sufficient data.
+                // For example, after CONNECTIVITY_ACTION listening is removed, here
+                // is where we could observe a Wi-Fi network becoming available and
+                // passing validation.
+                if (mCurrentUpstreamIfaceSet == null) {
+                    // If we have no upstream interface, try to run through upstream
+                    // selection again.  If, for example, IPv4 connectivity has shown up
+                    // after IPv6 (e.g., 464xlat became available) we want the chance to
+                    // notice and act accordingly.
+                    chooseUpstreamType(false);
+                }
+                return;
+            }
+
+            switch (arg1) {
+                case UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES:
+                    handleNewUpstreamNetworkState(ns);
+                    break;
+                case UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES:
+                    chooseUpstreamType(false);
+                    break;
+                case UpstreamNetworkMonitor.EVENT_ON_LOST:
+                    // TODO: Re-evaluate possible upstreams. Currently upstream
+                    // reevaluation is triggered via received CONNECTIVITY_ACTION
+                    // broadcasts that result in being passed a
+                    // TetherMasterSM.CMD_UPSTREAM_CHANGED.
+                    handleNewUpstreamNetworkState(null);
+                    break;
+                default:
+                    mLog.e("Unknown arg1 value: " + arg1);
+                    break;
+            }
+        }
+
+        class TetherModeAliveState extends State {
+            boolean mUpstreamWanted = false;
+            boolean mTryCell = true;
+
+            @Override
+            public void enter() {
+                // If turning on master tether settings fails, we have already
+                // transitioned to an error state; exit early.
+                if (!turnOnMasterTetherSettings()) {
+                    return;
+                }
+
+                mUpstreamNetworkMonitor.startObserveAllNetworks();
+
+                // TODO: De-duplicate with updateUpstreamWanted() below.
+                if (upstreamWanted()) {
+                    mUpstreamWanted = true;
+                    mOffload.start();
+                    chooseUpstreamType(true);
+                    mTryCell = false;
+                }
+            }
+
+            @Override
+            public void exit() {
+                mOffload.stop();
+                mUpstreamNetworkMonitor.stop();
+                notifyDownstreamsOfNewUpstreamIface(null);
+                handleNewUpstreamNetworkState(null);
+                if (mTetherUpstream != null) {
+                    mTetherUpstream = null;
+                    reportUpstreamChanged(null);
+                }
+            }
+
+            private boolean updateUpstreamWanted() {
+                final boolean previousUpstreamWanted = mUpstreamWanted;
+                mUpstreamWanted = upstreamWanted();
+                if (mUpstreamWanted != previousUpstreamWanted) {
+                    if (mUpstreamWanted) {
+                        mOffload.start();
+                    } else {
+                        mOffload.stop();
+                    }
+                }
+                return previousUpstreamWanted;
+            }
+
+            @Override
+            public boolean processMessage(Message message) {
+                logMessage(this, message.what);
+                boolean retValue = true;
+                switch (message.what) {
+                    case EVENT_IFACE_SERVING_STATE_ACTIVE: {
+                        IpServer who = (IpServer) message.obj;
+                        if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
+                        handleInterfaceServingStateActive(message.arg1, who);
+                        who.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED,
+                                mCurrentUpstreamIfaceSet);
+                        // If there has been a change and an upstream is now
+                        // desired, kick off the selection process.
+                        final boolean previousUpstreamWanted = updateUpstreamWanted();
+                        if (!previousUpstreamWanted && mUpstreamWanted) {
+                            chooseUpstreamType(true);
+                        }
+                        break;
+                    }
+                    case EVENT_IFACE_SERVING_STATE_INACTIVE: {
+                        IpServer who = (IpServer) message.obj;
+                        if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
+                        handleInterfaceServingStateInactive(who);
+
+                        if (mNotifyList.isEmpty()) {
+                            // This transitions us out of TetherModeAliveState,
+                            // either to InitialState or an error state.
+                            turnOffMasterTetherSettings();
+                            break;
+                        }
+
+                        if (DBG) {
+                            Log.d(TAG, "TetherModeAlive still has " + mNotifyList.size()
+                                    + " live requests:");
+                            for (IpServer o : mNotifyList) {
+                                Log.d(TAG, "  " + o);
+                            }
+                        }
+                        // If there has been a change and an upstream is no
+                        // longer desired, release any mobile requests.
+                        final boolean previousUpstreamWanted = updateUpstreamWanted();
+                        if (previousUpstreamWanted && !mUpstreamWanted) {
+                            mUpstreamNetworkMonitor.releaseMobileNetworkRequest();
+                        }
+                        break;
+                    }
+                    case EVENT_IFACE_UPDATE_LINKPROPERTIES: {
+                        final LinkProperties newLp = (LinkProperties) message.obj;
+                        if (message.arg1 == IpServer.STATE_TETHERED) {
+                            mOffload.updateDownstreamLinkProperties(newLp);
+                        } else {
+                            mOffload.excludeDownstreamInterface(newLp.getInterfaceName());
+                        }
+                        break;
+                    }
+                    case EVENT_UPSTREAM_PERMISSION_CHANGED:
+                    case CMD_UPSTREAM_CHANGED:
+                        updateUpstreamWanted();
+                        if (!mUpstreamWanted) break;
+
+                        // Need to try DUN immediately if Wi-Fi goes down.
+                        chooseUpstreamType(true);
+                        mTryCell = false;
+                        break;
+                    case CMD_RETRY_UPSTREAM:
+                        updateUpstreamWanted();
+                        if (!mUpstreamWanted) break;
+
+                        chooseUpstreamType(mTryCell);
+                        mTryCell = !mTryCell;
+                        break;
+                    case EVENT_UPSTREAM_CALLBACK: {
+                        updateUpstreamWanted();
+                        if (mUpstreamWanted) {
+                            handleUpstreamNetworkMonitorCallback(message.arg1, message.obj);
+                        }
+                        break;
+                    }
+                    default:
+                        retValue = false;
+                        break;
+                }
+                return retValue;
+            }
+        }
+
+        class ErrorState extends State {
+            private int mErrorNotification;
+
+            @Override
+            public boolean processMessage(Message message) {
+                boolean retValue = true;
+                switch (message.what) {
+                    case EVENT_IFACE_SERVING_STATE_ACTIVE:
+                        IpServer who = (IpServer) message.obj;
+                        who.sendMessage(mErrorNotification);
+                        break;
+                    case CMD_CLEAR_ERROR:
+                        mErrorNotification = TETHER_ERROR_NO_ERROR;
+                        transitionTo(mInitialState);
+                        break;
+                    default:
+                        retValue = false;
+                }
+                return retValue;
+            }
+
+            void notify(int msgType) {
+                mErrorNotification = msgType;
+                for (IpServer ipServer : mNotifyList) {
+                    ipServer.sendMessage(msgType);
+                }
+            }
+
+        }
+
+        class SetIpForwardingEnabledErrorState extends ErrorState {
+            @Override
+            public void enter() {
+                Log.e(TAG, "Error in setIpForwardingEnabled");
+                notify(IpServer.CMD_IP_FORWARDING_ENABLE_ERROR);
+            }
+        }
+
+        class SetIpForwardingDisabledErrorState extends ErrorState {
+            @Override
+            public void enter() {
+                Log.e(TAG, "Error in setIpForwardingDisabled");
+                notify(IpServer.CMD_IP_FORWARDING_DISABLE_ERROR);
+            }
+        }
+
+        class StartTetheringErrorState extends ErrorState {
+            @Override
+            public void enter() {
+                Log.e(TAG, "Error in startTethering");
+                notify(IpServer.CMD_START_TETHERING_ERROR);
+                try {
+                    mNMService.setIpForwardingEnabled(false);
+                } catch (Exception e) { }
+            }
+        }
+
+        class StopTetheringErrorState extends ErrorState {
+            @Override
+            public void enter() {
+                Log.e(TAG, "Error in stopTethering");
+                notify(IpServer.CMD_STOP_TETHERING_ERROR);
+                try {
+                    mNMService.setIpForwardingEnabled(false);
+                } catch (Exception e) { }
+            }
+        }
+
+        class SetDnsForwardersErrorState extends ErrorState {
+            @Override
+            public void enter() {
+                Log.e(TAG, "Error in setDnsForwarders");
+                notify(IpServer.CMD_SET_DNS_FORWARDERS_ERROR);
+                try {
+                    mNMService.stopTethering();
+                } catch (Exception e) { }
+                try {
+                    mNMService.setIpForwardingEnabled(false);
+                } catch (Exception e) { }
+            }
+        }
+
+        // A wrapper class to handle multiple situations where several calls to
+        // the OffloadController need to happen together.
+        //
+        // TODO: This suggests that the interface between OffloadController and
+        // Tethering is in need of improvement. Refactor these calls into the
+        // OffloadController implementation.
+        class OffloadWrapper {
+            public void start() {
+                mOffloadController.start();
+                sendOffloadExemptPrefixes();
+            }
+
+            public void stop() {
+                mOffloadController.stop();
+            }
+
+            public void updateUpstreamNetworkState(NetworkState ns) {
+                mOffloadController.setUpstreamLinkProperties(
+                        (ns != null) ? ns.linkProperties : null);
+            }
+
+            public void updateDownstreamLinkProperties(LinkProperties newLp) {
+                // Update the list of offload-exempt prefixes before adding
+                // new prefixes on downstream interfaces to the offload HAL.
+                sendOffloadExemptPrefixes();
+                mOffloadController.notifyDownstreamLinkProperties(newLp);
+            }
+
+            public void excludeDownstreamInterface(String ifname) {
+                // This and other interfaces may be in local-only hotspot mode;
+                // resend all local prefixes to the OffloadController.
+                sendOffloadExemptPrefixes();
+                mOffloadController.removeDownstreamInterface(ifname);
+            }
+
+            public void sendOffloadExemptPrefixes() {
+                sendOffloadExemptPrefixes(mUpstreamNetworkMonitor.getLocalPrefixes());
+            }
+
+            public void sendOffloadExemptPrefixes(final Set<IpPrefix> localPrefixes) {
+                // Add in well-known minimum set.
+                PrefixUtils.addNonForwardablePrefixes(localPrefixes);
+                // Add tragically hardcoded prefixes.
+                localPrefixes.add(PrefixUtils.DEFAULT_WIFI_P2P_PREFIX);
+
+                // Maybe add prefixes or addresses for downstreams, depending on
+                // the IP serving mode of each.
+                for (IpServer ipServer : mNotifyList) {
+                    final LinkProperties lp = ipServer.linkProperties();
+
+                    switch (ipServer.servingMode()) {
+                        case IpServer.STATE_UNAVAILABLE:
+                        case IpServer.STATE_AVAILABLE:
+                            // No usable LinkProperties in these states.
+                            continue;
+                        case IpServer.STATE_TETHERED:
+                            // Only add IPv4 /32 and IPv6 /128 prefixes. The
+                            // directly-connected prefixes will be sent as
+                            // downstream "offload-able" prefixes.
+                            for (LinkAddress addr : lp.getAllLinkAddresses()) {
+                                final InetAddress ip = addr.getAddress();
+                                if (ip.isLinkLocalAddress()) continue;
+                                localPrefixes.add(PrefixUtils.ipAddressAsPrefix(ip));
+                            }
+                            break;
+                        case IpServer.STATE_LOCAL_ONLY:
+                            // Add prefixes covering all local IPs.
+                            localPrefixes.addAll(PrefixUtils.localPrefixesFrom(lp));
+                            break;
+                    }
+                }
+
+                mOffloadController.setLocalPrefixes(localPrefixes);
+            }
+        }
+    }
+
+    private void startTrackDefaultNetwork() {
+        mUpstreamNetworkMonitor.startTrackDefaultNetwork(mDeps.getDefaultNetworkRequest(),
+                mEntitlementMgr);
+    }
+
+    /** Get the latest value of the tethering entitlement check. */
+    void requestLatestTetheringEntitlementResult(int type, ResultReceiver receiver,
+            boolean showEntitlementUi) {
+        if (receiver != null) {
+            mEntitlementMgr.requestLatestTetheringEntitlementResult(type, receiver,
+                    showEntitlementUi);
+        }
+    }
+
+    /** Register tethering event callback */
+    void registerTetherInternalCallback(ITetherInternalCallback callback) {
+        mHandler.post(() -> {
+            mTetherInternalCallback = callback;
+            try {
+                mTetherInternalCallback.onCallbackCreated(mTetherUpstream,
+                        mConfig.toStableParcelable(), mTetherStatesParcel);
+            } catch (RemoteException e) {
+                // Not really very much to do here.
+            }
+        });
+    }
+
+    private void reportUpstreamChanged(Network network) {
+        // Don't need to synchronized mTetherInternalCallback because all the usage of this variable
+        // should run at the same thread.
+        if (mTetherInternalCallback == null) return;
+
+        try {
+            mTetherInternalCallback.onUpstreamChanged(network);
+        } catch (RemoteException e) {
+            // Not really very much to do here.
+        }
+    }
+
+    private void reportConfigurationChanged(TetheringConfigurationParcel config) {
+        if (mTetherInternalCallback == null) return;
+
+        try {
+            mTetherInternalCallback.onConfigurationChanged(config);
+        } catch (RemoteException e) {
+            // Not really very much to do here.
+        }
+    }
+
+    private void reportTetherStateChanged(TetherStatesParcel states) {
+        if (mTetherInternalCallback == null) return;
+
+        try {
+            mTetherInternalCallback.onTetherStatesChanged(states);
+        } catch (RemoteException e) {
+            // Not really very much to do here.
+        }
+    }
+
+    void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+        // Binder.java closes the resource for us.
+        @SuppressWarnings("resource")
+        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
+        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+
+        pw.println("Tethering:");
+        pw.increaseIndent();
+
+        pw.println("Configuration:");
+        pw.increaseIndent();
+        final TetheringConfiguration cfg = mConfig;
+        cfg.dump(pw);
+        pw.decreaseIndent();
+
+        pw.println("Entitlement:");
+        pw.increaseIndent();
+        mEntitlementMgr.dump(pw);
+        pw.decreaseIndent();
+
+        synchronized (mPublicSync) {
+            pw.println("Tether state:");
+            pw.increaseIndent();
+            for (int i = 0; i < mTetherStates.size(); i++) {
+                final String iface = mTetherStates.keyAt(i);
+                final TetherState tetherState = mTetherStates.valueAt(i);
+                pw.print(iface + " - ");
+
+                switch (tetherState.lastState) {
+                    case IpServer.STATE_UNAVAILABLE:
+                        pw.print("UnavailableState");
+                        break;
+                    case IpServer.STATE_AVAILABLE:
+                        pw.print("AvailableState");
+                        break;
+                    case IpServer.STATE_TETHERED:
+                        pw.print("TetheredState");
+                        break;
+                    case IpServer.STATE_LOCAL_ONLY:
+                        pw.print("LocalHotspotState");
+                        break;
+                    default:
+                        pw.print("UnknownState");
+                        break;
+                }
+                pw.println(" - lastError = " + tetherState.lastError);
+            }
+            pw.println("Upstream wanted: " + upstreamWanted());
+            pw.println("Current upstream interface(s): " + mCurrentUpstreamIfaceSet);
+            pw.decreaseIndent();
+        }
+
+        pw.println("Hardware offload:");
+        pw.increaseIndent();
+        mOffloadController.dump(pw);
+        pw.decreaseIndent();
+
+        pw.println("Log:");
+        pw.increaseIndent();
+        if (argsContain(args, "--short")) {
+            pw.println("<log removed for brevity>");
+        } else {
+            mLog.dump(fd, pw, args);
+        }
+        pw.decreaseIndent();
+
+        pw.decreaseIndent();
+    }
+
+    private static boolean argsContain(String[] args, String target) {
+        for (String arg : args) {
+            if (target.equals(arg)) return true;
+        }
+        return false;
+    }
+
+    private IpServer.Callback makeControlCallback() {
+        return new IpServer.Callback() {
+            @Override
+            public void updateInterfaceState(IpServer who, int state, int lastError) {
+                notifyInterfaceStateChange(who, state, lastError);
+            }
+
+            @Override
+            public void updateLinkProperties(IpServer who, LinkProperties newLp) {
+                notifyLinkPropertiesChanged(who, newLp);
+            }
+        };
+    }
+
+    // TODO: Move into TetherMasterSM.
+    private void notifyInterfaceStateChange(IpServer who, int state, int error) {
+        final String iface = who.interfaceName();
+        synchronized (mPublicSync) {
+            final TetherState tetherState = mTetherStates.get(iface);
+            if (tetherState != null && tetherState.ipServer.equals(who)) {
+                tetherState.lastState = state;
+                tetherState.lastError = error;
+            } else {
+                if (DBG) Log.d(TAG, "got notification from stale iface " + iface);
+            }
+        }
+
+        mLog.log(String.format("OBSERVED iface=%s state=%s error=%s", iface, state, error));
+
+        try {
+            // Notify that we're tethering (or not) this interface.
+            // This is how data saver for instance knows if the user explicitly
+            // turned on tethering (thus keeping us from being in data saver mode).
+            mPolicyManager.onTetheringChanged(iface, state == IpServer.STATE_TETHERED);
+        } catch (RemoteException e) {
+            // Not really very much we can do here.
+        }
+
+        // If TetherMasterSM is in ErrorState, TetherMasterSM stays there.
+        // Thus we give a chance for TetherMasterSM to recover to InitialState
+        // by sending CMD_CLEAR_ERROR
+        if (error == TETHER_ERROR_MASTER_ERROR) {
+            mTetherMasterSM.sendMessage(TetherMasterSM.CMD_CLEAR_ERROR, who);
+        }
+        int which;
+        switch (state) {
+            case IpServer.STATE_UNAVAILABLE:
+            case IpServer.STATE_AVAILABLE:
+                which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_INACTIVE;
+                break;
+            case IpServer.STATE_TETHERED:
+            case IpServer.STATE_LOCAL_ONLY:
+                which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_ACTIVE;
+                break;
+            default:
+                Log.wtf(TAG, "Unknown interface state: " + state);
+                return;
+        }
+        mTetherMasterSM.sendMessage(which, state, 0, who);
+        sendTetherStateChangedBroadcast();
+    }
+
+    private void notifyLinkPropertiesChanged(IpServer who, LinkProperties newLp) {
+        final String iface = who.interfaceName();
+        final int state;
+        synchronized (mPublicSync) {
+            final TetherState tetherState = mTetherStates.get(iface);
+            if (tetherState != null && tetherState.ipServer.equals(who)) {
+                state = tetherState.lastState;
+            } else {
+                mLog.log("got notification from stale iface " + iface);
+                return;
+            }
+        }
+
+        mLog.log(String.format(
+                "OBSERVED LinkProperties update iface=%s state=%s lp=%s",
+                iface, IpServer.getStateString(state), newLp));
+        final int which = TetherMasterSM.EVENT_IFACE_UPDATE_LINKPROPERTIES;
+        mTetherMasterSM.sendMessage(which, state, 0, newLp);
+    }
+
+    private void maybeTrackNewInterfaceLocked(final String iface) {
+        // If we don't care about this type of interface, ignore.
+        final int interfaceType = ifaceNameToType(iface);
+        if (interfaceType == TETHERING_INVALID) {
+            mLog.log(iface + " is not a tetherable iface, ignoring");
+            return;
+        }
+        maybeTrackNewInterfaceLocked(iface, interfaceType);
+    }
+
+    private void maybeTrackNewInterfaceLocked(final String iface, int interfaceType) {
+        // If we have already started a TISM for this interface, skip.
+        if (mTetherStates.containsKey(iface)) {
+            mLog.log("active iface (" + iface + ") reported as added, ignoring");
+            return;
+        }
+
+        mLog.log("adding TetheringInterfaceStateMachine for: " + iface);
+        final TetherState tetherState = new TetherState(
+                new IpServer(iface, mLooper, interfaceType, mLog, mNMService, mStatsService,
+                             makeControlCallback(), mConfig.enableLegacyDhcpServer,
+                             mDeps.getIpServerDependencies()));
+        mTetherStates.put(iface, tetherState);
+        tetherState.ipServer.start();
+    }
+
+    private void stopTrackingInterfaceLocked(final String iface) {
+        final TetherState tetherState = mTetherStates.get(iface);
+        if (tetherState == null) {
+            mLog.log("attempting to remove unknown iface (" + iface + "), ignoring");
+            return;
+        }
+        tetherState.ipServer.stop();
+        mLog.log("removing TetheringInterfaceStateMachine for: " + iface);
+        mTetherStates.remove(iface);
+    }
+
+    private static String[] copy(String[] strarray) {
+        return Arrays.copyOf(strarray, strarray.length);
+    }
+}
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
index ca9b168..0ab4d63 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -38,6 +38,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.net.ConnectivityManager;
+import android.net.TetheringConfigurationParcel;
 import android.net.util.SharedLog;
 import android.provider.Settings;
 import android.telephony.SubscriptionManager;
@@ -384,4 +385,32 @@
         }
         return false;
     }
+
+    /**
+     * Convert this TetheringConfiguration to a TetheringConfigurationParcel.
+     */
+    public TetheringConfigurationParcel toStableParcelable() {
+        final TetheringConfigurationParcel parcel = new TetheringConfigurationParcel();
+        parcel.subId = subId;
+        parcel.tetherableUsbRegexs = tetherableUsbRegexs;
+        parcel.tetherableWifiRegexs = tetherableWifiRegexs;
+        parcel.tetherableBluetoothRegexs = tetherableBluetoothRegexs;
+        parcel.isDunRequired = isDunRequired;
+        parcel.chooseUpstreamAutomatically = chooseUpstreamAutomatically;
+
+        int[] preferredTypes = new int[preferredUpstreamIfaceTypes.size()];
+        int index = 0;
+        for (Integer type : preferredUpstreamIfaceTypes) {
+            preferredTypes[index++] = type;
+        }
+        parcel.preferredUpstreamIfaceTypes = preferredTypes;
+
+        parcel.legacyDhcpRanges = legacyDhcpRanges;
+        parcel.defaultIPv4DNS = defaultIPv4DNS;
+        parcel.enableLegacyDhcpServer = enableLegacyDhcpServer;
+        parcel.provisioningApp = provisioningApp;
+        parcel.provisioningAppNoUi = provisioningAppNoUi;
+        parcel.provisioningCheckPeriod = provisioningCheckPeriod;
+        return parcel;
+    }
 }
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java
new file mode 100644
index 0000000..0ba8412
--- /dev/null
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.tethering;
+
+import android.content.Context;
+import android.net.INetd;
+import android.net.INetworkPolicyManager;
+import android.net.INetworkStatsService;
+import android.net.NetworkRequest;
+import android.net.ip.IpServer;
+import android.net.util.SharedLog;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.INetworkManagementService;
+import android.os.Looper;
+import android.os.ServiceManager;
+
+import com.android.internal.util.StateMachine;
+
+import java.util.ArrayList;
+
+
+/**
+ * Capture tethering dependencies, for injection.
+ *
+ * @hide
+ */
+public class TetheringDependencies {
+    /**
+     * Get a reference to the offload hardware interface to be used by tethering.
+     */
+    public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) {
+        return new OffloadHardwareInterface(h, log);
+    }
+
+    /**
+     * Get a reference to the UpstreamNetworkMonitor to be used by tethering.
+     */
+    public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx, StateMachine target,
+            SharedLog log, int what) {
+        return new UpstreamNetworkMonitor(ctx, target, log, what);
+    }
+
+    /**
+     * Get a reference to the IPv6TetheringCoordinator to be used by tethering.
+     */
+    public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
+            ArrayList<IpServer> notifyList, SharedLog log) {
+        return new IPv6TetheringCoordinator(notifyList, log);
+    }
+
+    /**
+     * Get dependencies to be used by IpServer.
+     */
+    public IpServer.Dependencies getIpServerDependencies() {
+        return new IpServer.Dependencies();
+    }
+
+    /**
+     * Indicates whether tethering is supported on the device.
+     */
+    public boolean isTetheringSupported() {
+        return true;
+    }
+
+    /**
+     * Get the NetworkRequest that should be fulfilled by the default network.
+     */
+    public NetworkRequest getDefaultNetworkRequest() {
+        return null;
+    }
+
+    /**
+     * Get a reference to the EntitlementManager to be used by tethering.
+     */
+    public EntitlementManager getEntitlementManager(Context ctx, StateMachine target,
+            SharedLog log, int what) {
+        return new EntitlementManager(ctx, target, log, what);
+    }
+
+    /**
+     * Generate a new TetheringConfiguration according to input sub Id.
+     */
+    public TetheringConfiguration generateTetheringConfiguration(Context ctx, SharedLog log,
+            int subId) {
+        return new TetheringConfiguration(ctx, log, subId);
+    }
+
+    /**
+     * Get a reference to INetworkManagementService to registerTetheringStatsProvider from
+     * OffloadController. Note: This should be removed soon by Usage refactor work in R
+     * development cycle.
+     */
+    public INetworkManagementService getINetworkManagementService() {
+        return INetworkManagementService.Stub.asInterface(
+                ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
+    }
+
+    /**
+     *  Get a reference to INetworkStatsService to force update tethering usage.
+     *  Note: This should be removed in R development cycle.
+     */
+    public INetworkStatsService getINetworkStatsService() {
+        return INetworkStatsService.Stub.asInterface(
+                ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+    }
+
+    /**
+     * Get a reference to INetworkPolicyManager to be used by tethering.
+     */
+    public INetworkPolicyManager getINetworkPolicyManager() {
+        return INetworkPolicyManager.Stub.asInterface(
+                ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
+    }
+
+    /**
+     * Get a reference to INetd to be used by tethering.
+     */
+    public INetd getINetd(Context context) {
+        return INetd.Stub.asInterface(
+                (IBinder) context.getSystemService(Context.NETD_SERVICE));
+    }
+
+    /**
+     * Get tethering thread looper.
+     */
+    public Looper getTetheringLooper() {
+        return null;
+    }
+
+    /**
+     *  Get Context of TetheringSerice.
+     */
+    public Context getContext() {
+        return null;
+    }
+}
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java
similarity index 100%
rename from services/core/java/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java
rename to packages/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
new file mode 100644
index 0000000..456f2f7
--- /dev/null
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
@@ -0,0 +1,178 @@
+/*
+ * 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.connectivity.tethering;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.net.ConnectivityManager;
+import android.net.ITetherInternalCallback;
+import android.net.ITetheringConnector;
+import android.net.NetworkRequest;
+import android.net.util.SharedLog;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.ResultReceiver;
+import android.os.SystemProperties;
+import android.provider.Settings;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Android service used to manage tethering.
+ *
+ * <p>The service returns a binder for the system server to communicate with the tethering.
+ */
+public class TetheringService extends Service {
+    private static final String TAG = TetheringService.class.getSimpleName();
+
+    private final SharedLog mLog = new SharedLog(TAG);
+    private TetheringConnector mConnector;
+    private Context mContext;
+    private TetheringDependencies mDeps;
+    private Tethering mTethering;
+
+    @Override
+    public void onCreate() {
+        mLog.mark("onCreate");
+        mDeps = getTetheringDependencies();
+        mContext = mDeps.getContext();
+        mTethering = makeTethering(mDeps);
+    }
+
+    /**
+     * Make a reference to Tethering object.
+     */
+    @VisibleForTesting
+    public Tethering makeTethering(TetheringDependencies deps) {
+        return new Tethering(deps);
+    }
+
+    /**
+     * Create a binder connector for the system server to communicate with the tethering.
+     */
+    private synchronized IBinder makeConnector() {
+        if (mConnector == null) {
+            mConnector = new TetheringConnector(mTethering);
+        }
+        return mConnector;
+    }
+
+    @NonNull
+    @Override
+    public IBinder onBind(Intent intent) {
+        mLog.mark("onBind");
+        return makeConnector();
+    }
+
+    private static class TetheringConnector extends ITetheringConnector.Stub {
+        private final Tethering mService;
+
+        TetheringConnector(Tethering tether) {
+            mService = tether;
+        }
+
+        @Override
+        public void tether(String iface) {
+            mService.tether(iface);
+        }
+
+        @Override
+        public void untether(String iface) {
+            mService.untether(iface);
+        }
+
+        @Override
+        public void setUsbTethering(boolean enable) {
+            mService.setUsbTethering(enable);
+        }
+
+        @Override
+        public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
+            mService.startTethering(type, receiver, showProvisioningUi);
+        }
+
+        @Override
+        public void stopTethering(int type) {
+            mService.stopTethering(type);
+        }
+
+        @Override
+        public void requestLatestTetheringEntitlementResult(int type, ResultReceiver receiver,
+                boolean showEntitlementUi) {
+            mService.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi);
+        }
+
+        @Override
+        public void registerTetherInternalCallback(ITetherInternalCallback callback) {
+            mService.registerTetherInternalCallback(callback);
+        }
+    }
+
+    @Override
+    protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer,
+                @Nullable String[] args) {
+        mTethering.dump(fd, writer, args);
+    }
+
+    /**
+     * An injection method for testing.
+     */
+    @VisibleForTesting
+    public TetheringDependencies getTetheringDependencies() {
+        if (mDeps == null) {
+            mDeps = new TetheringDependencies() {
+                @Override
+                public NetworkRequest getDefaultNetworkRequest() {
+                    ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
+                            Context.CONNECTIVITY_SERVICE);
+                    return cm.getDefaultRequest();
+                }
+
+                @Override
+                public Looper getTetheringLooper() {
+                    final HandlerThread tetherThread = new HandlerThread("android.tethering");
+                    tetherThread.start();
+                    return tetherThread.getLooper();
+                }
+
+                @Override
+                public boolean isTetheringSupported() {
+                    int defaultVal =
+                            SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1;
+                    boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(),
+                            Settings.Global.TETHER_SUPPORTED, defaultVal) != 0;
+                    return tetherSupported;
+                }
+
+                @Override
+                public Context getContext() {
+                    return TetheringService.this;
+                }
+            };
+        }
+
+        return mDeps;
+    }
+}
diff --git a/packages/Tethering/tests/unit/Android.bp b/packages/Tethering/tests/unit/Android.bp
index 363be18..5b018df 100644
--- a/packages/Tethering/tests/unit/Android.bp
+++ b/packages/Tethering/tests/unit/Android.bp
@@ -18,7 +18,6 @@
     name: "TetheringTests",
     certificate: "platform",
     srcs: [
-        ":servicescore-tethering-src",
         "src/**/*.java",
     ],
     test_suites: ["device-tests"],
@@ -41,17 +40,3 @@
         "libstaticjvmtiagent",
     ],
 }
-
-// This group would be removed when tethering migration is done.
-filegroup {
-    name: "tethering-tests-src",
-    srcs: [
-        "src/com/android/server/connectivity/tethering/EntitlementManagerTest.java",
-        "src/com/android/server/connectivity/tethering/OffloadControllerTest.java",
-        "src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java",
-        "src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java",
-        "src/android/net/dhcp/DhcpServingParamsParcelExtTest.java",
-        "src/android/net/ip/IpServerTest.java",
-        "src/android/net/util/InterfaceSetTest.java",
-    ],
-}
diff --git a/packages/Tethering/tests/unit/src/android/net/util/VersionedBroadcastListenerTest.java b/packages/Tethering/tests/unit/src/android/net/util/VersionedBroadcastListenerTest.java
new file mode 100644
index 0000000..5a9b6e3
--- /dev/null
+++ b/packages/Tethering/tests/unit/src/android/net/util/VersionedBroadcastListenerTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.reset;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.test.BroadcastInterceptingContext;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VersionedBroadcastListenerTest {
+    private static final String TAG = VersionedBroadcastListenerTest.class.getSimpleName();
+    private static final String ACTION_TEST = "action.test.happy.broadcasts";
+
+    @Mock private Context mContext;
+    private BroadcastInterceptingContext mServiceContext;
+    private Handler mHandler;
+    private VersionedBroadcastListener mListener;
+    private int mCallbackCount;
+
+    private void doCallback() {
+        mCallbackCount++;
+    }
+
+    private class MockContext extends BroadcastInterceptingContext {
+        MockContext(Context base) {
+            super(base);
+        }
+    }
+
+    @BeforeClass
+    public static void setUpBeforeClass() throws Exception {
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+    }
+
+    @Before public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        reset(mContext);
+        mServiceContext = new MockContext(mContext);
+        mHandler = new Handler(Looper.myLooper());
+        mCallbackCount = 0;
+        final IntentFilter filter = new IntentFilter();
+        filter.addAction(ACTION_TEST);
+        mListener = new VersionedBroadcastListener(
+                TAG, mServiceContext, mHandler, filter, (Intent intent) -> doCallback());
+    }
+
+    @After public void tearDown() throws Exception {
+        if (mListener != null) {
+            mListener.stopListening();
+            mListener = null;
+        }
+    }
+
+    private void sendBroadcast() {
+        final Intent intent = new Intent(ACTION_TEST);
+        mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+    }
+
+    @Test
+    public void testBasicListening() {
+        assertEquals(0, mCallbackCount);
+        mListener.startListening();
+        for (int i = 0; i < 5; i++) {
+            sendBroadcast();
+            assertEquals(i + 1, mCallbackCount);
+        }
+        mListener.stopListening();
+    }
+
+    @Test
+    public void testBroadcastsBeforeStartAreIgnored() {
+        assertEquals(0, mCallbackCount);
+        for (int i = 0; i < 5; i++) {
+            sendBroadcast();
+            assertEquals(0, mCallbackCount);
+        }
+
+        mListener.startListening();
+        sendBroadcast();
+        assertEquals(1, mCallbackCount);
+    }
+
+    @Test
+    public void testBroadcastsAfterStopAreIgnored() {
+        mListener.startListening();
+        sendBroadcast();
+        assertEquals(1, mCallbackCount);
+        mListener.stopListening();
+
+        for (int i = 0; i < 5; i++) {
+            sendBroadcast();
+            assertEquals(1, mCallbackCount);
+        }
+    }
+}
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
index 5217e26..99cf9e9 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
@@ -24,6 +24,9 @@
 import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED;
 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -44,6 +47,7 @@
 import android.os.Message;
 import android.os.PersistableBundle;
 import android.os.ResultReceiver;
+import android.os.SystemProperties;
 import android.os.test.TestLooper;
 import android.provider.Settings;
 import android.telephony.CarrierConfigManager;
@@ -57,7 +61,6 @@
 import com.android.internal.util.StateMachine;
 import com.android.internal.util.test.BroadcastInterceptingContext;
 import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.connectivity.MockableSystemProperties;
 
 import org.junit.After;
 import org.junit.Before;
@@ -65,6 +68,8 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
 
 import java.util.ArrayList;
 import java.util.concurrent.CountDownLatch;
@@ -80,7 +85,6 @@
 
     @Mock private CarrierConfigManager mCarrierConfigManager;
     @Mock private Context mContext;
-    @Mock private MockableSystemProperties mSystemProperties;
     @Mock private Resources mResources;
     @Mock private SharedLog mLog;
     @Mock private EntitlementManager.OnUiEntitlementFailedListener mEntitlementFailedListener;
@@ -95,6 +99,7 @@
     private TestStateMachine mSM;
     private WrappedEntitlementManager mEnMgr;
     private TetheringConfiguration mConfig;
+    private MockitoSession mMockingSession;
 
     private class MockContext extends BroadcastInterceptingContext {
         MockContext(Context base) {
@@ -118,8 +123,8 @@
         public int silentProvisionCount = 0;
 
         public WrappedEntitlementManager(Context ctx, StateMachine target,
-                SharedLog log, int what, MockableSystemProperties systemProperties) {
-            super(ctx, target, log, what, systemProperties);
+                SharedLog log, int what) {
+            super(ctx, target, log, what);
         }
 
         public void reset() {
@@ -144,6 +149,15 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+        mMockingSession = mockitoSession()
+                .initMocks(this)
+                .spyStatic(SystemProperties.class)
+                .strictness(Strictness.WARN)
+                .startMocking();
+        // Don't disable tethering provisioning unless requested.
+        doReturn(false).when(
+                () -> SystemProperties.getBoolean(
+                eq(EntitlementManager.DISABLE_PROVISIONING_SYSPROP_KEY), anyBoolean()));
 
         when(mResources.getStringArray(R.array.config_tether_dhcp_range))
             .thenReturn(new String[0]);
@@ -161,8 +175,7 @@
         mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
         mMockContext = new MockContext(mContext);
         mSM = new TestStateMachine();
-        mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, EVENT_EM_UPDATE,
-                mSystemProperties);
+        mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, EVENT_EM_UPDATE);
         mEnMgr.setOnUiEntitlementFailedListener(mEntitlementFailedListener);
         mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
         mEnMgr.setTetheringConfigurationFetcher(() -> {
@@ -176,6 +189,7 @@
             mSM.quit();
             mSM = null;
         }
+        mMockingSession.finishMocking();
     }
 
     private void setupForRequiredProvisioning() {
@@ -184,9 +198,6 @@
                 .thenReturn(PROVISIONING_APP_NAME);
         when(mResources.getString(R.string.config_mobile_hotspot_provision_app_no_ui))
                 .thenReturn(PROVISIONING_NO_UI_APP_NAME);
-       // Don't disable tethering provisioning unless requested.
-        when(mSystemProperties.getBoolean(eq(EntitlementManager.DISABLE_PROVISIONING_SYSPROP_KEY),
-                anyBoolean())).thenReturn(false);
         // Act like the CarrierConfigManager is present and ready unless told otherwise.
         when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
                 .thenReturn(mCarrierConfigManager);
@@ -244,7 +255,7 @@
     }
 
     @Test
-    public void testGetLastEntitlementCacheValue() throws Exception {
+    public void testRequestLastEntitlementCacheValue() throws Exception {
         final CountDownLatch mCallbacklatch = new CountDownLatch(1);
         // 1. Entitlement check is not required.
         mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
@@ -255,7 +266,7 @@
                 mCallbacklatch.countDown();
             }
         };
-        mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
+        mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
         mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
         assertEquals(0, mEnMgr.uiProvisionCount);
@@ -270,7 +281,7 @@
                 mCallbacklatch.countDown();
             }
         };
-        mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false);
+        mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false);
         mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
         assertEquals(0, mEnMgr.uiProvisionCount);
@@ -284,7 +295,7 @@
                 mCallbacklatch.countDown();
             }
         };
-        mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
+        mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
         mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
         assertEquals(1, mEnMgr.uiProvisionCount);
@@ -298,7 +309,7 @@
                 mCallbacklatch.countDown();
             }
         };
-        mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false);
+        mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false);
         mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
         assertEquals(0, mEnMgr.uiProvisionCount);
@@ -312,7 +323,7 @@
                 mCallbacklatch.countDown();
             }
         };
-        mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
+        mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
         mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
         assertEquals(1, mEnMgr.uiProvisionCount);
@@ -326,7 +337,7 @@
                 mCallbacklatch.countDown();
             }
         };
-        mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
+        mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
         mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
         assertEquals(0, mEnMgr.uiProvisionCount);
@@ -339,7 +350,7 @@
                 mCallbacklatch.countDown();
             }
         };
-        mEnMgr.getLatestTetheringEntitlementResult(TETHERING_USB, receiver, false);
+        mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_USB, receiver, false);
         mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
         assertEquals(0, mEnMgr.uiProvisionCount);
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
new file mode 100644
index 0000000..0273ed3
--- /dev/null
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
@@ -0,0 +1,1321 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.tethering;
+
+import static android.hardware.usb.UsbManager.USB_CONFIGURED;
+import static android.hardware.usb.UsbManager.USB_CONNECTED;
+import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
+import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
+import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY;
+import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER;
+import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER;
+import static android.net.ConnectivityManager.TETHERING_USB;
+import static android.net.ConnectivityManager.TETHERING_WIFI;
+import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
+import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
+import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
+import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
+import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
+import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
+import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY;
+import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
+import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.notNull;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.res.Resources;
+import android.hardware.usb.UsbManager;
+import android.net.INetd;
+import android.net.INetworkPolicyManager;
+import android.net.INetworkStatsService;
+import android.net.ITetherInternalCallback;
+import android.net.InterfaceConfiguration;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.MacAddress;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.net.NetworkState;
+import android.net.NetworkUtils;
+import android.net.RouteInfo;
+import android.net.TetherStatesParcel;
+import android.net.TetheringConfigurationParcel;
+import android.net.dhcp.DhcpServerCallbacks;
+import android.net.dhcp.DhcpServingParamsParcel;
+import android.net.dhcp.IDhcpServer;
+import android.net.ip.IpServer;
+import android.net.ip.RouterAdvertisementDaemon;
+import android.net.util.InterfaceParams;
+import android.net.util.NetworkConstants;
+import android.net.util.SharedLog;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+import android.net.wifi.p2p.WifiP2pGroup;
+import android.net.wifi.p2p.WifiP2pInfo;
+import android.net.wifi.p2p.WifiP2pManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.INetworkManagementService;
+import android.os.Looper;
+import android.os.PersistableBundle;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.test.TestLooper;
+import android.provider.Settings;
+import android.telephony.CarrierConfigManager;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
+import android.test.mock.MockContentResolver;
+
+import androidx.annotation.NonNull;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.StateMachine;
+import com.android.internal.util.test.BroadcastInterceptingContext;
+import com.android.internal.util.test.FakeSettingsProvider;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Vector;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class TetheringTest {
+    private static final int IFINDEX_OFFSET = 100;
+
+    private static final String TEST_MOBILE_IFNAME = "test_rmnet_data0";
+    private static final String TEST_XLAT_MOBILE_IFNAME = "v4-test_rmnet_data0";
+    private static final String TEST_USB_IFNAME = "test_rndis0";
+    private static final String TEST_WLAN_IFNAME = "test_wlan0";
+    private static final String TEST_P2P_IFNAME = "test_p2p-p2p0-0";
+
+    private static final int DHCPSERVER_START_TIMEOUT_MS = 1000;
+
+    @Mock private ApplicationInfo mApplicationInfo;
+    @Mock private Context mContext;
+    @Mock private INetworkManagementService mNMService;
+    @Mock private INetworkStatsService mStatsService;
+    @Mock private INetworkPolicyManager mPolicyManager;
+    @Mock private OffloadHardwareInterface mOffloadHardwareInterface;
+    @Mock private Resources mResources;
+    @Mock private TelephonyManager mTelephonyManager;
+    @Mock private UsbManager mUsbManager;
+    @Mock private WifiManager mWifiManager;
+    @Mock private CarrierConfigManager mCarrierConfigManager;
+    @Mock private UpstreamNetworkMonitor mUpstreamNetworkMonitor;
+    @Mock private IPv6TetheringCoordinator mIPv6TetheringCoordinator;
+    @Mock private RouterAdvertisementDaemon mRouterAdvertisementDaemon;
+    @Mock private IDhcpServer mDhcpServer;
+    @Mock private INetd mNetd;
+    @Mock private UserManager mUserManager;
+
+    private final MockIpServerDependencies mIpServerDependencies =
+            spy(new MockIpServerDependencies());
+    private final MockTetheringDependencies mTetheringDependencies =
+            new MockTetheringDependencies();
+
+    // Like so many Android system APIs, these cannot be mocked because it is marked final.
+    // We have to use the real versions.
+    private final PersistableBundle mCarrierConfig = new PersistableBundle();
+    private final TestLooper mLooper = new TestLooper();
+
+    private Vector<Intent> mIntents;
+    private BroadcastInterceptingContext mServiceContext;
+    private MockContentResolver mContentResolver;
+    private BroadcastReceiver mBroadcastReceiver;
+    private Tethering mTethering;
+    private PhoneStateListener mPhoneStateListener;
+
+    private class TestContext extends BroadcastInterceptingContext {
+        TestContext(Context base) {
+            super(base);
+        }
+
+        @Override
+        public ApplicationInfo getApplicationInfo() {
+            return mApplicationInfo;
+        }
+
+        @Override
+        public ContentResolver getContentResolver() {
+            return mContentResolver;
+        }
+
+        @Override
+        public String getPackageName() {
+            return "TetheringTest";
+        }
+
+        @Override
+        public Resources getResources() {
+            return mResources;
+        }
+
+        @Override
+        public Object getSystemService(String name) {
+            if (Context.WIFI_SERVICE.equals(name)) return mWifiManager;
+            if (Context.USB_SERVICE.equals(name)) return mUsbManager;
+            if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager;
+            if (Context.USER_SERVICE.equals(name)) return mUserManager;
+            return super.getSystemService(name);
+        }
+
+        @Override
+        public String getSystemServiceName(Class<?> serviceClass) {
+            if (TelephonyManager.class.equals(serviceClass)) return Context.TELEPHONY_SERVICE;
+            return super.getSystemServiceName(serviceClass);
+        }
+    }
+
+    public class MockIpServerDependencies extends IpServer.Dependencies {
+        @Override
+        public RouterAdvertisementDaemon getRouterAdvertisementDaemon(
+                InterfaceParams ifParams) {
+            return mRouterAdvertisementDaemon;
+        }
+
+        @Override
+        public InterfaceParams getInterfaceParams(String ifName) {
+            assertTrue("Non-mocked interface " + ifName,
+                    ifName.equals(TEST_USB_IFNAME)
+                            || ifName.equals(TEST_WLAN_IFNAME)
+                            || ifName.equals(TEST_MOBILE_IFNAME)
+                            || ifName.equals(TEST_P2P_IFNAME));
+            final String[] ifaces = new String[] {
+                    TEST_USB_IFNAME, TEST_WLAN_IFNAME, TEST_MOBILE_IFNAME, TEST_P2P_IFNAME};
+            return new InterfaceParams(ifName, ArrayUtils.indexOf(ifaces, ifName) + IFINDEX_OFFSET,
+                    MacAddress.ALL_ZEROS_ADDRESS);
+        }
+
+        @Override
+        public INetd getNetdService() {
+            return mNetd;
+        }
+
+        @Override
+        public void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
+                DhcpServerCallbacks cb) {
+            new Thread(() -> {
+                try {
+                    cb.onDhcpServerCreated(STATUS_SUCCESS, mDhcpServer);
+                } catch (RemoteException e) {
+                    fail(e.getMessage());
+                }
+            }).run();
+        }
+    }
+
+    private class MockTetheringConfiguration extends TetheringConfiguration {
+        MockTetheringConfiguration(Context ctx, SharedLog log, int id) {
+            super(ctx, log, id);
+        }
+
+        @Override
+        protected Resources getResourcesForSubIdWrapper(Context ctx, int subId) {
+            return mResources;
+        }
+    }
+
+    public class MockTetheringDependencies extends TetheringDependencies {
+        StateMachine mUpstreamNetworkMonitorMasterSM;
+        ArrayList<IpServer> mIpv6CoordinatorNotifyList;
+        int mIsTetheringSupportedCalls;
+
+        public void reset() {
+            mUpstreamNetworkMonitorMasterSM = null;
+            mIpv6CoordinatorNotifyList = null;
+            mIsTetheringSupportedCalls = 0;
+        }
+
+        @Override
+        public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) {
+            return mOffloadHardwareInterface;
+        }
+
+        @Override
+        public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx,
+                StateMachine target, SharedLog log, int what) {
+            mUpstreamNetworkMonitorMasterSM = target;
+            return mUpstreamNetworkMonitor;
+        }
+
+        @Override
+        public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
+                ArrayList<IpServer> notifyList, SharedLog log) {
+            mIpv6CoordinatorNotifyList = notifyList;
+            return mIPv6TetheringCoordinator;
+        }
+
+        @Override
+        public IpServer.Dependencies getIpServerDependencies() {
+            return mIpServerDependencies;
+        }
+
+        @Override
+        public boolean isTetheringSupported() {
+            mIsTetheringSupportedCalls++;
+            return true;
+        }
+
+        @Override
+        public TetheringConfiguration generateTetheringConfiguration(Context ctx, SharedLog log,
+                int subId) {
+            return new MockTetheringConfiguration(ctx, log, subId);
+        }
+
+        @Override
+        public INetworkManagementService getINetworkManagementService() {
+            return mNMService;
+        }
+
+        @Override
+        public INetworkStatsService getINetworkStatsService() {
+            return mStatsService;
+        }
+
+        @Override
+        public INetworkPolicyManager getINetworkPolicyManager() {
+            return mPolicyManager;
+        }
+
+        @Override
+        public INetd getINetd(Context context) {
+            return mNetd;
+        }
+
+        @Override
+        public Looper getTetheringLooper() {
+            return mLooper.getLooper();
+        }
+
+        @Override
+        public Context getContext() {
+            return mServiceContext;
+        }
+    }
+
+    private static NetworkState buildMobileUpstreamState(boolean withIPv4, boolean withIPv6,
+            boolean with464xlat) {
+        final NetworkInfo info = new NetworkInfo(TYPE_MOBILE, 0, null, null);
+        info.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
+        final LinkProperties prop = new LinkProperties();
+        prop.setInterfaceName(TEST_MOBILE_IFNAME);
+
+        if (withIPv4) {
+            prop.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0),
+                    NetworkUtils.numericToInetAddress("10.0.0.1"), TEST_MOBILE_IFNAME));
+        }
+
+        if (withIPv6) {
+            prop.addDnsServer(NetworkUtils.numericToInetAddress("2001:db8::2"));
+            prop.addLinkAddress(
+                    new LinkAddress(NetworkUtils.numericToInetAddress("2001:db8::"),
+                            NetworkConstants.RFC7421_PREFIX_LENGTH));
+            prop.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0),
+                    NetworkUtils.numericToInetAddress("2001:db8::1"), TEST_MOBILE_IFNAME));
+        }
+
+        if (with464xlat) {
+            final LinkProperties stackedLink = new LinkProperties();
+            stackedLink.setInterfaceName(TEST_XLAT_MOBILE_IFNAME);
+            stackedLink.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0),
+                    NetworkUtils.numericToInetAddress("192.0.0.1"), TEST_XLAT_MOBILE_IFNAME));
+
+            prop.addStackedLink(stackedLink);
+        }
+
+
+        final NetworkCapabilities capabilities = new NetworkCapabilities()
+                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+        return new NetworkState(info, prop, capabilities, new Network(100), null, "netid");
+    }
+
+    private static NetworkState buildMobileIPv4UpstreamState() {
+        return buildMobileUpstreamState(true, false, false);
+    }
+
+    private static NetworkState buildMobileIPv6UpstreamState() {
+        return buildMobileUpstreamState(false, true, false);
+    }
+
+    private static NetworkState buildMobileDualStackUpstreamState() {
+        return buildMobileUpstreamState(true, true, false);
+    }
+
+    private static NetworkState buildMobile464xlatUpstreamState() {
+        return buildMobileUpstreamState(false, true, true);
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        when(mResources.getStringArray(com.android.internal.R.array.config_tether_dhcp_range))
+                .thenReturn(new String[0]);
+        when(mResources.getStringArray(com.android.internal.R.array.config_tether_usb_regexs))
+                .thenReturn(new String[] { "test_rndis\\d" });
+        when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_regexs))
+                .thenReturn(new String[]{ "test_wlan\\d" });
+        when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_p2p_regexs))
+                .thenReturn(new String[]{ "test_p2p-p2p\\d-.*" });
+        when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs))
+                .thenReturn(new String[0]);
+        when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
+                .thenReturn(new int[0]);
+        when(mResources.getBoolean(com.android.internal.R.bool.config_tether_upstream_automatic))
+                .thenReturn(false);
+        when(mNMService.listInterfaces())
+                .thenReturn(new String[] {
+                        TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME, TEST_P2P_IFNAME});
+        when(mNMService.getInterfaceConfig(anyString()))
+                .thenReturn(new InterfaceConfiguration());
+        when(mRouterAdvertisementDaemon.start())
+                .thenReturn(true);
+
+        mServiceContext = new TestContext(mContext);
+        mContentResolver = new MockContentResolver(mServiceContext);
+        mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+        Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 0);
+        mIntents = new Vector<>();
+        mBroadcastReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                mIntents.addElement(intent);
+            }
+        };
+        mServiceContext.registerReceiver(mBroadcastReceiver,
+                new IntentFilter(ACTION_TETHER_STATE_CHANGED));
+        mTethering = makeTethering();
+        verify(mNMService).registerTetheringStatsProvider(any(), anyString());
+        verify(mNetd).registerUnsolicitedEventListener(any());
+        final ArgumentCaptor<PhoneStateListener> phoneListenerCaptor =
+                ArgumentCaptor.forClass(PhoneStateListener.class);
+        verify(mTelephonyManager).listen(phoneListenerCaptor.capture(),
+                eq(PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE));
+        mPhoneStateListener = phoneListenerCaptor.getValue();
+    }
+
+    private Tethering makeTethering() {
+        mTetheringDependencies.reset();
+        return new Tethering(mTetheringDependencies);
+    }
+
+    @After
+    public void tearDown() {
+        mServiceContext.unregisterReceiver(mBroadcastReceiver);
+    }
+
+    private void sendWifiApStateChanged(int state) {
+        final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
+        intent.putExtra(EXTRA_WIFI_AP_STATE, state);
+        mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+    }
+
+    private void sendWifiApStateChanged(int state, String ifname, int ipmode) {
+        final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
+        intent.putExtra(EXTRA_WIFI_AP_STATE, state);
+        intent.putExtra(EXTRA_WIFI_AP_INTERFACE_NAME, ifname);
+        intent.putExtra(EXTRA_WIFI_AP_MODE, ipmode);
+        mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+    }
+
+    private static final String[] P2P_RECEIVER_PERMISSIONS_FOR_BROADCAST = {
+            android.Manifest.permission.ACCESS_FINE_LOCATION,
+            android.Manifest.permission.ACCESS_WIFI_STATE
+    };
+
+    private void sendWifiP2pConnectionChanged(
+            boolean isGroupFormed, boolean isGroupOwner, String ifname) {
+        WifiP2pInfo p2pInfo = new WifiP2pInfo();
+        p2pInfo.groupFormed = isGroupFormed;
+        p2pInfo.isGroupOwner = isGroupOwner;
+
+        NetworkInfo networkInfo = new NetworkInfo(TYPE_WIFI_P2P, 0, null, null);
+
+        WifiP2pGroup group = new WifiP2pGroup();
+        group.setIsGroupOwner(isGroupOwner);
+        group.setInterface(ifname);
+
+        final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
+        intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, p2pInfo);
+        intent.putExtra(WifiP2pManager.EXTRA_NETWORK_INFO, networkInfo);
+        intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, group);
+        mServiceContext.sendBroadcastAsUserMultiplePermissions(intent, UserHandle.ALL,
+                P2P_RECEIVER_PERMISSIONS_FOR_BROADCAST);
+    }
+
+    private void sendUsbBroadcast(boolean connected, boolean configured, boolean rndisFunction) {
+        final Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
+        intent.putExtra(USB_CONNECTED, connected);
+        intent.putExtra(USB_CONFIGURED, configured);
+        intent.putExtra(USB_FUNCTION_RNDIS, rndisFunction);
+        mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+    }
+
+    private void sendConfigurationChanged() {
+        final Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
+        mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+    }
+
+    private void verifyInterfaceServingModeStarted(String ifname) throws Exception {
+        verify(mNMService, times(1)).getInterfaceConfig(ifname);
+        verify(mNMService, times(1))
+                .setInterfaceConfig(eq(ifname), any(InterfaceConfiguration.class));
+        verify(mNMService, times(1)).tetherInterface(ifname);
+    }
+
+    private void verifyTetheringBroadcast(String ifname, String whichExtra) {
+        // Verify that ifname is in the whichExtra array of the tether state changed broadcast.
+        final Intent bcast = mIntents.get(0);
+        assertEquals(ACTION_TETHER_STATE_CHANGED, bcast.getAction());
+        final ArrayList<String> ifnames = bcast.getStringArrayListExtra(whichExtra);
+        assertTrue(ifnames.contains(ifname));
+        mIntents.remove(bcast);
+    }
+
+    public void failingLocalOnlyHotspotLegacyApBroadcast(
+            boolean emulateInterfaceStatusChanged) throws Exception {
+        // Emulate externally-visible WifiManager effects, causing the
+        // per-interface state machine to start up, and telling us that
+        // hotspot mode is to be started.
+        if (emulateInterfaceStatusChanged) {
+            mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
+        }
+        sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
+        mLooper.dispatchAll();
+
+        // If, and only if, Tethering received an interface status changed then
+        // it creates a IpServer and sends out a broadcast indicating that the
+        // interface is "available".
+        if (emulateInterfaceStatusChanged) {
+            assertEquals(1, mTetheringDependencies.mIsTetheringSupportedCalls);
+            verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
+            verify(mWifiManager).updateInterfaceIpState(
+                    TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
+        }
+        verifyNoMoreInteractions(mNMService);
+        verifyNoMoreInteractions(mWifiManager);
+    }
+
+    private void prepareUsbTethering(NetworkState upstreamState) {
+        when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
+        when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
+                .thenReturn(upstreamState);
+
+        // Emulate pressing the USB tethering button in Settings UI.
+        mTethering.startTethering(TETHERING_USB, null, false);
+        mLooper.dispatchAll();
+        verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
+
+        mTethering.interfaceStatusChanged(TEST_USB_IFNAME, true);
+    }
+
+    @Test
+    public void testUsbConfiguredBroadcastStartsTethering() throws Exception {
+        NetworkState upstreamState = buildMobileIPv4UpstreamState();
+        prepareUsbTethering(upstreamState);
+
+        // This should produce no activity of any kind.
+        verifyNoMoreInteractions(mNMService);
+
+        // Pretend we then receive USB configured broadcast.
+        sendUsbBroadcast(true, true, true);
+        mLooper.dispatchAll();
+        // Now we should see the start of tethering mechanics (in this case:
+        // tetherMatchingInterfaces() which starts by fetching all interfaces).
+        verify(mNMService, times(1)).listInterfaces();
+
+        // UpstreamNetworkMonitor should receive selected upstream
+        verify(mUpstreamNetworkMonitor, times(1)).selectPreferredUpstreamType(any());
+        verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(upstreamState.network);
+    }
+
+    @Test
+    public void failingLocalOnlyHotspotLegacyApBroadcastWithIfaceStatusChanged() throws Exception {
+        failingLocalOnlyHotspotLegacyApBroadcast(true);
+    }
+
+    @Test
+    public void failingLocalOnlyHotspotLegacyApBroadcastSansIfaceStatusChanged() throws Exception {
+        failingLocalOnlyHotspotLegacyApBroadcast(false);
+    }
+
+    public void workingLocalOnlyHotspotEnrichedApBroadcast(
+            boolean emulateInterfaceStatusChanged) throws Exception {
+        // Emulate externally-visible WifiManager effects, causing the
+        // per-interface state machine to start up, and telling us that
+        // hotspot mode is to be started.
+        if (emulateInterfaceStatusChanged) {
+            mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
+        }
+        sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_LOCAL_ONLY);
+        mLooper.dispatchAll();
+
+        verifyInterfaceServingModeStarted(TEST_WLAN_IFNAME);
+        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
+        verify(mNMService, times(1)).setIpForwardingEnabled(true);
+        verify(mNMService, times(1)).startTethering(any(String[].class));
+        verifyNoMoreInteractions(mNMService);
+        verify(mWifiManager).updateInterfaceIpState(
+                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
+        verify(mWifiManager).updateInterfaceIpState(
+                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
+        verifyNoMoreInteractions(mWifiManager);
+        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY);
+        verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks();
+        // This will be called twice, one is on entering IpServer.STATE_AVAILABLE,
+        // and another one is on IpServer.STATE_TETHERED/IpServer.STATE_LOCAL_ONLY.
+        assertEquals(2, mTetheringDependencies.mIsTetheringSupportedCalls);
+
+        // Emulate externally-visible WifiManager effects, when hotspot mode
+        // is being torn down.
+        sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
+        mTethering.interfaceRemoved(TEST_WLAN_IFNAME);
+        mLooper.dispatchAll();
+
+        verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
+        // {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4.
+        verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME);
+        verify(mNMService, times(2))
+                .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
+        verify(mNMService, times(1)).stopTethering();
+        verify(mNMService, times(1)).setIpForwardingEnabled(false);
+        verify(mWifiManager, times(3)).updateInterfaceIpState(
+                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
+        verifyNoMoreInteractions(mNMService);
+        verifyNoMoreInteractions(mWifiManager);
+        // Asking for the last error after the per-interface state machine
+        // has been reaped yields an unknown interface error.
+        assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_WLAN_IFNAME));
+    }
+
+    /**
+     * Send CMD_IPV6_TETHER_UPDATE to IpServers as would be done by IPv6TetheringCoordinator.
+     */
+    private void sendIPv6TetherUpdates(NetworkState upstreamState) {
+        // IPv6TetheringCoordinator must have been notified of downstream
+        verify(mIPv6TetheringCoordinator, times(1)).addActiveDownstream(
+                argThat(sm -> sm.linkProperties().getInterfaceName().equals(TEST_USB_IFNAME)),
+                eq(IpServer.STATE_TETHERED));
+
+        for (IpServer ipSrv : mTetheringDependencies.mIpv6CoordinatorNotifyList) {
+            NetworkState ipv6OnlyState = buildMobileUpstreamState(false, true, false);
+            ipSrv.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0,
+                    upstreamState.linkProperties.isIpv6Provisioned()
+                            ? ipv6OnlyState.linkProperties
+                            : null);
+        }
+        mLooper.dispatchAll();
+    }
+
+    private void runUsbTethering(NetworkState upstreamState) {
+        prepareUsbTethering(upstreamState);
+        sendUsbBroadcast(true, true, true);
+        mLooper.dispatchAll();
+    }
+
+    @Test
+    public void workingMobileUsbTethering_IPv4() throws Exception {
+        NetworkState upstreamState = buildMobileIPv4UpstreamState();
+        runUsbTethering(upstreamState);
+
+        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+
+        sendIPv6TetherUpdates(upstreamState);
+        verify(mRouterAdvertisementDaemon, never()).buildNewRa(any(), notNull());
+        verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
+    }
+
+    @Test
+    public void workingMobileUsbTethering_IPv4LegacyDhcp() {
+        Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 1);
+        sendConfigurationChanged();
+        final NetworkState upstreamState = buildMobileIPv4UpstreamState();
+        runUsbTethering(upstreamState);
+        sendIPv6TetherUpdates(upstreamState);
+
+        verify(mIpServerDependencies, never()).makeDhcpServer(any(), any(), any());
+    }
+
+    @Test
+    public void workingMobileUsbTethering_IPv6() throws Exception {
+        NetworkState upstreamState = buildMobileIPv6UpstreamState();
+        runUsbTethering(upstreamState);
+
+        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+
+        sendIPv6TetherUpdates(upstreamState);
+        verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
+        verify(mNetd, times(1)).tetherApplyDnsInterfaces();
+    }
+
+    @Test
+    public void workingMobileUsbTethering_DualStack() throws Exception {
+        NetworkState upstreamState = buildMobileDualStackUpstreamState();
+        runUsbTethering(upstreamState);
+
+        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+        verify(mRouterAdvertisementDaemon, times(1)).start();
+        verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
+
+        sendIPv6TetherUpdates(upstreamState);
+        verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
+        verify(mNetd, times(1)).tetherApplyDnsInterfaces();
+    }
+
+    @Test
+    public void workingMobileUsbTethering_MultipleUpstreams() throws Exception {
+        NetworkState upstreamState = buildMobile464xlatUpstreamState();
+        runUsbTethering(upstreamState);
+
+        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
+        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+        verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
+        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME,
+                TEST_XLAT_MOBILE_IFNAME);
+
+        sendIPv6TetherUpdates(upstreamState);
+        verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
+        verify(mNetd, times(1)).tetherApplyDnsInterfaces();
+    }
+
+    @Test
+    public void workingMobileUsbTethering_v6Then464xlat() throws Exception {
+        // Setup IPv6
+        NetworkState upstreamState = buildMobileIPv6UpstreamState();
+        runUsbTethering(upstreamState);
+
+        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+        verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
+        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+
+        // Then 464xlat comes up
+        upstreamState = buildMobile464xlatUpstreamState();
+        when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
+                .thenReturn(upstreamState);
+
+        // Upstream LinkProperties changed: UpstreamNetworkMonitor sends EVENT_ON_LINKPROPERTIES.
+        mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage(
+                Tethering.TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
+                UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES,
+                0,
+                upstreamState);
+        mLooper.dispatchAll();
+
+        // Forwarding is added for 464xlat
+        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
+        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME,
+                TEST_XLAT_MOBILE_IFNAME);
+        // Forwarding was not re-added for v6 (still times(1))
+        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+        // DHCP not restarted on downstream (still times(1))
+        verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
+    }
+
+    @Test
+    public void configTetherUpstreamAutomaticIgnoresConfigTetherUpstreamTypes() throws Exception {
+        when(mResources.getBoolean(com.android.internal.R.bool.config_tether_upstream_automatic))
+                .thenReturn(true);
+        sendConfigurationChanged();
+
+        // Setup IPv6
+        final NetworkState upstreamState = buildMobileIPv6UpstreamState();
+        runUsbTethering(upstreamState);
+
+        // UpstreamNetworkMonitor should choose upstream automatically
+        // (in this specific case: choose the default network).
+        verify(mUpstreamNetworkMonitor, times(1)).getCurrentPreferredUpstream();
+        verify(mUpstreamNetworkMonitor, never()).selectPreferredUpstreamType(any());
+
+        verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(upstreamState.network);
+    }
+
+    @Test
+    public void workingLocalOnlyHotspotEnrichedApBroadcastWithIfaceChanged() throws Exception {
+        workingLocalOnlyHotspotEnrichedApBroadcast(true);
+    }
+
+    @Test
+    public void workingLocalOnlyHotspotEnrichedApBroadcastSansIfaceChanged() throws Exception {
+        workingLocalOnlyHotspotEnrichedApBroadcast(false);
+    }
+
+    // TODO: Test with and without interfaceStatusChanged().
+    @Test
+    public void failingWifiTetheringLegacyApBroadcast() throws Exception {
+        when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
+
+        // Emulate pressing the WiFi tethering button.
+        mTethering.startTethering(TETHERING_WIFI, null, false);
+        mLooper.dispatchAll();
+        verify(mWifiManager, times(1)).startSoftAp(null);
+        verifyNoMoreInteractions(mWifiManager);
+        verifyNoMoreInteractions(mNMService);
+
+        // Emulate externally-visible WifiManager effects, causing the
+        // per-interface state machine to start up, and telling us that
+        // tethering mode is to be started.
+        mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
+        sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
+        mLooper.dispatchAll();
+
+        assertEquals(1, mTetheringDependencies.mIsTetheringSupportedCalls);
+        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
+        verify(mWifiManager).updateInterfaceIpState(
+                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
+        verifyNoMoreInteractions(mNMService);
+        verifyNoMoreInteractions(mWifiManager);
+    }
+
+    // TODO: Test with and without interfaceStatusChanged().
+    @Test
+    public void workingWifiTetheringEnrichedApBroadcast() throws Exception {
+        when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
+
+        // Emulate pressing the WiFi tethering button.
+        mTethering.startTethering(TETHERING_WIFI, null, false);
+        mLooper.dispatchAll();
+        verify(mWifiManager, times(1)).startSoftAp(null);
+        verifyNoMoreInteractions(mWifiManager);
+        verifyNoMoreInteractions(mNMService);
+
+        // Emulate externally-visible WifiManager effects, causing the
+        // per-interface state machine to start up, and telling us that
+        // tethering mode is to be started.
+        mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
+        sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
+        mLooper.dispatchAll();
+
+        verifyInterfaceServingModeStarted(TEST_WLAN_IFNAME);
+        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
+        verify(mNMService, times(1)).setIpForwardingEnabled(true);
+        verify(mNMService, times(1)).startTethering(any(String[].class));
+        verifyNoMoreInteractions(mNMService);
+        verify(mWifiManager).updateInterfaceIpState(
+                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
+        verify(mWifiManager).updateInterfaceIpState(
+                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
+        verifyNoMoreInteractions(mWifiManager);
+        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_TETHER);
+        verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks();
+        // In tethering mode, in the default configuration, an explicit request
+        // for a mobile network is also made.
+        verify(mUpstreamNetworkMonitor, times(1)).registerMobileNetworkRequest();
+        // This will be called twice, one is on entering IpServer.STATE_AVAILABLE,
+        // and another one is on IpServer.STATE_TETHERED/IpServer.STATE_LOCAL_ONLY.
+        assertEquals(2, mTetheringDependencies.mIsTetheringSupportedCalls);
+
+        /////
+        // We do not currently emulate any upstream being found.
+        //
+        // This is why there are no calls to verify mNMService.enableNat() or
+        // mNMService.startInterfaceForwarding().
+        /////
+
+        // Emulate pressing the WiFi tethering button.
+        mTethering.stopTethering(TETHERING_WIFI);
+        mLooper.dispatchAll();
+        verify(mWifiManager, times(1)).stopSoftAp();
+        verifyNoMoreInteractions(mWifiManager);
+        verifyNoMoreInteractions(mNMService);
+
+        // Emulate externally-visible WifiManager effects, when tethering mode
+        // is being torn down.
+        sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
+        mTethering.interfaceRemoved(TEST_WLAN_IFNAME);
+        mLooper.dispatchAll();
+
+        verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
+        // {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4.
+        verify(mNMService, atLeastOnce()).getInterfaceConfig(TEST_WLAN_IFNAME);
+        verify(mNMService, atLeastOnce())
+                .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
+        verify(mNMService, times(1)).stopTethering();
+        verify(mNMService, times(1)).setIpForwardingEnabled(false);
+        verify(mWifiManager, times(3)).updateInterfaceIpState(
+                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
+        verifyNoMoreInteractions(mNMService);
+        verifyNoMoreInteractions(mWifiManager);
+        // Asking for the last error after the per-interface state machine
+        // has been reaped yields an unknown interface error.
+        assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_WLAN_IFNAME));
+    }
+
+    // TODO: Test with and without interfaceStatusChanged().
+    @Test
+    public void failureEnablingIpForwarding() throws Exception {
+        when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
+        doThrow(new RemoteException()).when(mNMService).setIpForwardingEnabled(true);
+
+        // Emulate pressing the WiFi tethering button.
+        mTethering.startTethering(TETHERING_WIFI, null, false);
+        mLooper.dispatchAll();
+        verify(mWifiManager, times(1)).startSoftAp(null);
+        verifyNoMoreInteractions(mWifiManager);
+        verifyNoMoreInteractions(mNMService);
+
+        // Emulate externally-visible WifiManager effects, causing the
+        // per-interface state machine to start up, and telling us that
+        // tethering mode is to be started.
+        mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
+        sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
+        mLooper.dispatchAll();
+
+        // We verify get/set called thrice here: twice for setup (on NMService) and once during
+        // teardown (on Netd) because all events happen over the course of the single
+        // dispatchAll() above. Note that once the IpServer IPv4 address config
+        // code is refactored the two calls during shutdown will revert to one.
+        verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME);
+        verify(mNMService, times(2))
+                .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
+        verify(mNetd, times(1)).interfaceSetCfg(argThat(p -> TEST_WLAN_IFNAME.equals(p.ifName)));
+        verify(mNMService, times(1)).tetherInterface(TEST_WLAN_IFNAME);
+        verify(mWifiManager).updateInterfaceIpState(
+                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
+        verify(mWifiManager).updateInterfaceIpState(
+                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
+        // There are 3 state change event:
+        // AVAILABLE -> STATE_TETHERED -> STATE_AVAILABLE.
+        assertEquals(3, mTetheringDependencies.mIsTetheringSupportedCalls);
+        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
+        // This is called, but will throw.
+        verify(mNMService, times(1)).setIpForwardingEnabled(true);
+        // This never gets called because of the exception thrown above.
+        verify(mNMService, times(0)).startTethering(any(String[].class));
+        // When the master state machine transitions to an error state it tells
+        // downstream interfaces, which causes us to tell Wi-Fi about the error
+        // so it can take down AP mode.
+        verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
+        verify(mWifiManager).updateInterfaceIpState(
+                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR);
+
+        verifyNoMoreInteractions(mWifiManager);
+        verifyNoMoreInteractions(mNMService);
+    }
+
+    private void runUserRestrictionsChange(
+            boolean currentDisallow, boolean nextDisallow, String[] activeTetheringIfacesList,
+            int expectedInteractionsWithShowNotification) throws  Exception {
+        final Bundle newRestrictions = new Bundle();
+        newRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_TETHERING, nextDisallow);
+        final Tethering mockTethering = mock(Tethering.class);
+        when(mockTethering.getTetheredIfaces()).thenReturn(activeTetheringIfacesList);
+        when(mUserManager.getUserRestrictions()).thenReturn(newRestrictions);
+
+        final Tethering.UserRestrictionActionListener ural =
+                new Tethering.UserRestrictionActionListener(mUserManager, mockTethering);
+        ural.mDisallowTethering = currentDisallow;
+
+        ural.onUserRestrictionsChanged();
+
+        verify(mockTethering, times(expectedInteractionsWithShowNotification))
+                .showTetheredNotification(anyInt(), eq(false));
+
+        verify(mockTethering, times(expectedInteractionsWithShowNotification))
+                .untetherAll();
+    }
+
+    @Test
+    public void testDisallowTetheringWhenNoTetheringInterfaceIsActive() throws Exception {
+        final String[] emptyActiveIfacesList = new String[]{};
+        final boolean currDisallow = false;
+        final boolean nextDisallow = true;
+        final int expectedInteractionsWithShowNotification = 0;
+
+        runUserRestrictionsChange(currDisallow, nextDisallow, emptyActiveIfacesList,
+                expectedInteractionsWithShowNotification);
+    }
+
+    @Test
+    public void testDisallowTetheringWhenAtLeastOneTetheringInterfaceIsActive() throws Exception {
+        final String[] nonEmptyActiveIfacesList = new String[]{TEST_WLAN_IFNAME};
+        final boolean currDisallow = false;
+        final boolean nextDisallow = true;
+        final int expectedInteractionsWithShowNotification = 1;
+
+        runUserRestrictionsChange(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
+                expectedInteractionsWithShowNotification);
+    }
+
+    @Test
+    public void testAllowTetheringWhenNoTetheringInterfaceIsActive() throws Exception {
+        final String[] nonEmptyActiveIfacesList = new String[]{};
+        final boolean currDisallow = true;
+        final boolean nextDisallow = false;
+        final int expectedInteractionsWithShowNotification = 0;
+
+        runUserRestrictionsChange(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
+                expectedInteractionsWithShowNotification);
+    }
+
+    @Test
+    public void testAllowTetheringWhenAtLeastOneTetheringInterfaceIsActive() throws Exception {
+        final String[] nonEmptyActiveIfacesList = new String[]{TEST_WLAN_IFNAME};
+        final boolean currDisallow = true;
+        final boolean nextDisallow = false;
+        final int expectedInteractionsWithShowNotification = 0;
+
+        runUserRestrictionsChange(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
+                expectedInteractionsWithShowNotification);
+    }
+
+    @Test
+    public void testDisallowTetheringUnchanged() throws Exception {
+        final String[] nonEmptyActiveIfacesList = new String[]{TEST_WLAN_IFNAME};
+        final int expectedInteractionsWithShowNotification = 0;
+        boolean currDisallow = true;
+        boolean nextDisallow = true;
+
+        runUserRestrictionsChange(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
+                expectedInteractionsWithShowNotification);
+
+        currDisallow = false;
+        nextDisallow = false;
+
+        runUserRestrictionsChange(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
+                expectedInteractionsWithShowNotification);
+    }
+
+    private class TestTetherInternalCallback extends ITetherInternalCallback.Stub {
+        private final ArrayList<Network> mActualUpstreams = new ArrayList<>();
+        private final ArrayList<TetheringConfigurationParcel> mTetheringConfigs =
+                new ArrayList<>();
+        private final ArrayList<TetherStatesParcel> mTetherStates = new ArrayList<>();
+
+        // This function will remove the recorded callbacks, so it must be called once for
+        // each callback. If this is called after multiple callback, the order matters.
+        // onCallbackCreated counts as the first call to expectUpstreamChanged with
+        // @see onCallbackCreated.
+        public void expectUpstreamChanged(Network... networks) {
+            if (networks == null) {
+                assertNoUpstreamChangeCallback();
+                return;
+            }
+
+            final ArrayList<Network> expectedUpstreams =
+                    new ArrayList<Network>(Arrays.asList(networks));
+            for (Network upstream : expectedUpstreams) {
+                // throws OOB if no expectations
+                assertEquals(mActualUpstreams.remove(0), upstream);
+            }
+            assertNoUpstreamChangeCallback();
+        }
+
+        // This function will remove the recorded callbacks, so it must be called once
+        // for each callback. If this is called after multiple callback, the order matters.
+        // onCallbackCreated counts as the first call to onConfigurationChanged with
+        // @see onCallbackCreated.
+        public void expectConfigurationChanged(TetheringConfigurationParcel... tetherConfigs) {
+            final ArrayList<TetheringConfigurationParcel> expectedTetherConfig =
+                    new ArrayList<TetheringConfigurationParcel>(Arrays.asList(tetherConfigs));
+            for (TetheringConfigurationParcel config : expectedTetherConfig) {
+                // throws OOB if no expectations
+                final TetheringConfigurationParcel actualConfig = mTetheringConfigs.remove(0);
+                assertTetherConfigParcelEqual(actualConfig, config);
+            }
+            assertNoConfigChangeCallback();
+        }
+
+        public TetherStatesParcel pollTetherStatesChanged() {
+            assertStateChangeCallback();
+            return mTetherStates.remove(0);
+        }
+
+        @Override
+        public void onUpstreamChanged(Network network) {
+            mActualUpstreams.add(network);
+        }
+
+        @Override
+        public void onConfigurationChanged(TetheringConfigurationParcel config) {
+            mTetheringConfigs.add(config);
+        }
+
+        @Override
+        public void onTetherStatesChanged(TetherStatesParcel states) {
+            mTetherStates.add(states);
+        }
+
+        @Override
+        public void onCallbackCreated(Network network, TetheringConfigurationParcel config,
+                TetherStatesParcel states) {
+            mActualUpstreams.add(network);
+            mTetheringConfigs.add(config);
+            mTetherStates.add(states);
+        }
+
+        public void assertNoUpstreamChangeCallback() {
+            assertTrue(mActualUpstreams.isEmpty());
+        }
+
+        public void assertNoConfigChangeCallback() {
+            assertTrue(mTetheringConfigs.isEmpty());
+        }
+
+        public void assertStateChangeCallback() {
+            assertFalse(mTetherStates.isEmpty());
+        }
+
+        private void assertTetherConfigParcelEqual(@NonNull TetheringConfigurationParcel actual,
+                @NonNull TetheringConfigurationParcel expect) {
+            assertEquals(actual.subId, expect.subId);
+            assertArrayEquals(actual.tetherableUsbRegexs, expect.tetherableUsbRegexs);
+            assertArrayEquals(actual.tetherableWifiRegexs, expect.tetherableWifiRegexs);
+            assertArrayEquals(actual.tetherableBluetoothRegexs, expect.tetherableBluetoothRegexs);
+            assertEquals(actual.isDunRequired, expect.isDunRequired);
+            assertEquals(actual.chooseUpstreamAutomatically, expect.chooseUpstreamAutomatically);
+            assertArrayEquals(actual.preferredUpstreamIfaceTypes,
+                    expect.preferredUpstreamIfaceTypes);
+            assertArrayEquals(actual.legacyDhcpRanges, expect.legacyDhcpRanges);
+            assertArrayEquals(actual.defaultIPv4DNS, expect.defaultIPv4DNS);
+            assertEquals(actual.enableLegacyDhcpServer, expect.enableLegacyDhcpServer);
+            assertArrayEquals(actual.provisioningApp, expect.provisioningApp);
+            assertEquals(actual.provisioningAppNoUi, expect.provisioningAppNoUi);
+            assertEquals(actual.provisioningCheckPeriod, expect.provisioningCheckPeriod);
+        }
+    }
+
+    @Test
+    public void testRegisterTetherInternalCallback() throws Exception {
+        TestTetherInternalCallback callback = new TestTetherInternalCallback();
+
+        // 1. Register one callback before running any tethering.
+        mTethering.registerTetherInternalCallback(callback);
+        mLooper.dispatchAll();
+        callback.expectUpstreamChanged(new Network[] {null});
+        callback.expectConfigurationChanged(
+                mTethering.getTetheringConfiguration().toStableParcelable());
+        TetherStatesParcel tetherState = callback.pollTetherStatesChanged();
+        assertEquals(tetherState, null);
+        // 2. Enable wifi tethering
+        NetworkState upstreamState = buildMobileDualStackUpstreamState();
+        when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
+        when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
+                .thenReturn(upstreamState);
+        when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
+        mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
+        mLooper.dispatchAll();
+        tetherState = callback.pollTetherStatesChanged();
+        assertArrayEquals(tetherState.availableList, new String[] {TEST_WLAN_IFNAME});
+
+        mTethering.startTethering(TETHERING_WIFI, null, false);
+        sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
+        mLooper.dispatchAll();
+        tetherState = callback.pollTetherStatesChanged();
+        assertArrayEquals(tetherState.tetheredList, new String[] {TEST_WLAN_IFNAME});
+        callback.expectUpstreamChanged(upstreamState.network);
+
+        // 3. Disable wifi tethering.
+        mTethering.stopTethering(TETHERING_WIFI);
+        sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
+        mLooper.dispatchAll();
+        tetherState = callback.pollTetherStatesChanged();
+        assertArrayEquals(tetherState.availableList, new String[] {TEST_WLAN_IFNAME});
+        mLooper.dispatchAll();
+        callback.expectUpstreamChanged(new Network[] {null});
+    }
+
+    @Test
+    public void testMultiSimAware() throws Exception {
+        final TetheringConfiguration initailConfig = mTethering.getTetheringConfiguration();
+        assertEquals(INVALID_SUBSCRIPTION_ID, initailConfig.subId);
+
+        final int fakeSubId = 1234;
+        mPhoneStateListener.onActiveDataSubscriptionIdChanged(fakeSubId);
+        final TetheringConfiguration newConfig = mTethering.getTetheringConfiguration();
+        assertEquals(fakeSubId, newConfig.subId);
+    }
+
+    private void workingWifiP2pGroupOwner(
+            boolean emulateInterfaceStatusChanged) throws Exception {
+        if (emulateInterfaceStatusChanged) {
+            mTethering.interfaceStatusChanged(TEST_P2P_IFNAME, true);
+        }
+        sendWifiP2pConnectionChanged(true, true, TEST_P2P_IFNAME);
+        mLooper.dispatchAll();
+
+        verifyInterfaceServingModeStarted(TEST_P2P_IFNAME);
+        verifyTetheringBroadcast(TEST_P2P_IFNAME, EXTRA_AVAILABLE_TETHER);
+        verify(mNMService, times(1)).setIpForwardingEnabled(true);
+        verify(mNMService, times(1)).startTethering(any(String[].class));
+        verifyNoMoreInteractions(mNMService);
+        verifyTetheringBroadcast(TEST_P2P_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY);
+        verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks();
+        // This will be called twice, one is on entering IpServer.STATE_AVAILABLE,
+        // and another one is on IpServer.STATE_TETHERED/IpServer.STATE_LOCAL_ONLY.
+        assertEquals(2, mTetheringDependencies.mIsTetheringSupportedCalls);
+
+        assertEquals(TETHER_ERROR_NO_ERROR, mTethering.getLastTetherError(TEST_P2P_IFNAME));
+
+        // Emulate externally-visible WifiP2pManager effects, when wifi p2p group
+        // is being removed.
+        sendWifiP2pConnectionChanged(false, true, TEST_P2P_IFNAME);
+        mTethering.interfaceRemoved(TEST_P2P_IFNAME);
+        mLooper.dispatchAll();
+
+        verify(mNMService, times(1)).untetherInterface(TEST_P2P_IFNAME);
+        // {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4.
+        verify(mNMService, times(2)).getInterfaceConfig(TEST_P2P_IFNAME);
+        verify(mNMService, times(2))
+                .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
+        verify(mNMService, times(1)).stopTethering();
+        verify(mNMService, times(1)).setIpForwardingEnabled(false);
+        verify(mUpstreamNetworkMonitor, never()).getCurrentPreferredUpstream();
+        verify(mUpstreamNetworkMonitor, never()).selectPreferredUpstreamType(any());
+        verifyNoMoreInteractions(mNMService);
+        // Asking for the last error after the per-interface state machine
+        // has been reaped yields an unknown interface error.
+        assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME));
+    }
+
+    private void workingWifiP2pGroupClient(
+            boolean emulateInterfaceStatusChanged) throws Exception {
+        if (emulateInterfaceStatusChanged) {
+            mTethering.interfaceStatusChanged(TEST_P2P_IFNAME, true);
+        }
+        sendWifiP2pConnectionChanged(true, false, TEST_P2P_IFNAME);
+        mLooper.dispatchAll();
+
+        verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME);
+        verify(mNMService, never())
+                .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
+        verify(mNMService, never()).tetherInterface(TEST_P2P_IFNAME);
+        verify(mNMService, never()).setIpForwardingEnabled(true);
+        verify(mNMService, never()).startTethering(any(String[].class));
+
+        // Emulate externally-visible WifiP2pManager effects, when wifi p2p group
+        // is being removed.
+        sendWifiP2pConnectionChanged(false, false, TEST_P2P_IFNAME);
+        mTethering.interfaceRemoved(TEST_P2P_IFNAME);
+        mLooper.dispatchAll();
+
+        verify(mNMService, never()).untetherInterface(TEST_P2P_IFNAME);
+        verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME);
+        verify(mNMService, never())
+                .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
+        verify(mNMService, never()).stopTethering();
+        verify(mNMService, never()).setIpForwardingEnabled(false);
+        verifyNoMoreInteractions(mNMService);
+        // Asking for the last error after the per-interface state machine
+        // has been reaped yields an unknown interface error.
+        assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME));
+    }
+
+    @Test
+    public void workingWifiP2pGroupOwnerWithIfaceChanged() throws Exception {
+        workingWifiP2pGroupOwner(true);
+    }
+
+    @Test
+    public void workingWifiP2pGroupOwnerSansIfaceChanged() throws Exception {
+        workingWifiP2pGroupOwner(false);
+    }
+
+    private void workingWifiP2pGroupOwnerLegacyMode(
+            boolean emulateInterfaceStatusChanged) throws Exception {
+        // change to legacy mode and update tethering information by chaning SIM
+        when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_p2p_regexs))
+                .thenReturn(new String[]{});
+        final int fakeSubId = 1234;
+        mPhoneStateListener.onActiveDataSubscriptionIdChanged(fakeSubId);
+
+        if (emulateInterfaceStatusChanged) {
+            mTethering.interfaceStatusChanged(TEST_P2P_IFNAME, true);
+        }
+        sendWifiP2pConnectionChanged(true, true, TEST_P2P_IFNAME);
+        mLooper.dispatchAll();
+
+        verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME);
+        verify(mNMService, never())
+                .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
+        verify(mNMService, never()).tetherInterface(TEST_P2P_IFNAME);
+        verify(mNMService, never()).setIpForwardingEnabled(true);
+        verify(mNMService, never()).startTethering(any(String[].class));
+        assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME));
+    }
+    @Test
+    public void workingWifiP2pGroupOwnerLegacyModeWithIfaceChanged() throws Exception {
+        workingWifiP2pGroupOwnerLegacyMode(true);
+    }
+
+    @Test
+    public void workingWifiP2pGroupOwnerLegacyModeSansIfaceChanged() throws Exception {
+        workingWifiP2pGroupOwnerLegacyMode(false);
+    }
+
+    @Test
+    public void workingWifiP2pGroupClientWithIfaceChanged() throws Exception {
+        workingWifiP2pGroupClient(true);
+    }
+
+    @Test
+    public void workingWifiP2pGroupClientSansIfaceChanged() throws Exception {
+        workingWifiP2pGroupClient(false);
+    }
+
+    // TODO: Test that a request for hotspot mode doesn't interfere with an
+    // already operating tethering mode interface.
+}
diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml
index 469bdc6..e4de625 100644
--- a/packages/VpnDialogs/AndroidManifest.xml
+++ b/packages/VpnDialogs/AndroidManifest.xml
@@ -21,7 +21,6 @@
 
     <uses-permission android:name="android.permission.CONTROL_VPN" />
     <uses-permission android:name="android.permission.CONTROL_ALWAYS_ON_VPN" />
-    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
     <uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"/>
 
     <application android:label="VpnDialogs"
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
index 1c2c640..8a4a1c6 100644
--- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -153,6 +153,7 @@
                 Slog.v(TAG, "lockGen=" + lockGeneration + " : lockChanged=" + lockChanged);
                 Slog.v(TAG, "sysEligble=" + sysEligible);
                 Slog.v(TAG, "lockEligible=" + lockEligible);
+                Slog.v(TAG, "hasLockWallpaper=" + hasLockWallpaper);
             }
 
             // only back up the wallpapers if we've been told they're eligible
@@ -174,6 +175,17 @@
                 prefs.edit().putInt(SYSTEM_GENERATION, sysGeneration).apply();
             }
 
+            // If there's no lock wallpaper, then we have nothing to add to the backup.
+            if (lockGeneration == -1) {
+                if (lockChanged && lockImageStage.exists()) {
+                    if (DEBUG) Slog.v(TAG, "Removed lock wallpaper; deleting");
+                    lockImageStage.delete();
+                }
+                if (DEBUG) Slog.v(TAG, "No lock paper set, add nothing to backup");
+                prefs.edit().putInt(LOCK_GENERATION, lockGeneration).apply();
+                return;
+            }
+
             // Don't try to store the lock image if we overran our quota last time
             if (lockEligible && hasLockWallpaper && mLockWallpaperFile.exists() && !mQuotaExceeded) {
                 if (lockChanged || !lockImageStage.exists()) {
diff --git a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/tests/WallpaperBackupAgentTest.java b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/tests/WallpaperBackupAgentTest.java
index 46a7dfe..255fdef 100644
--- a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/tests/WallpaperBackupAgentTest.java
+++ b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/tests/WallpaperBackupAgentTest.java
@@ -19,8 +19,13 @@
 import static android.app.WallpaperManager.FLAG_LOCK;
 import static android.app.WallpaperManager.FLAG_SYSTEM;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -40,6 +45,7 @@
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 import org.junit.runner.RunWith;
+import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -53,78 +59,109 @@
     private static final String SYSTEM_GENERATION = "system_gen";
     private static final String LOCK_GENERATION = "lock_gen";
 
+    private static final int TEST_SYSTEM_WALLPAPER_ID = 1;
+    private static final int TEST_LOCK_WALLPAPER_ID = 2;
+
     @Mock private FullBackupDataOutput mOutput;
     @Mock private WallpaperManager mWallpaperManager;
     @Mock private SharedPreferences mSharedPreferences;
+    @Mock private SharedPreferences.Editor mSharedPreferenceEditor;
 
     @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
 
     private ContextWithServiceOverrides mContext;
+    private IsolatedWallpaperBackupAgent mWallpaperBackupAgent;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
+        when(mSharedPreferences.edit()).thenReturn(mSharedPreferenceEditor);
+        when(mSharedPreferenceEditor.putInt(anyString(), anyInt()))
+                .thenReturn(mSharedPreferenceEditor);
+        doNothing().when(mSharedPreferenceEditor).apply();
+
         mContext = new ContextWithServiceOverrides(ApplicationProvider.getApplicationContext());
         mContext.injectSystemService(WallpaperManager.class, mWallpaperManager);
         mContext.setSharedPreferencesOverride(mSharedPreferences);
+
+        mWallpaperBackupAgent = new IsolatedWallpaperBackupAgent(mTemporaryFolder.getRoot());
+        mWallpaperBackupAgent.attach(mContext);
+        mWallpaperBackupAgent.onCreate();
     }
 
     @Test
     public void testOnFullBackup_withNoChanges_onlyBacksUpEmptyFile() throws IOException {
-        WallpaperBackupAgent wallpaperBackupAgent = new WallpaperBackupAgent();
-        initialiseAgent(wallpaperBackupAgent);
+        mockBackedUpState();
+        mockCurrentWallpapers(TEST_SYSTEM_WALLPAPER_ID, TEST_LOCK_WALLPAPER_ID);
 
-        when(mWallpaperManager.getWallpaperIdForUser(eq(FLAG_SYSTEM), eq(UserHandle.USER_SYSTEM)))
-                .thenReturn(1);
-        when(mWallpaperManager.getWallpaperIdForUser(eq(FLAG_LOCK), eq(UserHandle.USER_SYSTEM)))
-                .thenReturn(1);
-        when(mSharedPreferences.getInt(eq(SYSTEM_GENERATION), eq(-1))).thenReturn(1);
-        when(mSharedPreferences.getInt(eq(LOCK_GENERATION), eq(-1))).thenReturn(1);
+        mWallpaperBackupAgent.onFullBackup(mOutput);
 
-        wallpaperBackupAgent.onFullBackup(mOutput);
-
-        verify(mOutput); // Backup of empty file only
+        assertThat(mWallpaperBackupAgent.mBackedUpFiles.size()).isEqualTo(1);
+        assertThat(mWallpaperBackupAgent.mBackedUpFiles.get(0).getName()).isEqualTo("empty");
     }
 
     @Test
     public void testOnFullBackup_withOnlyChangedSystem_updatesTheSharedPreferences()
             throws IOException {
-        // Create a system wallpaper file
-        mTemporaryFolder.newFile("wallpaper_orig");
-        // Create stageing file to simulate he wallpaper being ready to back up
-        new File(mContext.getFilesDir(), "wallpaper-stage").createNewFile();
+        mockSystemWallpaperReadyToBackUp();
+        mockUnbackedUpState();
+        mockCurrentWallpapers(TEST_SYSTEM_WALLPAPER_ID, TEST_LOCK_WALLPAPER_ID);
 
-        WallpaperBackupAgent wallpaperBackupAgent =
-                new IsolatedWallpaperBackupAgent(mTemporaryFolder.getRoot());
-        initialiseAgent(wallpaperBackupAgent);
+        mWallpaperBackupAgent.onFullBackup(mOutput);
 
-        SharedPreferences.Editor preferenceEditor = mock(SharedPreferences.Editor.class);
+        verify(mSharedPreferenceEditor).putInt(eq(SYSTEM_GENERATION), eq(TEST_SYSTEM_WALLPAPER_ID));
+    }
 
+    @Test
+    public void testOnFullBackup_withLockChangedToMatchSystem_updatesTheSharedPreferences()
+            throws IOException {
+        mockBackedUpState();
+        mockSystemWallpaperReadyToBackUp();
+        mockCurrentWallpapers(TEST_SYSTEM_WALLPAPER_ID, -1);
+
+        mWallpaperBackupAgent.onFullBackup(mOutput);
+
+        InOrder inOrder = inOrder(mSharedPreferenceEditor);
+        inOrder.verify(mSharedPreferenceEditor)
+                .putInt(eq(SYSTEM_GENERATION), eq(TEST_SYSTEM_WALLPAPER_ID));
+        inOrder.verify(mSharedPreferenceEditor).apply();
+        inOrder.verify(mSharedPreferenceEditor).putInt(eq(LOCK_GENERATION), eq(-1));
+        inOrder.verify(mSharedPreferenceEditor).apply();
+    }
+
+    private void mockUnbackedUpState() {
+        mockCurrentWallpapers(TEST_SYSTEM_WALLPAPER_ID, TEST_LOCK_WALLPAPER_ID);
+        when(mSharedPreferences.getInt(eq(SYSTEM_GENERATION), eq(-1))).thenReturn(-1);
+        when(mSharedPreferences.getInt(eq(LOCK_GENERATION), eq(-1))).thenReturn(-1);
+    }
+
+    private void mockBackedUpState() {
+        when(mSharedPreferences.getInt(eq(SYSTEM_GENERATION), eq(-1)))
+                .thenReturn(TEST_SYSTEM_WALLPAPER_ID);
+        when(mSharedPreferences.getInt(eq(LOCK_GENERATION), eq(-1)))
+                .thenReturn(TEST_LOCK_WALLPAPER_ID);
+    }
+
+    private void mockCurrentWallpapers(int systemWallpaperId, int lockWallpaperId) {
         when(mWallpaperManager.getWallpaperIdForUser(eq(FLAG_SYSTEM), eq(UserHandle.USER_SYSTEM)))
-                .thenReturn(2);
+                .thenReturn(systemWallpaperId);
         when(mWallpaperManager.getWallpaperIdForUser(eq(FLAG_LOCK), eq(UserHandle.USER_SYSTEM)))
-                .thenReturn(1);
+                .thenReturn(lockWallpaperId);
         when(mWallpaperManager.isWallpaperBackupEligible(eq(FLAG_SYSTEM))).thenReturn(true);
         when(mWallpaperManager.isWallpaperBackupEligible(eq(FLAG_LOCK))).thenReturn(true);
-        when(mSharedPreferences.getInt(eq(SYSTEM_GENERATION), eq(-1))).thenReturn(1);
-        when(mSharedPreferences.getInt(eq(LOCK_GENERATION), eq(-1))).thenReturn(1);
-        when(mSharedPreferences.edit()).thenReturn(preferenceEditor);
-        when(preferenceEditor.putInt(eq(SYSTEM_GENERATION), eq(2))).thenReturn(preferenceEditor);
-
-        wallpaperBackupAgent.onFullBackup(mOutput);
-
-        verify(preferenceEditor).putInt(eq(SYSTEM_GENERATION), eq(2));
     }
 
-    private void initialiseAgent(WallpaperBackupAgent agent) {
-        agent.attach(mContext);
-        agent.onCreate();
+    private void mockSystemWallpaperReadyToBackUp() throws IOException {
+        // Create a system wallpaper file
+        mTemporaryFolder.newFile("wallpaper_orig");
+        // Create staging file to simulate he wallpaper being ready to back up
+        new File(mContext.getFilesDir(), "wallpaper-stage").createNewFile();
     }
 
-    private static class IsolatedWallpaperBackupAgent extends WallpaperBackupAgent {
+    private class IsolatedWallpaperBackupAgent extends WallpaperBackupAgent {
         File mWallpaperBaseDirectory;
-        List<File> mBackedUpFiles = new ArrayList();
+        List<File> mBackedUpFiles = new ArrayList<>();
 
         IsolatedWallpaperBackupAgent(File wallpaperBaseDirectory) {
             mWallpaperBaseDirectory = wallpaperBaseDirectory;
@@ -139,5 +176,10 @@
         protected void backupFile(File file, FullBackupDataOutput data) {
             mBackedUpFiles.add(file);
         }
+
+        @Override
+        public SharedPreferences getSharedPreferences(File file, int mode) {
+            return mSharedPreferences;
+        }
     }
 }
diff --git a/services/Android.bp b/services/Android.bp
index 041631b..3b56607 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -96,3 +96,8 @@
     name: "services-platform-compat-config",
     src: ":services",
 }
+
+filegroup {
+    name: "art-profile",
+    srcs: ["art-profile"],
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index 339fc96..8ce92a3 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -972,6 +972,9 @@
         if (shouldComputeWindows) {
             mWindowManagerInternal.computeWindowsForAccessibility(displayId);
         }
+
+        mWindowManagerInternal.setAccessibilityIdToSurfaceMetadata(
+                windowToken.asBinder(), windowId);
         return windowId;
     }
 
@@ -991,7 +994,7 @@
             final int removedWindowId = removeAccessibilityInteractionConnectionInternalLocked(
                     token, mGlobalWindowTokens, mGlobalInteractionConnections);
             if (removedWindowId >= 0) {
-                onAccessibilityInteractionConnectionRemovedLocked(removedWindowId);
+                onAccessibilityInteractionConnectionRemovedLocked(removedWindowId, token);
                 if (DEBUG) {
                     Slog.i(LOG_TAG, "Removed global connection for pid:" + Binder.getCallingPid()
                             + " with windowId: " + removedWindowId + " and token: "
@@ -1007,7 +1010,8 @@
                                 getWindowTokensForUserLocked(userId),
                                 getInteractionConnectionsForUserLocked(userId));
                 if (removedWindowIdForUser >= 0) {
-                    onAccessibilityInteractionConnectionRemovedLocked(removedWindowIdForUser);
+                    onAccessibilityInteractionConnectionRemovedLocked(
+                            removedWindowIdForUser, token);
                     if (DEBUG) {
                         Slog.i(LOG_TAG, "Removed user connection for pid:" + Binder.getCallingPid()
                                 + " with windowId: " + removedWindowIdForUser + " and userId:"
@@ -1069,18 +1073,21 @@
      * @param userId The userId to remove
      */
     private void removeAccessibilityInteractionConnectionLocked(int windowId, int userId) {
+        IBinder window = null;
         if (userId == UserHandle.USER_ALL) {
+            window = mGlobalWindowTokens.get(windowId);
             mGlobalWindowTokens.remove(windowId);
             mGlobalInteractionConnections.remove(windowId);
         } else {
             if (isValidUserForWindowTokensLocked(userId)) {
+                window = getWindowTokensForUserLocked(userId).get(windowId);
                 getWindowTokensForUserLocked(userId).remove(windowId);
             }
             if (isValidUserForInteractionConnectionsLocked(userId)) {
                 getInteractionConnectionsForUserLocked(userId).remove(windowId);
             }
         }
-        onAccessibilityInteractionConnectionRemovedLocked(windowId);
+        onAccessibilityInteractionConnectionRemovedLocked(windowId, window);
         if (DEBUG) {
             Slog.i(LOG_TAG, "Removing interaction connection to windowId: " + windowId);
         }
@@ -1091,12 +1098,17 @@
      *
      * @param windowId Removed windowId
      */
-    private void onAccessibilityInteractionConnectionRemovedLocked(int windowId) {
+    private void onAccessibilityInteractionConnectionRemovedLocked(
+            int windowId, @Nullable IBinder binder) {
         // Active window will not update, if windows callback is unregistered.
         // Update active window to invalid, when its a11y interaction connection is removed.
         if (!isTrackingWindowsLocked() && windowId >= 0 && mActiveWindowId == windowId) {
             mActiveWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
         }
+        if (binder != null) {
+            mWindowManagerInternal.setAccessibilityIdToSurfaceMetadata(
+                    binder, AccessibilityWindowInfo.UNDEFINED_WINDOW_ID);
+        }
     }
 
     /**
diff --git a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
index 19ac0d3..1754926 100644
--- a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
+++ b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
@@ -17,6 +17,8 @@
 package com.android.server.accessibility;
 
 import android.accessibilityservice.AccessibilityService;
+import android.app.PendingIntent;
+import android.app.RemoteAction;
 import android.app.StatusBarManager;
 import android.content.Context;
 import android.hardware.input.InputManager;
@@ -25,81 +27,272 @@
 import android.os.Looper;
 import android.os.PowerManager;
 import android.os.SystemClock;
+import android.util.ArrayMap;
+import android.util.Slog;
 import android.view.InputDevice;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ScreenshotHelper;
 import com.android.server.LocalServices;
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
 import java.util.function.Supplier;
 
 /**
- * Handle the back-end of AccessibilityService#performGlobalAction
+ * Handle the back-end of system AccessibilityAction.
+ *
+ * This class should support three use cases with combined usage of new API and legacy API:
+ *
+ * Use case 1: SystemUI doesn't use the new system action registration API. Accessibility
+ *             service doesn't use the new system action API to obtain action list. Accessibility
+ *             service uses legacy global action id to perform predefined system actions.
+ * Use case 2: SystemUI uses the new system action registration API to register available system
+ *             actions. Accessibility service doesn't use the new system action API to obtain action
+ *             list. Accessibility service uses legacy global action id to trigger the system
+ *             actions registered by SystemUI.
+ * Use case 3: SystemUI doesn't use the new system action registration API.Accessibility service
+ *             obtains the available system actions using new AccessibilityService API and trigger
+ *             the predefined system actions.
  */
 public class SystemActionPerformer {
+    private static final String TAG = "SystemActionPerformer";
+
+    interface SystemActionsChangedListener {
+        void onSystemActionsChanged();
+    }
+    private final SystemActionsChangedListener mListener;
+
+    private final Object mSystemActionLock = new Object();
+    // Resource id based ActionId -> RemoteAction
+    @GuardedBy("mSystemActionLock")
+    private final Map<Integer, RemoteAction> mRegisteredSystemActions = new ArrayMap<>();
+
+    // Legacy system actions.
+    private final AccessibilityAction mLegacyHomeAction;
+    private final AccessibilityAction mLegacyBackAction;
+    private final AccessibilityAction mLegacyRecentsAction;
+    private final AccessibilityAction mLegacyNotificationsAction;
+    private final AccessibilityAction mLegacyQuickSettingsAction;
+    private final AccessibilityAction mLegacyPowerDialogAction;
+    private final AccessibilityAction mLegacyToggleSplitScreenAction;
+    private final AccessibilityAction mLegacyLockScreenAction;
+    private final AccessibilityAction mLegacyTakeScreenshotAction;
+
     private final WindowManagerInternal mWindowManagerService;
     private final Context mContext;
     private Supplier<ScreenshotHelper> mScreenshotHelperSupplier;
 
-    public SystemActionPerformer(Context context, WindowManagerInternal windowManagerInternal) {
-        mContext = context;
-        mWindowManagerService = windowManagerInternal;
-        mScreenshotHelperSupplier = null;
+    public SystemActionPerformer(
+            Context context,
+            WindowManagerInternal windowManagerInternal) {
+      this(context, windowManagerInternal, null, null);
     }
 
     // Used to mock ScreenshotHelper
     @VisibleForTesting
-    public SystemActionPerformer(Context context, WindowManagerInternal windowManagerInternal,
+    public SystemActionPerformer(
+            Context context,
+            WindowManagerInternal windowManagerInternal,
             Supplier<ScreenshotHelper> screenshotHelperSupplier) {
-        this(context, windowManagerInternal);
+        this(context, windowManagerInternal, screenshotHelperSupplier, null);
+    }
+
+    public SystemActionPerformer(
+            Context context,
+            WindowManagerInternal windowManagerInternal,
+            Supplier<ScreenshotHelper> screenshotHelperSupplier,
+            SystemActionsChangedListener listener) {
+        mContext = context;
+        mWindowManagerService = windowManagerInternal;
+        mListener = listener;
         mScreenshotHelperSupplier = screenshotHelperSupplier;
+
+        mLegacyHomeAction = new AccessibilityAction(
+                AccessibilityService.GLOBAL_ACTION_HOME,
+                mContext.getResources().getString(
+                        R.string.accessibility_system_action_home_label));
+        mLegacyBackAction = new AccessibilityAction(
+                AccessibilityService.GLOBAL_ACTION_BACK,
+                mContext.getResources().getString(
+                        R.string.accessibility_system_action_back_label));
+        mLegacyRecentsAction = new AccessibilityAction(
+                AccessibilityService.GLOBAL_ACTION_RECENTS,
+                mContext.getResources().getString(
+                        R.string.accessibility_system_action_recents_label));
+        mLegacyNotificationsAction = new AccessibilityAction(
+                AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS,
+                mContext.getResources().getString(
+                        R.string.accessibility_system_action_notifications_label));
+        mLegacyQuickSettingsAction = new AccessibilityAction(
+                AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS,
+                mContext.getResources().getString(
+                        R.string.accessibility_system_action_quick_settings_label));
+        mLegacyPowerDialogAction = new AccessibilityAction(
+                AccessibilityService.GLOBAL_ACTION_POWER_DIALOG,
+                mContext.getResources().getString(
+                        R.string.accessibility_system_action_power_dialog_label));
+        mLegacyToggleSplitScreenAction = new AccessibilityAction(
+                AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN,
+                mContext.getResources().getString(
+                        R.string.accessibility_system_action_toggle_split_screen_label));
+        mLegacyLockScreenAction = new AccessibilityAction(
+                AccessibilityService.GLOBAL_ACTION_LOCK_SCREEN,
+                mContext.getResources().getString(
+                        R.string.accessibility_system_action_lock_screen_label));
+        mLegacyTakeScreenshotAction = new AccessibilityAction(
+                AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT,
+                mContext.getResources().getString(
+                        R.string.accessibility_system_action_screenshot_label));
     }
 
     /**
-     * Performe the system action matching the given action id.
+     * This method is called to register a system action. If a system action is already registered
+     * with the given id, the existing system action will be overwritten.
      */
-    public boolean performSystemAction(int action) {
+    void registerSystemAction(int id, RemoteAction action) {
+        synchronized (mSystemActionLock) {
+            mRegisteredSystemActions.put(id, action);
+        }
+        if (mListener != null) {
+            mListener.onSystemActionsChanged();
+        }
+    }
+
+    /**
+     * This method is called to unregister a system action previously registered through
+     * registerSystemAction.
+     */
+    void unregisterSystemAction(int id) {
+        synchronized (mSystemActionLock) {
+            mRegisteredSystemActions.remove(id);
+        }
+        if (mListener != null) {
+            mListener.onSystemActionsChanged();
+        }
+    }
+
+    /**
+     * This method returns the list of available system actions.
+     */
+    List<AccessibilityAction> getSystemActions() {
+        List<AccessibilityAction> systemActions = new ArrayList<>();
+        synchronized (mSystemActionLock) {
+            for (Map.Entry<Integer, RemoteAction> entry : mRegisteredSystemActions.entrySet()) {
+                AccessibilityAction systemAction = new AccessibilityAction(
+                        entry.getKey(),
+                        entry.getValue().getTitle());
+                systemActions.add(systemAction);
+            }
+
+            // add AccessibilitySystemAction entry for legacy system actions if not overwritten
+            addLegacySystemActions(systemActions);
+        }
+        return systemActions;
+    }
+
+    private void addLegacySystemActions(List<AccessibilityAction> systemActions) {
+        if (!mRegisteredSystemActions.containsKey(AccessibilityService.GLOBAL_ACTION_BACK)) {
+            systemActions.add(mLegacyBackAction);
+        }
+        if (!mRegisteredSystemActions.containsKey(AccessibilityService.GLOBAL_ACTION_HOME)) {
+            systemActions.add(mLegacyHomeAction);
+        }
+        if (!mRegisteredSystemActions.containsKey(AccessibilityService.GLOBAL_ACTION_RECENTS)) {
+            systemActions.add(mLegacyRecentsAction);
+        }
+        if (!mRegisteredSystemActions.containsKey(
+                AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS)) {
+            systemActions.add(mLegacyNotificationsAction);
+        }
+        if (!mRegisteredSystemActions.containsKey(
+                AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS)) {
+            systemActions.add(mLegacyQuickSettingsAction);
+        }
+        if (!mRegisteredSystemActions.containsKey(
+                AccessibilityService.GLOBAL_ACTION_POWER_DIALOG)) {
+            systemActions.add(mLegacyPowerDialogAction);
+        }
+        if (!mRegisteredSystemActions.containsKey(
+                AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN)) {
+            systemActions.add(mLegacyToggleSplitScreenAction);
+        }
+        if (!mRegisteredSystemActions.containsKey(
+                AccessibilityService.GLOBAL_ACTION_LOCK_SCREEN)) {
+            systemActions.add(mLegacyLockScreenAction);
+        }
+        if (!mRegisteredSystemActions.containsKey(
+                AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT)) {
+            systemActions.add(mLegacyTakeScreenshotAction);
+        }
+    }
+
+    /**
+     * Trigger the registered action by the matching action id.
+     */
+    public boolean performSystemAction(int actionId) {
         final long identity = Binder.clearCallingIdentity();
         try {
-            switch (action) {
-                case AccessibilityService.GLOBAL_ACTION_BACK: {
-                    sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK);
-                }
-                return true;
-                case AccessibilityService.GLOBAL_ACTION_HOME: {
-                    sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME);
-                }
-                return true;
-                case AccessibilityService.GLOBAL_ACTION_RECENTS: {
-                    return openRecents();
-                }
-                case AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS: {
-                    expandNotifications();
-                }
-                return true;
-                case AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS: {
-                    expandQuickSettings();
-                }
-                return true;
-                case AccessibilityService.GLOBAL_ACTION_POWER_DIALOG: {
-                    showGlobalActions();
-                }
-                return true;
-                case AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN: {
-                    return toggleSplitScreen();
-                }
-                case AccessibilityService.GLOBAL_ACTION_LOCK_SCREEN: {
-                    return lockScreen();
-                }
-                case AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT: {
-                    return takeScreenshot();
+            synchronized (mSystemActionLock) {
+                // If a system action is registered with the given actionId, call the corresponding
+                // RemoteAction.
+                RemoteAction registeredAction = mRegisteredSystemActions.get(actionId);
+                if (registeredAction != null) {
+                    try {
+                        registeredAction.getActionIntent().send();
+                        return true;
+                    } catch (PendingIntent.CanceledException ex) {
+                        Slog.e(TAG,
+                                "canceled PendingIntent for global action "
+                                        + registeredAction.getTitle(),
+                                ex);
+                    }
+                    return false;
                 }
             }
-            return false;
+
+            // No RemoteAction registered with the given actionId, try the default legacy system
+            // actions.
+            switch (actionId) {
+                case AccessibilityService.GLOBAL_ACTION_BACK: {
+                    sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK);
+                    return true;
+                }
+                case AccessibilityService.GLOBAL_ACTION_HOME: {
+                    sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME);
+                    return true;
+                }
+                case AccessibilityService.GLOBAL_ACTION_RECENTS:
+                    return openRecents();
+                case AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS: {
+                    expandNotifications();
+                    return true;
+                }
+                case AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS: {
+                    expandQuickSettings();
+                    return true;
+                }
+                case AccessibilityService.GLOBAL_ACTION_POWER_DIALOG: {
+                    showGlobalActions();
+                    return true;
+                }
+                case AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN:
+                    return toggleSplitScreen();
+                case AccessibilityService.GLOBAL_ACTION_LOCK_SCREEN:
+                    return lockScreen();
+                case AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT:
+                    return takeScreenshot();
+                default:
+                    return false;
+            }
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index 70fb535..5796142 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -383,7 +383,7 @@
             }
             child.setOnClickListener((v) -> {
                 if (sVerbose) {
-                    Slog.v(TAG, "Applying " + id + " after " + v + " was clicked");
+                    Slog.v(TAG, " Cancelling session after " + v + " clicked");
                 }
                 mCallback.cancelSession();
             });
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index d7114a0..8eea047 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -291,10 +291,17 @@
         }
 
         final TextView noButton = view.findViewById(R.id.autofill_save_no);
-        if (info.getNegativeActionStyle() == SaveInfo.NEGATIVE_BUTTON_STYLE_REJECT) {
-            noButton.setText(R.string.save_password_notnow);
-        } else {
-            noButton.setText(R.string.autofill_save_no);
+        final int negativeActionStyle = info.getNegativeActionStyle();
+        switch (negativeActionStyle) {
+            case SaveInfo.NEGATIVE_BUTTON_STYLE_REJECT:
+                noButton.setText(R.string.autofill_save_notnow);
+                break;
+            case SaveInfo.NEGATIVE_BUTTON_STYLE_NEVER:
+                noButton.setText(R.string.autofill_save_never);
+                break;
+            case SaveInfo.NEGATIVE_BUTTON_STYLE_CANCEL:
+            default:
+                noButton.setText(R.string.autofill_save_no);
         }
         noButton.setOnClickListener((v) -> mListener.onCancel(info.getNegativeActionListener()));
 
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 222a6f2..e8c5299 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -67,6 +67,7 @@
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -1510,6 +1511,26 @@
     }
 
     /**
+     * Excludes keys from KV restore for a given package. The corresponding data will be excluded
+     * from the data set available the backup agent during restore. However,  final list  of keys
+     * that have been excluded will be passed to the agent to make it aware of the exclusions.
+     */
+    public void excludeKeysFromRestore(String packageName, List<String> keys) {
+        int userId = Binder.getCallingUserHandle().getIdentifier();
+        if (!isUserReadyForBackup(userId)) {
+            Slog.w(TAG, "Returning from excludeKeysFromRestore as backup for user" + userId +
+                    " is not initialized yet");
+            return;
+        }
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(userId, "excludeKeysFromRestore()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.excludeKeysFromRestore(packageName, keys);
+        }
+    }
+
+    /**
      * Returns the {@link UserBackupManagerService} instance for the specified user {@code userId}.
      * If the user is not registered with the service (either the user is locked or not eligible for
      * the backup service) then return {@code null}.
diff --git a/services/backup/java/com/android/server/backup/DataChangedJournal.java b/services/backup/java/com/android/server/backup/DataChangedJournal.java
index 498185c..e75eb73 100644
--- a/services/backup/java/com/android/server/backup/DataChangedJournal.java
+++ b/services/backup/java/com/android/server/backup/DataChangedJournal.java
@@ -17,6 +17,7 @@
 package com.android.server.backup;
 
 import android.annotation.Nullable;
+import android.util.Slog;
 
 import java.io.BufferedInputStream;
 import java.io.DataInputStream;
@@ -36,6 +37,7 @@
  * reboot.
  */
 public class DataChangedJournal {
+    private static final String TAG = "DataChangedJournal";
     private static final String FILE_NAME_PREFIX = "journal";
 
     /**
@@ -139,7 +141,12 @@
      */
     static ArrayList<DataChangedJournal> listJournals(File journalDirectory) {
         ArrayList<DataChangedJournal> journals = new ArrayList<>();
-        for (File file : journalDirectory.listFiles()) {
+        File[] journalFiles = journalDirectory.listFiles();
+        if (journalFiles == null) {
+            Slog.w(TAG, "Failed to read journal files");
+            return journals;
+        }
+        for (File file : journalFiles) {
             journals.add(new DataChangedJournal(file));
         }
         return journals;
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 77888db..56b345b 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -158,6 +158,7 @@
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.Queue;
 import java.util.Random;
 import java.util.Set;
@@ -332,6 +333,8 @@
     // locking around the pending-backup management
     private final Object mQueueLock = new Object();
 
+    private final UserBackupPreferences mBackupPreferences;
+
     // The thread performing the sequence of queued backups binds to each app's agent
     // in succession.  Bind notifications are asynchronously delivered through the
     // Activity Manager; use this lock object to signal when a requested binding has
@@ -632,6 +635,8 @@
         // the pending backup set
         mBackupHandler.postDelayed(this::parseLeftoverJournals, INITIALIZATION_DELAY_MILLIS);
 
+        mBackupPreferences = new UserBackupPreferences(mContext, mBaseStateDir);
+
         // Power management
         mWakelock = new BackupWakeLock(
                 mPowerManager.newWakeLock(
@@ -1097,6 +1102,14 @@
         }
     }
 
+    public Map<String, Set<String>> getExcludedRestoreKeys(String... packages) {
+        return mBackupPreferences.getExcludedRestoreKeysForPackages(packages);
+    }
+
+    public Map<String, Set<String>> getAllExcludedRestoreKeys() {
+        return mBackupPreferences.getAllExcludedRestoreKeys();
+    }
+
     /** Used for generating random salts or passwords. */
     public byte[] randomBytes(int bits) {
         byte[] array = new byte[bits / 8];
@@ -2746,6 +2759,14 @@
         }
     }
 
+    /**
+     * Excludes keys from KV restore for a given package. The keys won't be part of the data passed
+     * to the backup agent during restore.
+     */
+    public void excludeKeysFromRestore(String packageName, List<String> keys) {
+        mBackupPreferences.addExcludedKeys(packageName, keys);
+    }
+
     private boolean startConfirmationUi(int token, String action) {
         try {
             Intent confIntent = new Intent(action);
@@ -3341,7 +3362,8 @@
                                 restoreSet,
                                 packageName,
                                 token,
-                                listener);
+                                listener,
+                                getExcludedRestoreKeys(packageName));
                 mBackupHandler.sendMessage(msg);
             } catch (Exception e) {
                 // Calling into the transport broke; back off and proceed with the installation.
diff --git a/services/backup/java/com/android/server/backup/UserBackupPreferences.java b/services/backup/java/com/android/server/backup/UserBackupPreferences.java
new file mode 100644
index 0000000..41b9719
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/UserBackupPreferences.java
@@ -0,0 +1,63 @@
+/*
+ * 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.backup;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/** Manages the persisted backup preferences per user. */
+public class UserBackupPreferences {
+    private static final String PREFERENCES_FILE = "backup_preferences";
+
+    private final SharedPreferences mPreferences;
+    private final SharedPreferences.Editor mEditor;
+
+    UserBackupPreferences(Context conext, File storageDir) {
+        File excludedKeysFile = new File(storageDir, PREFERENCES_FILE);
+        mPreferences = conext.getSharedPreferences(excludedKeysFile, Context.MODE_PRIVATE);
+        mEditor = mPreferences.edit();
+    }
+
+    void addExcludedKeys(String packageName, List<String> keys) {
+        Set<String> existingKeys =
+                new HashSet<>(mPreferences.getStringSet(packageName, Collections.emptySet()));
+        existingKeys.addAll(keys);
+        mEditor.putStringSet(packageName, existingKeys);
+        mEditor.commit();
+    }
+
+    Map<String, Set<String>> getExcludedRestoreKeysForPackages(String... packages) {
+        Map<String, Set<String>> excludedKeys = new HashMap<>();
+        for (String packageName : packages) {
+            excludedKeys.put(packageName,
+                    mPreferences.getStringSet(packageName, Collections.emptySet()));
+        }
+        return excludedKeys;
+    }
+
+    Map<String, Set<String>> getAllExcludedRestoreKeys() {
+        return (Map<String, Set<String>>) mPreferences.getAll();
+    }
+}
diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
index 059b1b9..8c48b84 100644
--- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java
+++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
@@ -279,7 +279,8 @@
                                 params.pmToken,
                                 params.isSystemRestore,
                                 params.filterSet,
-                                params.listener);
+                                params.listener,
+                                params.excludedKeys);
 
                 synchronized (backupManagerService.getPendingRestores()) {
                     if (backupManagerService.isRestoreInProgress()) {
diff --git a/services/backup/java/com/android/server/backup/params/RestoreParams.java b/services/backup/java/com/android/server/backup/params/RestoreParams.java
index c9a6b60..09b7e35 100644
--- a/services/backup/java/com/android/server/backup/params/RestoreParams.java
+++ b/services/backup/java/com/android/server/backup/params/RestoreParams.java
@@ -24,6 +24,9 @@
 import com.android.server.backup.internal.OnTaskFinishedListener;
 import com.android.server.backup.transport.TransportClient;
 
+import java.util.Map;
+import java.util.Set;
+
 public class RestoreParams {
     public final TransportClient transportClient;
     public final IRestoreObserver observer;
@@ -34,6 +37,7 @@
     public final boolean isSystemRestore;
     @Nullable public final String[] filterSet;
     public final OnTaskFinishedListener listener;
+    public final Map<String, Set<String>> excludedKeys;
 
     /**
      * No kill after restore.
@@ -44,7 +48,8 @@
             IBackupManagerMonitor monitor,
             long token,
             PackageInfo packageInfo,
-            OnTaskFinishedListener listener) {
+            OnTaskFinishedListener listener,
+            Map<String, Set<String>> excludedKeys) {
         return new RestoreParams(
                 transportClient,
                 observer,
@@ -54,7 +59,8 @@
                 /* pmToken */ 0,
                 /* isSystemRestore */ false,
                 /* filterSet */ null,
-                listener);
+                listener,
+                excludedKeys);
     }
 
     /**
@@ -67,7 +73,8 @@
             long token,
             String packageName,
             int pmToken,
-            OnTaskFinishedListener listener) {
+            OnTaskFinishedListener listener,
+            Map<String, Set<String>> excludedKeys) {
         String[] filterSet = {packageName};
         return new RestoreParams(
                 transportClient,
@@ -78,7 +85,8 @@
                 pmToken,
                 /* isSystemRestore */ false,
                 filterSet,
-                listener);
+                listener,
+                excludedKeys);
     }
 
     /**
@@ -89,7 +97,8 @@
             IRestoreObserver observer,
             IBackupManagerMonitor monitor,
             long token,
-            OnTaskFinishedListener listener) {
+            OnTaskFinishedListener listener,
+            Map<String, Set<String>> excludedKeys) {
         return new RestoreParams(
                 transportClient,
                 observer,
@@ -99,7 +108,8 @@
                 /* pmToken */ 0,
                 /* isSystemRestore */ true,
                 /* filterSet */ null,
-                listener);
+                listener,
+                excludedKeys);
     }
 
     /**
@@ -112,7 +122,8 @@
             long token,
             String[] filterSet,
             boolean isSystemRestore,
-            OnTaskFinishedListener listener) {
+            OnTaskFinishedListener listener,
+            Map<String, Set<String>> excludedKeys) {
         return new RestoreParams(
                 transportClient,
                 observer,
@@ -122,7 +133,8 @@
                 /* pmToken */ 0,
                 isSystemRestore,
                 filterSet,
-                listener);
+                listener,
+                excludedKeys);
     }
 
     private RestoreParams(
@@ -134,7 +146,8 @@
             int pmToken,
             boolean isSystemRestore,
             @Nullable String[] filterSet,
-            OnTaskFinishedListener listener) {
+            OnTaskFinishedListener listener,
+            Map<String, Set<String>> excludedKeys) {
         this.transportClient = transportClient;
         this.observer = observer;
         this.monitor = monitor;
@@ -144,5 +157,6 @@
         this.isSystemRestore = isSystemRestore;
         this.filterSet = filterSet;
         this.listener = listener;
+        this.excludedKeys = excludedKeys;
     }
 }
diff --git a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
index 5a57cdc..c0f76c3 100644
--- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
+++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
@@ -178,7 +178,8 @@
                                                 observer,
                                                 monitor,
                                                 token,
-                                                listener),
+                                                listener,
+                                                mBackupManagerService.getAllExcludedRestoreKeys()),
                                 "RestoreSession.restoreAll()");
                     } finally {
                         Binder.restoreCallingIdentity(oldId);
@@ -271,7 +272,8 @@
                                                 token,
                                                 packages,
                                                 /* isSystemRestore */ packages.length > 1,
-                                                listener),
+                                                listener,
+                                                mBackupManagerService.getExcludedRestoreKeys(packages)),
                                 "RestoreSession.restorePackages(" + packages.length + " packages)");
                     } finally {
                         Binder.restoreCallingIdentity(oldId);
@@ -363,7 +365,8 @@
                                     monitor,
                                     token,
                                     app,
-                                    listener),
+                                    listener,
+                                    mBackupManagerService.getExcludedRestoreKeys(app.packageName)),
                     "RestoreSession.restorePackage(" + packageName + ")");
         } finally {
             Binder.restoreCallingIdentity(oldId);
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index 675a6eb..be597d7 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -52,6 +52,7 @@
 import android.util.EventLog;
 import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.backup.IBackupTransport;
 import com.android.internal.util.Preconditions;
 import com.android.server.AppWidgetBackupBridge;
@@ -77,6 +78,8 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 public class PerformUnifiedRestoreTask implements BackupRestoreTask {
 
@@ -151,6 +154,8 @@
     // When finished call listener
     private final OnTaskFinishedListener mListener;
 
+    private final Map<String, Set<String>> mExcludedKeys;
+
     // Key/value: bookkeeping about staged data and files for agent access
     private File mBackupDataName;
     private File mStageName;
@@ -161,6 +166,17 @@
     private final int mEphemeralOpToken;
     private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
+    @VisibleForTesting
+    PerformUnifiedRestoreTask(Map<String, Set<String>> excludedKeys) {
+        mExcludedKeys = excludedKeys;
+        mListener = null;
+        mAgentTimeoutParameters = null;
+        mTransportClient = null;
+        mTransportManager = null;
+        mEphemeralOpToken = 0;
+        mUserId = 0;
+    }
+
     // This task can assume that the wakelock is properly held for it and doesn't have to worry
     // about releasing it.
     public PerformUnifiedRestoreTask(
@@ -173,7 +189,8 @@
             int pmToken,
             boolean isFullSystemRestore,
             @Nullable String[] filterSet,
-            OnTaskFinishedListener listener) {
+            OnTaskFinishedListener listener,
+            Map<String, Set<String>> excludedKeys) {
         this.backupManagerService = backupManagerService;
         mUserId = backupManagerService.getUserId();
         mTransportManager = backupManagerService.getTransportManager();
@@ -195,6 +212,8 @@
                 backupManagerService.getAgentTimeoutParameters(),
                 "Timeout parameters cannot be null");
 
+        mExcludedKeys = excludedKeys;
+
         if (targetPackage != null) {
             // Single package restore
             mAcceptSet = new ArrayList<>();
@@ -724,27 +743,7 @@
 
                 BackupDataInput in = new BackupDataInput(stage.getFileDescriptor());
                 BackupDataOutput out = new BackupDataOutput(mBackupData.getFileDescriptor());
-                byte[] buffer = new byte[8192]; // will grow when needed
-                while (in.readNextHeader()) {
-                    final String key = in.getKey();
-                    final int size = in.getDataSize();
-
-                    // is this a special key?
-                    if (key.equals(KEY_WIDGET_STATE)) {
-                        if (DEBUG) {
-                            Slog.i(TAG, "Restoring widget state for " + packageName);
-                        }
-                        mWidgetData = new byte[size];
-                        in.readEntityData(mWidgetData, 0, size);
-                    } else {
-                        if (size > buffer.length) {
-                            buffer = new byte[size];
-                        }
-                        in.readEntityData(buffer, 0, size);
-                        out.writeEntityHeader(key, size);
-                        out.writeEntityData(buffer, size);
-                    }
-                }
+                filterExcludedKeys(packageName, in, out);
 
                 mBackupData.close();
             }
@@ -783,6 +782,39 @@
         }
     }
 
+    @VisibleForTesting
+    void filterExcludedKeys(String packageName, BackupDataInput in, BackupDataOutput out)
+            throws Exception {
+        Set<String> excludedKeysForPackage = mExcludedKeys.get(packageName);
+
+        byte[] buffer = new byte[8192]; // will grow when needed
+        while (in.readNextHeader()) {
+            final String key = in.getKey();
+            final int size = in.getDataSize();
+
+            if (excludedKeysForPackage != null && excludedKeysForPackage.contains(key)) {
+                in.skipEntityData();
+                continue;
+            }
+
+            // is this a special key?
+            if (key.equals(KEY_WIDGET_STATE)) {
+                if (DEBUG) {
+                    Slog.i(TAG, "Restoring widget state for " + packageName);
+                }
+                mWidgetData = new byte[size];
+                in.readEntityData(mWidgetData, 0, size);
+            } else {
+                if (size > buffer.length) {
+                    buffer = new byte[size];
+                }
+                in.readEntityData(buffer, 0, size);
+                out.writeEntityHeader(key, size);
+                out.writeEntityData(buffer, size);
+            }
+        }
+    }
+
     // state RESTORE_FULL : restore one package via streaming engine
     private void restoreFull() {
         // None of this can run on the work looper here, so we spin asynchronous
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 594ac10..203bc61 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -83,9 +83,9 @@
         ":storaged_aidl",
         ":vold_aidl",
         ":platform-compat-config",
-        ":tethering-servicescore-srcs",
         "java/com/android/server/EventLogTags.logtags",
         "java/com/android/server/am/EventLogTags.logtags",
+        "java/com/android/server/wm/EventLogTags.logtags",
         "java/com/android/server/policy/EventLogTags.logtags",
     ],
 
@@ -114,7 +114,6 @@
         "android.hardware.biometrics.face-V1.0-java",
         "android.hardware.biometrics.fingerprint-V2.1-java",
         "android.hardware.oemlock-V1.0-java",
-        "android.hardware.tetheroffload.control-V1.0-java",
         "android.hardware.configstore-V1.0-java",
         "android.hardware.contexthub-V1.0-java",
         "android.hidl.manager-V1.2-java",
@@ -164,10 +163,8 @@
     src: ":services.core.json.gz",
 }
 
-// TODO: this should be removed after tethering migration done.
-filegroup {
-    name: "servicescore-tethering-src",
-    srcs: [
-        "java/com/android/server/connectivity/MockableSystemProperties.java",
-    ],
+platform_compat_config {
+    name: "services-core-platform-compat-config",
+    src: ":services.core.unboosted",
 }
+
diff --git a/services/core/java/android/app/usage/UsageStatsManagerInternal.java b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
index 6641b5b..2f8c506 100644
--- a/services/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -281,4 +281,13 @@
             return mUsageRemaining;
         }
     }
+
+    /**
+     * Called by {@link com.android.server.usage.UsageStatsIdleService} when the device is idle to
+     * prune usage stats data for uninstalled packages.
+     *
+     * @param userId the user associated with the job
+     * @return {@code true} if the pruning was successful, {@code false} otherwise
+     */
+    public abstract boolean pruneUninstalledPackagesData(@UserIdInt int userId);
 }
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 413a79d..21f5f89 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -29,6 +29,8 @@
 import android.content.pm.PackageManager.ComponentInfoFlags;
 import android.content.pm.PackageManager.PackageInfoFlags;
 import android.content.pm.PackageManager.ResolveInfoFlags;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils;
 import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.util.ArraySet;
@@ -326,7 +328,7 @@
      * @param installed the new installed state
      * @return true if the installed state changed as a result
      */
-    public abstract boolean setInstalled(PackageParser.Package pkg,
+    public abstract boolean setInstalled(AndroidPackage pkg,
             @UserIdInt int userId, boolean installed);
 
     /**
@@ -405,7 +407,7 @@
      * Returns whether or not the given package represents a legacy system application released
      * prior to runtime permissions.
      */
-    public abstract boolean isLegacySystemApp(PackageParser.Package pkg);
+    public abstract boolean isLegacySystemApp(AndroidPackage pkg);
 
     /**
      * Get all overlay packages for a user.
@@ -497,13 +499,17 @@
     /**
      * Returns a package object for the given package name.
      */
-    public abstract @Nullable PackageParser.Package getPackage(@NonNull String packageName);
+    public abstract @Nullable AndroidPackage getPackage(@NonNull String packageName);
+
+    // TODO(b/135203078): PackageSetting can't be referenced directly. Should move to a server side
+    //  internal PM which is aware of PS.
+    public abstract @Nullable Object getPackageSetting(String packageName);
 
     /**
      * Returns a package for the given UID. If the UID is part of a shared user ID, one
      * of the packages will be chosen to be returned.
      */
-    public abstract @Nullable PackageParser.Package getPackage(int uid);
+    public abstract @Nullable AndroidPackage getPackage(int uid);
 
     /**
      * Returns a list without a change observer.
@@ -534,17 +540,19 @@
      */
     public abstract void removePackageListObserver(@NonNull PackageListObserver observer);
 
+    // TODO(b/135203078): PackageSetting can't be referenced directly
     /**
      * Returns a package object for the disabled system package name.
      */
-    public abstract @Nullable PackageParser.Package getDisabledSystemPackage(
-            @NonNull String packageName);
+    public abstract @Nullable Object getDisabledSystemPackage(@NonNull String packageName);
 
     /**
      * Returns the package name for the disabled system package.
      *
      * This is equivalent to
-     * {@link #getDisabledSystemPackage(String)}.{@link PackageParser.Package#packageName}
+     * {@link #getDisabledSystemPackage(String)}
+     *     .{@link com.android.server.pm.PackageSetting#pkg}
+     *     .{@link AndroidPackage#getPackageName()}
      */
     public abstract @Nullable String getDisabledSystemPackageName(@NonNull String packageName);
 
@@ -579,7 +587,7 @@
      * @see #canAccessInstantApps
      */
     public abstract boolean filterAppAccess(
-            @NonNull PackageParser.Package pkg, int callingUid, int userId);
+            @NonNull AndroidPackage pkg, int callingUid, int userId);
 
     /**
      * Returns whether or not access to the application should be filtered.
@@ -653,7 +661,8 @@
             throws IOException;
 
     /** Returns {@code true} if the specified component is enabled and matches the given flags. */
-    public abstract boolean isEnabledAndMatches(@NonNull ComponentInfo info, int flags, int userId);
+    public abstract boolean isEnabledAndMatches(
+            @NonNull ComponentParseUtils.ParsedComponent component, int flags, int userId);
 
     /** Returns {@code true} if the given user requires extra badging for icons. */
     public abstract boolean userNeedsBadging(int userId);
@@ -664,14 +673,14 @@
      *
      * @param actionLocked action to be performed
      */
-    public abstract void forEachPackage(Consumer<PackageParser.Package> actionLocked);
+    public abstract void forEachPackage(Consumer<AndroidPackage> actionLocked);
 
     /**
      * Perform the given action for each installed package for a user.
      * Note that packages lock will be held while performin the actions.
      */
     public abstract void forEachInstalledPackage(
-            @NonNull Consumer<PackageParser.Package> actionLocked, @UserIdInt int userId);
+            @NonNull Consumer<AndroidPackage> actionLocked, @UserIdInt int userId);
 
     /** Returns the list of enabled components */
     public abstract ArraySet<String> getEnabledComponents(String packageName, int userId);
@@ -768,9 +777,10 @@
      * @param userId user to uninstall apex package for. Must be
      *               {@link android.os.UserHandle#USER_ALL}, otherwise failure will be reported.
      * @param intentSender a {@link IntentSender} to send result of an uninstall to.
+     * @param flags flags about the uninstall.
      */
     public abstract void uninstallApex(String packageName, long versionCode, int userId,
-            IntentSender intentSender);
+            IntentSender intentSender, int flags);
 
     /**
      * Get fingerprint of build that updated the runtime permissions for a user.
@@ -805,7 +815,7 @@
      * Otherwise, {@code false}.
      */
     public abstract boolean isCallerInstallerOfRecord(
-            @NonNull PackageParser.Package pkg, int callingUid);
+            @NonNull AndroidPackage pkg, int callingUid);
 
     /** Returns whether or not default runtime permissions are granted for the given user */
     public abstract boolean areDefaultRuntimePermissionsGranted(@UserIdInt int userId);
diff --git a/services/core/java/android/os/UserManagerInternal.java b/services/core/java/android/os/UserManagerInternal.java
index 9a7cb3f..a2e9341 100644
--- a/services/core/java/android/os/UserManagerInternal.java
+++ b/services/core/java/android/os/UserManagerInternal.java
@@ -15,6 +15,7 @@
  */
 package android.os;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -22,13 +23,24 @@
 import android.content.pm.UserInfo;
 import android.graphics.Bitmap;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * @hide Only for use within the system server.
  */
 public abstract class UserManagerInternal {
-    public static final int CAMERA_NOT_DISABLED = 0;
-    public static final int CAMERA_DISABLED_LOCALLY = 1;
-    public static final int CAMERA_DISABLED_GLOBALLY = 2;
+
+    public static final int OWNER_TYPE_DEVICE_OWNER = 0;
+    public static final int OWNER_TYPE_PROFILE_OWNER = 1;
+    public static final int OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE = 2;
+    public static final int OWNER_TYPE_NO_OWNER = 3;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {OWNER_TYPE_DEVICE_OWNER, OWNER_TYPE_PROFILE_OWNER,
+            OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE, OWNER_TYPE_NO_OWNER})
+    public @interface OwnerType {
+    }
 
     public interface UserRestrictionsListener {
         /**
@@ -47,13 +59,19 @@
      *
      * @param userId target user id for the local restrictions.
      * @param restrictions a bundle of user restrictions.
-     * @param isDeviceOwner whether {@code userId} corresponds to device owner user id.
-     * @param cameraRestrictionScope is camera disabled and if so what is the scope of restriction.
-     *        Should be one of {@link #CAMERA_NOT_DISABLED}, {@link #CAMERA_DISABLED_LOCALLY} or
-     *                               {@link #CAMERA_DISABLED_GLOBALLY}
+     * @param restrictionOwnerType determines which admin {@code userId} corresponds to.
+     *             The admin can be either
+     *             {@link UserManagerInternal#OWNER_TYPE_DEVICE_OWNER},
+     *             {@link UserManagerInternal#OWNER_TYPE_PROFILE_OWNER},
+     *             {@link UserManagerInternal#OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE}
+     *             or {@link UserManagerInternal#OWNER_TYPE_NO_OWNER}.
+     *             If the admin is a DEVICE_OWNER or a PROFILE_OWNER_ORG_OWNED_DEVICE then
+     *             a restriction may be applied globally depending on which restriction it is,
+     *             otherwise it will be applied just on the current user.
+     * @see OwnerType
      */
     public abstract void setDevicePolicyUserRestrictions(int userId, @Nullable Bundle restrictions,
-            boolean isDeviceOwner, int cameraRestrictionScope);
+            @OwnerType int restrictionOwnerType);
 
     /**
      * Returns the "base" user restrictions.
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index e4d477a..1e5b915 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -790,7 +790,7 @@
             return b.toString();
         }
 
-        public void writeToProto(ProtoOutputStream proto, long fieldId, long nowElapsed,
+        public void dumpDebug(ProtoOutputStream proto, long fieldId, long nowElapsed,
                 long nowRTC) {
             final long token = proto.start(fieldId);
 
@@ -798,7 +798,7 @@
             proto.write(BatchProto.END_REALTIME, end);
             proto.write(BatchProto.FLAGS, flags);
             for (Alarm a : alarms) {
-                a.writeToProto(proto, BatchProto.ALARMS, nowElapsed, nowRTC);
+                a.dumpDebug(proto, BatchProto.ALARMS, nowElapsed, nowRTC);
             }
 
             proto.end(token);
@@ -1320,7 +1320,7 @@
                     + "}";
         }
 
-        public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        public void dumpDebug(ProtoOutputStream proto, long fieldId) {
             final long token = proto.start(fieldId);
 
             proto.write(InFlightProto.UID, mUid);
@@ -1328,16 +1328,16 @@
             proto.write(InFlightProto.WHEN_ELAPSED_MS, mWhenElapsed);
             proto.write(InFlightProto.ALARM_TYPE, mAlarmType);
             if (mPendingIntent != null) {
-                mPendingIntent.writeToProto(proto, InFlightProto.PENDING_INTENT);
+                mPendingIntent.dumpDebug(proto, InFlightProto.PENDING_INTENT);
             }
             if (mBroadcastStats != null) {
-                mBroadcastStats.writeToProto(proto, InFlightProto.BROADCAST_STATS);
+                mBroadcastStats.dumpDebug(proto, InFlightProto.BROADCAST_STATS);
             }
             if (mFilterStats != null) {
-                mFilterStats.writeToProto(proto, InFlightProto.FILTER_STATS);
+                mFilterStats.dumpDebug(proto, InFlightProto.FILTER_STATS);
             }
             if (mWorkSource != null) {
-                mWorkSource.writeToProto(proto, InFlightProto.WORK_SOURCE);
+                mWorkSource.dumpDebug(proto, InFlightProto.WORK_SOURCE);
             }
 
             proto.end(token);
@@ -1387,7 +1387,7 @@
                     + "}";
         }
 
-        public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        public void dumpDebug(ProtoOutputStream proto, long fieldId) {
             final long token = proto.start(fieldId);
 
             proto.write(FilterStatsProto.TAG, mTag);
@@ -1431,7 +1431,7 @@
                     + "}";
         }
 
-        public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        public void dumpDebug(ProtoOutputStream proto, long fieldId) {
             final long token = proto.start(fieldId);
 
             proto.write(BroadcastStatsProto.UID, mUid);
@@ -2573,34 +2573,34 @@
                 proto.end(aToken);
             }
             for (Batch b : mAlarmBatches) {
-                b.writeToProto(proto, AlarmManagerServiceDumpProto.PENDING_ALARM_BATCHES,
+                b.dumpDebug(proto, AlarmManagerServiceDumpProto.PENDING_ALARM_BATCHES,
                         nowElapsed, nowRTC);
             }
             for (int i = 0; i < mPendingBackgroundAlarms.size(); i++) {
                 final ArrayList<Alarm> blockedAlarms = mPendingBackgroundAlarms.valueAt(i);
                 if (blockedAlarms != null) {
                     for (Alarm a : blockedAlarms) {
-                        a.writeToProto(proto,
+                        a.dumpDebug(proto,
                                 AlarmManagerServiceDumpProto.PENDING_USER_BLOCKED_BACKGROUND_ALARMS,
                                 nowElapsed, nowRTC);
                     }
                 }
             }
             if (mPendingIdleUntil != null) {
-                mPendingIdleUntil.writeToProto(
+                mPendingIdleUntil.dumpDebug(
                         proto, AlarmManagerServiceDumpProto.PENDING_IDLE_UNTIL, nowElapsed, nowRTC);
             }
             for (Alarm a : mPendingWhileIdleAlarms) {
-                a.writeToProto(proto, AlarmManagerServiceDumpProto.PENDING_WHILE_IDLE_ALARMS,
+                a.dumpDebug(proto, AlarmManagerServiceDumpProto.PENDING_WHILE_IDLE_ALARMS,
                         nowElapsed, nowRTC);
             }
             if (mNextWakeFromIdle != null) {
-                mNextWakeFromIdle.writeToProto(proto, AlarmManagerServiceDumpProto.NEXT_WAKE_FROM_IDLE,
+                mNextWakeFromIdle.dumpDebug(proto, AlarmManagerServiceDumpProto.NEXT_WAKE_FROM_IDLE,
                         nowElapsed, nowRTC);
             }
 
             for (Alarm a : mPendingNonWakeupAlarms) {
-                a.writeToProto(proto, AlarmManagerServiceDumpProto.PAST_DUE_NON_WAKEUP_ALARMS,
+                a.dumpDebug(proto, AlarmManagerServiceDumpProto.PAST_DUE_NON_WAKEUP_ALARMS,
                         nowElapsed, nowRTC);
             }
 
@@ -2617,7 +2617,7 @@
             proto.write(AlarmManagerServiceDumpProto.LISTENER_FINISH_COUNT, mListenerFinishCount);
 
             for (InFlight f : mInFlight) {
-                f.writeToProto(proto, AlarmManagerServiceDumpProto.OUTSTANDING_DELIVERIES);
+                f.dumpDebug(proto, AlarmManagerServiceDumpProto.OUTSTANDING_DELIVERIES);
             }
 
             for (int i = 0; i < mLastAllowWhileIdleDispatch.size(); ++i) {
@@ -2640,7 +2640,7 @@
                 }
             }
 
-            mLog.writeToProto(proto, AlarmManagerServiceDumpProto.RECENT_PROBLEMS);
+            mLog.dumpDebug(proto, AlarmManagerServiceDumpProto.RECENT_PROBLEMS);
 
             final FilterStats[] topFilters = new FilterStats[10];
             final Comparator<FilterStats> comparator = new Comparator<FilterStats>() {
@@ -2687,7 +2687,7 @@
                 proto.write(AlarmManagerServiceDumpProto.TopAlarm.UID, fs.mBroadcastStats.mUid);
                 proto.write(AlarmManagerServiceDumpProto.TopAlarm.PACKAGE_NAME,
                         fs.mBroadcastStats.mPackageName);
-                fs.writeToProto(proto, AlarmManagerServiceDumpProto.TopAlarm.FILTER);
+                fs.dumpDebug(proto, AlarmManagerServiceDumpProto.TopAlarm.FILTER);
 
                 proto.end(token);
             }
@@ -2699,7 +2699,7 @@
                     final long token = proto.start(AlarmManagerServiceDumpProto.ALARM_STATS);
 
                     BroadcastStats bs = uidStats.valueAt(ip);
-                    bs.writeToProto(proto, AlarmManagerServiceDumpProto.AlarmStat.BROADCAST);
+                    bs.dumpDebug(proto, AlarmManagerServiceDumpProto.AlarmStat.BROADCAST);
 
                     // uidStats is an ArrayMap, which we can't sort.
                     tmpFilters.clear();
@@ -2708,7 +2708,7 @@
                     }
                     Collections.sort(tmpFilters, comparator);
                     for (FilterStats fs : tmpFilters) {
-                        fs.writeToProto(proto, AlarmManagerServiceDumpProto.AlarmStat.FILTERS);
+                        fs.dumpDebug(proto, AlarmManagerServiceDumpProto.AlarmStat.FILTERS);
                     }
 
                     proto.end(token);
@@ -3652,7 +3652,7 @@
             }
         }
 
-        public void writeToProto(ProtoOutputStream proto, long fieldId, long nowElapsed,
+        public void dumpDebug(ProtoOutputStream proto, long fieldId, long nowElapsed,
                 long nowRTC) {
             final long token = proto.start(fieldId);
 
@@ -3664,10 +3664,10 @@
             proto.write(AlarmProto.COUNT, count);
             proto.write(AlarmProto.FLAGS, flags);
             if (alarmClock != null) {
-                alarmClock.writeToProto(proto, AlarmProto.ALARM_CLOCK);
+                alarmClock.dumpDebug(proto, AlarmProto.ALARM_CLOCK);
             }
             if (operation != null) {
-                operation.writeToProto(proto, AlarmProto.OPERATION);
+                operation.dumpDebug(proto, AlarmProto.OPERATION);
             }
             if (listener != null) {
                 proto.write(AlarmProto.LISTENER, listener.asBinder().toString());
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 798a4c6..119b987 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -74,6 +74,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.HashMap;
+import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.Locale;
 import java.util.Map;
@@ -613,22 +614,7 @@
     }
 
     public boolean isEnabled() {
-        if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) {
-            Slog.w(TAG, "isEnabled(): not allowed for non-active and non system user");
-            return false;
-        }
-
-        try {
-            mBluetoothLock.readLock().lock();
-            if (mBluetooth != null) {
-                return mBluetooth.isEnabled();
-            }
-        } catch (RemoteException e) {
-            Slog.e(TAG, "isEnabled()", e);
-        } finally {
-            mBluetoothLock.readLock().unlock();
-        }
-        return false;
+        return getState() == BluetoothAdapter.STATE_ON;
     }
 
     public int getState() {
@@ -695,6 +681,35 @@
         return mIsHearingAidProfileSupported;
     }
 
+    @Override
+    /** @hide */
+    public java.util.List<String> getSystemConfigEnabledProfilesForPackage(String packageName) {
+        if (Binder.getCallingUid() != Process.BLUETOOTH_UID) {
+            Slog.w(TAG, "getSystemConfigEnabledProfilesForPackage(): not allowed for non-bluetooth");
+            return null;
+        }
+
+        SystemConfig systemConfig = SystemConfig.getInstance();
+        if (systemConfig == null) {
+            return null;
+        }
+
+        android.util.ArrayMap<String, Boolean> componentEnabledStates =
+                systemConfig.getComponentsEnabledStates(packageName);
+        if (componentEnabledStates == null) {
+            return null;
+        }
+
+        ArrayList enabledProfiles = new ArrayList<String>();
+        for (Map.Entry<String, Boolean> entry : componentEnabledStates.entrySet()) {
+            if (entry.getValue()) {
+                enabledProfiles.add(entry.getKey());
+            }
+        }
+
+        return enabledProfiles;
+    }
+
     // Monitor change of BLE scan only mode settings.
     private void registerForBleScanModeChange() {
         ContentObserver contentObserver = new ContentObserver(null) {
@@ -1766,14 +1781,8 @@
 
                         //Do enable request
                         try {
-                            if (!mQuietEnable) {
-                                if (!mBluetooth.enable()) {
-                                    Slog.e(TAG, "IBluetooth.enable() returned false");
-                                }
-                            } else {
-                                if (!mBluetooth.enableNoAutoConnect()) {
-                                    Slog.e(TAG, "IBluetooth.enableNoAutoConnect() returned false");
-                                }
+                            if (!mBluetooth.enable(mQuietEnable)) {
+                                Slog.e(TAG, "IBluetooth.enable() returned false");
                             }
                         } catch (RemoteException e) {
                             Slog.e(TAG, "Unable to call enable()", e);
@@ -2048,14 +2057,8 @@
             } else if (mBluetooth != null) {
                 //Enable bluetooth
                 try {
-                    if (!mQuietEnable) {
-                        if (!mBluetooth.enable()) {
-                            Slog.e(TAG, "IBluetooth.enable() returned false");
-                        }
-                    } else {
-                        if (!mBluetooth.enableNoAutoConnect()) {
-                            Slog.e(TAG, "IBluetooth.enableNoAutoConnect() returned false");
-                        }
+                    if (!mBluetooth.enable(mQuietEnable)) {
+                        Slog.e(TAG, "IBluetooth.enable() returned false");
                     }
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Unable to call enable()", e);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index bb7406a..753c117 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -108,6 +108,7 @@
 import android.net.ProxyInfo;
 import android.net.RouteInfo;
 import android.net.SocketKeepalive;
+import android.net.TetheringManager;
 import android.net.UidRange;
 import android.net.Uri;
 import android.net.VpnService;
@@ -187,9 +188,7 @@
 import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
 import com.android.server.connectivity.PermissionMonitor;
 import com.android.server.connectivity.ProxyTracker;
-import com.android.server.connectivity.Tethering;
 import com.android.server.connectivity.Vpn;
-import com.android.server.connectivity.tethering.TetheringDependencies;
 import com.android.server.net.BaseNetdEventCallback;
 import com.android.server.net.BaseNetworkObserver;
 import com.android.server.net.LockdownVpnTracker;
@@ -233,7 +232,6 @@
 
     private static final String DIAG_ARG = "--diag";
     public static final String SHORT_ARG = "--short";
-    private static final String TETHERING_ARG = "tethering";
     private static final String NETWORK_ARG = "networks";
     private static final String REQUEST_ARG = "requests";
 
@@ -280,7 +278,7 @@
 
     private MockableSystemProperties mSystemProperties;
 
-    private Tethering mTethering;
+    private TetheringManager mTetheringManager;
 
     @VisibleForTesting
     protected final PermissionMonitor mPermissionMonitor;
@@ -869,15 +867,10 @@
         }
 
         /**
-         * @see Tethering
+         * Get a reference to the TetheringManager.
          */
-        public Tethering makeTethering(@NonNull Context context,
-                @NonNull INetworkManagementService nms,
-                @NonNull INetworkStatsService statsService,
-                @NonNull INetworkPolicyManager policyManager,
-                @NonNull TetheringDependencies tetheringDeps) {
-            return new Tethering(context, nms, statsService, policyManager,
-                    IoThread.get().getLooper(), getSystemProperties(), tetheringDeps);
+        public TetheringManager getTetheringManager() {
+            return TetheringManager.getInstance();
         }
 
         /**
@@ -932,6 +925,10 @@
             return IIpConnectivityMetrics.Stub.asInterface(
                     ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
         }
+
+        public IBatteryStats getBatteryStatsService() {
+            return BatteryStatsService.getService();
+        }
     }
 
     public ConnectivityService(Context context, INetworkManagementService netManager,
@@ -1075,8 +1072,7 @@
 
         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
 
-        mTethering = deps.makeTethering(mContext, mNMS, mStatsService, mPolicyManager,
-                makeTetheringDependencies());
+        mTetheringManager = mDeps.getTetheringManager();
 
         mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
 
@@ -1111,7 +1107,6 @@
                 mHandler);
 
         try {
-            mNMS.registerObserver(mTethering);
             mNMS.registerObserver(mDataActivityObserver);
         } catch (RemoteException e) {
             loge("Error registering observer :" + e);
@@ -1145,19 +1140,6 @@
         registerPrivateDnsSettingsCallbacks();
     }
 
-    private TetheringDependencies makeTetheringDependencies() {
-        return new TetheringDependencies() {
-            @Override
-            public boolean isTetheringSupported() {
-                return ConnectivityService.this.isTetheringSupported();
-            }
-            @Override
-            public NetworkRequest getDefaultNetworkRequest() {
-                return mDefaultRequest;
-            }
-        };
-    }
-
     private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
         final NetworkCapabilities netCap = new NetworkCapabilities();
         netCap.addCapability(NET_CAPABILITY_INTERNET);
@@ -1413,7 +1395,7 @@
 
     @Override
     public Network getActiveNetworkForUid(int uid, boolean ignoreBlocked) {
-        enforceConnectivityInternalPermission();
+        NetworkStack.checkNetworkStackPermission(mContext);
         return getActiveNetworkForUidInternal(uid, ignoreBlocked);
     }
 
@@ -1455,7 +1437,7 @@
 
     @Override
     public NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked) {
-        enforceConnectivityInternalPermission();
+        NetworkStack.checkNetworkStackPermission(mContext);
         final NetworkState state = getUnfilteredActiveNetworkState(uid);
         filterNetworkStateForUid(state, uid, ignoreBlocked);
         return state.networkInfo;
@@ -1674,8 +1656,8 @@
 
     @Override
     public NetworkState[] getAllNetworkState() {
-        // Require internal since we're handing out IMSI details
-        enforceConnectivityInternalPermission();
+        // This contains IMSI details, so make sure the caller is privileged.
+        NetworkStack.checkNetworkStackPermission(mContext);
 
         final ArrayList<NetworkState> result = Lists.newArrayList();
         for (Network network : getAllNetworks()) {
@@ -1753,7 +1735,7 @@
         }
         enforceChangePermission();
         if (mProtectedNetworks.contains(networkType)) {
-            enforceConnectivityInternalPermission();
+            enforceConnectivityRestrictedNetworksPermission();
         }
 
         InetAddress addr;
@@ -1909,7 +1891,9 @@
             // TODO: relocate this specific callback in Tethering.
             if (restrictBackground) {
                 log("onRestrictBackgroundChanged(true): disabling tethering");
-                mTethering.untetherAll();
+                mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
+                mTetheringManager.stopTethering(ConnectivityManager.TETHERING_USB);
+                mTetheringManager.stopTethering(ConnectivityManager.TETHERING_BLUETOOTH);
             }
         }
     };
@@ -2021,6 +2005,12 @@
                 NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
     }
 
+    private void enforceNetworkFactoryPermission() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.NETWORK_FACTORY,
+                "ConnectivityService");
+    }
+
     private boolean checkSettingsPermission() {
         return checkAnyPermissionOf(
                 android.Manifest.permission.NETWORK_SETTINGS,
@@ -2040,18 +2030,19 @@
                 "ConnectivityService");
     }
 
-    private void enforceConnectivityInternalPermission() {
-        enforceAnyPermissionOf(
-                android.Manifest.permission.CONNECTIVITY_INTERNAL,
-                NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
-    }
-
     private void enforceControlAlwaysOnVpnPermission() {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CONTROL_ALWAYS_ON_VPN,
                 "ConnectivityService");
     }
 
+    private void enforceNetworkStackOrSettingsPermission() {
+        enforceAnyPermissionOf(
+                android.Manifest.permission.NETWORK_SETTINGS,
+                android.Manifest.permission.NETWORK_STACK,
+                NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
+    }
+
     private void enforceNetworkStackSettingsOrSetup() {
         enforceAnyPermissionOf(
                 android.Manifest.permission.NETWORK_SETTINGS,
@@ -2079,7 +2070,11 @@
                     "ConnectivityService");
             return;
         } catch (SecurityException e) { /* fallback to ConnectivityInternalPermission */ }
-        enforceConnectivityInternalPermission();
+        //  TODO: Remove this fallback check after all apps have declared
+        //   CONNECTIVITY_USE_RESTRICTED_NETWORKS.
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CONNECTIVITY_INTERNAL,
+                "ConnectivityService");
     }
 
     private void enforceKeepalivePermission() {
@@ -2088,7 +2083,7 @@
 
     // Public because it's used by mLockdownTracker.
     public void sendConnectedBroadcast(NetworkInfo info) {
-        enforceConnectivityInternalPermission();
+        NetworkStack.checkNetworkStackPermission(mContext);
         sendGeneralBroadcast(info, CONNECTIVITY_ACTION);
     }
 
@@ -2164,7 +2159,7 @@
                     opts.setMaxManifestReceiverApiLevel(Build.VERSION_CODES.M);
                     options = opts.toBundle();
                 }
-                final IBatteryStats bs = BatteryStatsService.getService();
+                final IBatteryStats bs = mDeps.getBatteryStatsService();
                 try {
                     bs.noteConnectivityChanged(intent.getIntExtra(
                             ConnectivityManager.EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_NONE),
@@ -2193,7 +2188,6 @@
         mPermissionMonitor.startMonitoring();
         mProxyTracker.loadGlobalProxy();
         registerNetdEventCallback();
-        mTethering.systemReady();
 
         synchronized (this) {
             mSystemReady = true;
@@ -2405,9 +2399,6 @@
         if (ArrayUtils.contains(args, DIAG_ARG)) {
             dumpNetworkDiagnostics(pw);
             return;
-        } else if (ArrayUtils.contains(args, TETHERING_ARG)) {
-            mTethering.dump(fd, pw, args);
-            return;
         } else if (ArrayUtils.contains(args, NETWORK_ARG)) {
             dumpNetworks(pw);
             return;
@@ -2469,10 +2460,13 @@
         mLegacyTypeTracker.dump(pw);
 
         pw.println();
-        mTethering.dump(fd, pw, args);
+        mKeepaliveTracker.dump(pw);
 
         pw.println();
-        mKeepaliveTracker.dump(pw);
+        pw.println("TetheringManager logs:");
+        pw.increaseIndent();
+        TetheringManager.getInstance().dump(pw);
+        pw.decreaseIndent();
 
         pw.println();
         dumpAvoidBadWifiSettings(pw);
@@ -3606,7 +3600,7 @@
 
     @Override
     public void startCaptivePortalApp(Network network) {
-        enforceConnectivityInternalPermission();
+        enforceNetworkStackOrSettingsPermission();
         mHandler.post(() -> {
             NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
             if (nai == null) return;
@@ -4004,7 +3998,7 @@
     public int tether(String iface, String callerPkg) {
         ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
         if (isTetheringSupported()) {
-            return mTethering.tether(iface);
+            return mTetheringManager.tether(iface);
         } else {
             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
         }
@@ -4016,7 +4010,7 @@
         ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
 
         if (isTetheringSupported()) {
-            return mTethering.untether(iface);
+            return mTetheringManager.untether(iface);
         } else {
             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
         }
@@ -4028,7 +4022,7 @@
         enforceTetherAccessPermission();
 
         if (isTetheringSupported()) {
-            return mTethering.getLastTetherError(iface);
+            return mTetheringManager.getLastTetherError(iface);
         } else {
             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
         }
@@ -4039,7 +4033,7 @@
     public String[] getTetherableUsbRegexs() {
         enforceTetherAccessPermission();
         if (isTetheringSupported()) {
-            return mTethering.getTetherableUsbRegexs();
+            return mTetheringManager.getTetherableUsbRegexs();
         } else {
             return new String[0];
         }
@@ -4049,7 +4043,7 @@
     public String[] getTetherableWifiRegexs() {
         enforceTetherAccessPermission();
         if (isTetheringSupported()) {
-            return mTethering.getTetherableWifiRegexs();
+            return mTetheringManager.getTetherableWifiRegexs();
         } else {
             return new String[0];
         }
@@ -4059,7 +4053,7 @@
     public String[] getTetherableBluetoothRegexs() {
         enforceTetherAccessPermission();
         if (isTetheringSupported()) {
-            return mTethering.getTetherableBluetoothRegexs();
+            return mTetheringManager.getTetherableBluetoothRegexs();
         } else {
             return new String[0];
         }
@@ -4069,7 +4063,7 @@
     public int setUsbTethering(boolean enable, String callerPkg) {
         ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
         if (isTetheringSupported()) {
-            return mTethering.setUsbTethering(enable);
+            return mTetheringManager.setUsbTethering(enable);
         } else {
             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
         }
@@ -4080,25 +4074,25 @@
     @Override
     public String[] getTetherableIfaces() {
         enforceTetherAccessPermission();
-        return mTethering.getTetherableIfaces();
+        return mTetheringManager.getTetherableIfaces();
     }
 
     @Override
     public String[] getTetheredIfaces() {
         enforceTetherAccessPermission();
-        return mTethering.getTetheredIfaces();
+        return mTetheringManager.getTetheredIfaces();
     }
 
     @Override
     public String[] getTetheringErroredIfaces() {
         enforceTetherAccessPermission();
-        return mTethering.getErroredIfaces();
+        return mTetheringManager.getTetheringErroredIfaces();
     }
 
     @Override
     public String[] getTetheredDhcpRanges() {
-        enforceConnectivityInternalPermission();
-        return mTethering.getTetheredDhcpRanges();
+        enforceSettingsPermission();
+        return mTetheringManager.getTetheredDhcpRanges();
     }
 
     @Override
@@ -4126,7 +4120,8 @@
             Binder.restoreCallingIdentity(token);
         }
 
-        return tetherEnabledInSettings && adminUser && mTethering.hasTetherableConfiguration();
+        return tetherEnabledInSettings && adminUser
+                && mTetheringManager.hasTetherableConfiguration();
     }
 
     @Override
@@ -4137,13 +4132,13 @@
             receiver.send(ConnectivityManager.TETHER_ERROR_UNSUPPORTED, null);
             return;
         }
-        mTethering.startTethering(type, receiver, showProvisioningUi);
+        mTetheringManager.startTethering(type, receiver, showProvisioningUi);
     }
 
     @Override
     public void stopTethering(int type, String callerPkg) {
         ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
-        mTethering.stopTethering(type);
+        mTetheringManager.stopTethering(type);
     }
 
     /**
@@ -4157,7 +4152,8 @@
     public void getLatestTetheringEntitlementResult(int type, ResultReceiver receiver,
             boolean showEntitlementUi, String callerPkg) {
         ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
-        mTethering.getLatestTetheringEntitlementResult(type, receiver, showEntitlementUi);
+        mTetheringManager.requestLatestTetheringEntitlementResult(
+                type, receiver, showEntitlementUi);
     }
 
     /** Register tethering event callback. */
@@ -4165,7 +4161,7 @@
     public void registerTetheringEventCallback(ITetheringEventCallback callback,
             String callerPkg) {
         ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
-        mTethering.registerTetheringEventCallback(callback);
+        mTetheringManager.registerTetheringEventCallback(callback);
     }
 
     /** Unregister tethering event callback. */
@@ -4173,7 +4169,7 @@
     public void unregisterTetheringEventCallback(ITetheringEventCallback callback,
             String callerPkg) {
         ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
-        mTethering.unregisterTetheringEventCallback(callback);
+        mTetheringManager.unregisterTetheringEventCallback(callback);
     }
 
     // Called when we lose the default network and have no replacement yet.
@@ -4319,7 +4315,7 @@
 
     @Override
     public void setGlobalProxy(final ProxyInfo proxyProperties) {
-        enforceConnectivityInternalPermission();
+        NetworkStack.checkNetworkStackPermission(mContext);
         mProxyTracker.setGlobalProxy(proxyProperties);
     }
 
@@ -4858,7 +4854,7 @@
 
     @Override
     public String getMobileProvisioningUrl() {
-        enforceConnectivityInternalPermission();
+        enforceSettingsPermission();
         String url = getProvisioningUrlBaseFromFile();
         if (TextUtils.isEmpty(url)) {
             url = mContext.getResources().getString(R.string.mobile_provisioning_url);
@@ -4884,7 +4880,7 @@
     @Override
     public void setProvisioningNotificationVisible(boolean visible, int networkType,
             String action) {
-        enforceConnectivityInternalPermission();
+        enforceSettingsPermission();
         if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
             return;
         }
@@ -5472,7 +5468,7 @@
 
     @Override
     public int registerNetworkFactory(Messenger messenger, String name) {
-        enforceConnectivityInternalPermission();
+        enforceNetworkFactoryPermission();
         NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel(),
                 NetworkFactory.SerialNumber.nextSerialNumber());
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi));
@@ -5487,7 +5483,7 @@
 
     @Override
     public void unregisterNetworkFactory(Messenger messenger) {
-        enforceConnectivityInternalPermission();
+        enforceNetworkFactoryPermission();
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_NETWORK_FACTORY, messenger));
     }
 
@@ -5586,7 +5582,7 @@
     public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
             LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
             int currentScore, NetworkMisc networkMisc, int factorySerialNumber) {
-        enforceConnectivityInternalPermission();
+        enforceNetworkFactoryPermission();
 
         LinkProperties lp = new LinkProperties(linkProperties);
         lp.ensureDirectlyConnectedRoutes();
@@ -5647,7 +5643,8 @@
         // are accurate.
         networkAgent.clatd.fixupLinkProperties(oldLp, newLp);
 
-        updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities);
+        updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities,
+                networkAgent.networkInfo.getType());
 
         // update filtering rules, need to happen after the interface update so netd knows about the
         // new interface (the interface name -> index map becomes initialized)
@@ -5726,21 +5723,26 @@
 
     }
 
-    private void updateInterfaces(LinkProperties newLp, LinkProperties oldLp, int netId,
-                                  NetworkCapabilities caps) {
-        CompareResult<String> interfaceDiff = new CompareResult<>(
+    private void updateInterfaces(final @Nullable LinkProperties newLp,
+            final @Nullable LinkProperties oldLp, final int netId,
+            final @Nullable NetworkCapabilities caps, final int legacyType) {
+        final CompareResult<String> interfaceDiff = new CompareResult<>(
                 oldLp != null ? oldLp.getAllInterfaceNames() : null,
                 newLp != null ? newLp.getAllInterfaceNames() : null);
-        for (String iface : interfaceDiff.added) {
-            try {
-                if (DBG) log("Adding iface " + iface + " to network " + netId);
-                mNMS.addInterfaceToNetwork(iface, netId);
-                wakeupModifyInterface(iface, caps, true);
-            } catch (Exception e) {
-                loge("Exception adding interface: " + e);
+        if (!interfaceDiff.added.isEmpty()) {
+            final IBatteryStats bs = mDeps.getBatteryStatsService();
+            for (final String iface : interfaceDiff.added) {
+                try {
+                    if (DBG) log("Adding iface " + iface + " to network " + netId);
+                    mNMS.addInterfaceToNetwork(iface, netId);
+                    wakeupModifyInterface(iface, caps, true);
+                    bs.noteNetworkInterfaceType(iface, legacyType);
+                } catch (Exception e) {
+                    loge("Exception adding interface: " + e);
+                }
             }
         }
-        for (String iface : interfaceDiff.removed) {
+        for (final String iface : interfaceDiff.removed) {
             try {
                 if (DBG) log("Removing iface " + iface + " from network " + netId);
                 wakeupModifyInterface(iface, caps, false);
@@ -6462,90 +6464,76 @@
                    newNetwork.name(), score, newNetwork.getCurrentScore()));
         }
 
-        // Second pass: process all listens.
-        if (wasBackgroundNetwork != newNetwork.isBackgroundNetwork()) {
-            // If the network went from background to foreground or vice versa, we need to update
-            // its foreground state. It is safe to do this after rematching the requests because
-            // NET_CAPABILITY_FOREGROUND does not affect requests, as is not a requestable
-            // capability and does not affect the network's score (see the Slog.wtf call above).
-            updateCapabilities(score, newNetwork, newNetwork.networkCapabilities);
-        } else {
-            processListenRequests(newNetwork, false);
-        }
-
-        // do this after the default net is switched, but
+        // Notify requested networks are available after the default net is switched, but
         // before LegacyTypeTracker sends legacy broadcasts
         for (NetworkRequestInfo nri : addedRequests) notifyNetworkAvailable(newNetwork, nri);
 
-        // Linger any networks that are no longer needed. This should be done after sending the
-        // available callback for newNetwork.
-        for (NetworkAgentInfo nai : removedRequests) {
-            updateLingerState(nai, now);
-        }
-        // Possibly unlinger newNetwork. Unlingering a network does not send any callbacks so it
-        // does not need to be done in any particular order.
-        updateLingerState(newNetwork, now);
+        // Second pass: process all listens.
+        if (wasBackgroundNetwork != newNetwork.isBackgroundNetwork()) {
+            // TODO : most of the following is useless because the only thing that changed
+            // here is whether the network is a background network. Clean this up.
 
-        if (isNewDefault) {
-            // Maintain the illusion: since the legacy API only
-            // understands one network at a time, we must pretend
-            // that the current default network disconnected before
-            // the new one connected.
-            if (oldDefaultNetwork != null) {
-                mLegacyTypeTracker.remove(oldDefaultNetwork.networkInfo.getType(),
-                                          oldDefaultNetwork, true);
-            }
-            mDefaultInetConditionPublished = newNetwork.lastValidated ? 100 : 0;
-            mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork);
-            notifyLockdownVpn(newNetwork);
-        }
+            NetworkCapabilities newNc = mixInCapabilities(newNetwork,
+                    newNetwork.networkCapabilities);
 
-        if (reassignedRequests.containsValue(newNetwork) || newNetwork.isVPN()) {
-            // Notify battery stats service about this network, both the normal
-            // interface and any stacked links.
-            // TODO: Avoid redoing this; this must only be done once when a network comes online.
-            try {
-                final IBatteryStats bs = BatteryStatsService.getService();
-                final int type = newNetwork.networkInfo.getType();
+            if (Objects.equals(newNetwork.networkCapabilities, newNc)) return;
 
-                final String baseIface = newNetwork.linkProperties.getInterfaceName();
-                bs.noteNetworkInterfaceType(baseIface, type);
-                for (LinkProperties stacked : newNetwork.linkProperties.getStackedLinks()) {
-                    final String stackedIface = stacked.getInterfaceName();
-                    bs.noteNetworkInterfaceType(stackedIface, type);
-                }
-            } catch (RemoteException ignored) {
-            }
-
-            // This has to happen after the notifyNetworkCallbacks as that tickles each
-            // ConnectivityManager instance so that legacy requests correctly bind dns
-            // requests to this network.  The legacy users are listening for this broadcast
-            // and will generally do a dns request so they can ensureRouteToHost and if
-            // they do that before the callbacks happen they'll use the default network.
-            //
-            // TODO: Is there still a race here? We send the broadcast
-            // after sending the callback, but if the app can receive the
-            // broadcast before the callback, it might still break.
-            //
-            // This *does* introduce a race where if the user uses the new api
-            // (notification callbacks) and then uses the old api (getNetworkInfo(type))
-            // they may get old info.  Reverse this after the old startUsing api is removed.
-            // This is on top of the multiple intent sequencing referenced in the todo above.
-            for (int i = 0; i < newNetwork.numNetworkRequests(); i++) {
-                NetworkRequest nr = newNetwork.requestAt(i);
-                if (nr.legacyType != TYPE_NONE && nr.isRequest()) {
-                    // legacy type tracker filters out repeat adds
-                    mLegacyTypeTracker.add(nr.legacyType, newNetwork);
+            final int oldPermission = getNetworkPermission(newNetwork.networkCapabilities);
+            final int newPermission = getNetworkPermission(newNc);
+            if (oldPermission != newPermission && newNetwork.created && !newNetwork.isVPN()) {
+                try {
+                    mNMS.setNetworkPermission(newNetwork.network.netId, newPermission);
+                } catch (RemoteException e) {
+                    loge("Exception in setNetworkPermission: " + e);
                 }
             }
 
-            // A VPN generally won't get added to the legacy tracker in the "for (nri)" loop above,
-            // because usually there are no NetworkRequests it satisfies (e.g., mDefaultRequest
-            // wants the NOT_VPN capability, so it will never be satisfied by a VPN). So, add the
-            // newNetwork to the tracker explicitly (it's a no-op if it has already been added).
-            if (newNetwork.isVPN()) {
-                mLegacyTypeTracker.add(TYPE_VPN, newNetwork);
+            final NetworkCapabilities prevNc;
+            synchronized (newNetwork) {
+                prevNc = newNetwork.networkCapabilities;
+                newNetwork.setNetworkCapabilities(newNc);
             }
+
+            updateUids(newNetwork, prevNc, newNc);
+
+            if (newNetwork.getCurrentScore() == score
+                    && newNc.equalRequestableCapabilities(prevNc)) {
+                // If the requestable capabilities haven't changed, and the score hasn't changed,
+                // then the change we're processing can't affect any requests, it can only affect
+                // the listens on this network.
+                processListenRequests(newNetwork, true);
+            } else {
+                rematchAllNetworksAndRequests();
+                notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_CAP_CHANGED);
+            }
+
+            if (prevNc != null) {
+                final boolean oldMetered = prevNc.isMetered();
+                final boolean newMetered = newNc.isMetered();
+                final boolean meteredChanged = oldMetered != newMetered;
+
+                if (meteredChanged) {
+                    maybeNotifyNetworkBlocked(newNetwork, oldMetered, newMetered,
+                            mRestrictBackground, mRestrictBackground);
+                }
+
+                final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING)
+                        != newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+
+                // Report changes that are interesting for network statistics tracking.
+                if (meteredChanged || roamingChanged) {
+                    notifyIfacesChangedForNetworkStats();
+                }
+            }
+
+            if (!newNc.hasTransport(TRANSPORT_VPN)) {
+                // Tell VPNs about updated capabilities, since they may need to
+                // bubble those changes through.
+                updateAllVpnsCapabilities();
+            }
+
+        } else {
+            processListenRequests(newNetwork, false);
         }
     }
 
@@ -6560,15 +6548,32 @@
         // requests. Once the code has switched to a request-major iteration style, this can
         // be optimized to only do the processing needed.
         final long now = SystemClock.elapsedRealtime();
+        final NetworkAgentInfo oldDefaultNetwork = getDefaultNetwork();
+
         final NetworkAgentInfo[] nais = mNetworkAgentInfos.values().toArray(
                 new NetworkAgentInfo[mNetworkAgentInfos.size()]);
         // Rematch higher scoring networks first to prevent requests first matching a lower
         // scoring network and then a higher scoring network, which could produce multiple
-        // callbacks and inadvertently unlinger networks.
+        // callbacks.
         Arrays.sort(nais);
-        for (NetworkAgentInfo nai : nais) {
+        for (final NetworkAgentInfo nai : nais) {
             rematchNetworkAndRequests(nai, now);
         }
+
+        final NetworkAgentInfo newDefaultNetwork = getDefaultNetwork();
+
+        for (final NetworkAgentInfo nai : nais) {
+            // Rematching may have altered the linger state of some networks, so update all linger
+            // timers. updateLingerState reads the state from the network agent and does nothing
+            // if the state has not changed : the source of truth is controlled with
+            // NetworkAgentInfo#lingerRequest and NetworkAgentInfo#unlingerRequest, which have been
+            // called while rematching the individual networks above.
+            updateLingerState(nai, now);
+        }
+
+        updateLegacyTypeTrackerAndVpnLockdownForRematch(oldDefaultNetwork, newDefaultNetwork, nais);
+
+        // Tear down all unneeded networks.
         for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
             if (unneeded(nai, UnneededFor.TEARDOWN)) {
                 if (nai.getLingerExpiry() > 0) {
@@ -6588,6 +6593,70 @@
         }
     }
 
+    private void updateLegacyTypeTrackerAndVpnLockdownForRematch(
+            @Nullable final NetworkAgentInfo oldDefaultNetwork,
+            @Nullable final NetworkAgentInfo newDefaultNetwork,
+            @NonNull final NetworkAgentInfo[] nais) {
+        if (oldDefaultNetwork != newDefaultNetwork) {
+            // Maintain the illusion : since the legacy API only understands one network at a time,
+            // if the default network changed, apps should see a disconnected broadcast for the
+            // old default network before they see a connected broadcast for the new one.
+            if (oldDefaultNetwork != null) {
+                mLegacyTypeTracker.remove(oldDefaultNetwork.networkInfo.getType(),
+                        oldDefaultNetwork, true);
+            }
+            if (newDefaultNetwork != null) {
+                // The new default network can be newly null if and only if the old default
+                // network doesn't satisfy the default request any more because it lost a
+                // capability.
+                mDefaultInetConditionPublished = newDefaultNetwork.lastValidated ? 100 : 0;
+                mLegacyTypeTracker.add(newDefaultNetwork.networkInfo.getType(), newDefaultNetwork);
+                // If the legacy VPN is connected, notifyLockdownVpn may end up sending a broadcast
+                // to reflect the NetworkInfo of this new network. This broadcast has to be sent
+                // after the disconnect broadcasts above, but before the broadcasts sent by the
+                // legacy type tracker below.
+                // TODO : refactor this, it's too complex
+                notifyLockdownVpn(newDefaultNetwork);
+            }
+        }
+
+        // Now that all the callbacks have been sent, send the legacy network broadcasts
+        // as needed. This is necessary so that legacy requests correctly bind dns
+        // requests to this network. The legacy users are listening for this broadcast
+        // and will generally do a dns request so they can ensureRouteToHost and if
+        // they do that before the callbacks happen they'll use the default network.
+        //
+        // TODO: Is there still a race here? The legacy broadcast will be sent after sending
+        // callbacks, but if apps can receive the broadcast before the callback, they still might
+        // have an inconsistent view of networking.
+        //
+        // This *does* introduce a race where if the user uses the new api
+        // (notification callbacks) and then uses the old api (getNetworkInfo(type))
+        // they may get old info. Reverse this after the old startUsing api is removed.
+        // This is on top of the multiple intent sequencing referenced in the todo above.
+        for (NetworkAgentInfo nai : nais) {
+            addNetworkToLegacyTypeTracker(nai);
+        }
+    }
+
+    private void addNetworkToLegacyTypeTracker(@NonNull final NetworkAgentInfo nai) {
+        for (int i = 0; i < nai.numNetworkRequests(); i++) {
+            NetworkRequest nr = nai.requestAt(i);
+            if (nr.legacyType != TYPE_NONE && nr.isRequest()) {
+                // legacy type tracker filters out repeat adds
+                mLegacyTypeTracker.add(nr.legacyType, nai);
+            }
+        }
+
+        // A VPN generally won't get added to the legacy tracker in the "for (nri)" loop above,
+        // because usually there are no NetworkRequests it satisfies (e.g., mDefaultRequest
+        // wants the NOT_VPN capability, so it will never be satisfied by a VPN). So, add the
+        // newNetwork to the tracker explicitly (it's a no-op if it has already been added).
+        if (nai.isVPN()) {
+            mLegacyTypeTracker.add(TYPE_VPN, nai);
+        }
+    }
+
     private void updateInetCondition(NetworkAgentInfo nai) {
         // Don't bother updating until we've graduated to validated at least once.
         if (!nai.everValidated) return;
@@ -6954,7 +7023,7 @@
 
     @Override
     public String getCaptivePortalServerUrl() {
-        enforceConnectivityInternalPermission();
+        enforceNetworkStackOrSettingsPermission();
         String settingUrl = mContext.getResources().getString(
                 R.string.config_networkCaptivePortalServerUrl);
 
@@ -7007,7 +7076,7 @@
 
     @Override
     public void factoryReset() {
-        enforceConnectivityInternalPermission();
+        enforceSettingsPermission();
 
         if (mUserManager.hasUserRestriction(UserManager.DISALLOW_NETWORK_RESET)) {
             return;
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index bec08f4..b595eb1 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -175,27 +175,6 @@
 3121 pm_package_stats (manual_time|2|3),(quota_time|2|3),(manual_data|2|2),(quota_data|2|2),(manual_cache|2|2),(quota_cache|2|2)
 
 # ---------------------------
-# WindowManagerService.java
-# ---------------------------
-# Out of memory for surfaces.
-31000 wm_no_surface_memory (Window|3),(PID|1|5),(Operation|3)
-# Task created.
-31001 wm_task_created (TaskId|1|5),(StackId|1|5)
-# Task moved to top (1) or bottom (0).
-31002 wm_task_moved (TaskId|1|5),(ToTop|1),(Index|1)
-# Task removed with source explanation.
-31003 wm_task_removed (TaskId|1|5),(Reason|3)
-# Stack created.
-31004 wm_stack_created (StackId|1|5)
-# Home stack moved to top (1) or bottom (0).
-31005 wm_home_stack_moved (ToTop|1)
-# Stack removed.
-31006 wm_stack_removed (StackId|1|5)
-# bootanim finished:
-31007 wm_boot_animation_done (time|2|3)
-
-
-# ---------------------------
 # InputMethodManagerService.java
 # ---------------------------
 # Re-connecting to input method service because we haven't received its interface
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index 80fda19..deb94bd 100644
--- a/services/core/java/com/android/server/IntentResolver.java
+++ b/services/core/java/com/android/server/IntentResolver.java
@@ -294,7 +294,7 @@
         }
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         long token = proto.start(fieldId);
         writeProtoMap(proto, IntentResolverProto.FULL_MIME_TYPES, mTypeToFilter);
         writeProtoMap(proto, IntentResolverProto.BASE_MIME_TYPES, mBaseTypeToFilter);
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 9ebe896..54dfc98 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -81,6 +81,7 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.TimeUtils;
 
 import com.android.internal.annotations.GuardedBy;
@@ -146,8 +147,13 @@
 
         @Override
         public void onBootPhase(int phase) {
-            if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
-                mService.systemRunning();
+            if (phase == PHASE_SYSTEM_SERVICES_READY) {
+                // the location service must be functioning after this boot phase
+                mService.onSystemReady();
+            } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
+                // some providers rely on third party code, so we wait to initialize
+                // providers until third party code is allowed to run
+                mService.onSystemThirdPartyAppsCanStart();
             }
         }
     }
@@ -264,156 +270,155 @@
                 userId -> mContext.getResources().getStringArray(
                         com.android.internal.R.array.config_locationExtraPackageNames));
 
-        // most startup is deferred until systemRunning()
+        // most startup is deferred until systemReady()
     }
 
-    private void systemRunning() {
+    private void onSystemReady() {
         synchronized (mLock) {
-            initializeLocked();
-        }
-    }
+            mPackageManager = mContext.getPackageManager();
+            mAppOps = mContext.getSystemService(AppOpsManager.class);
+            mPowerManager = mContext.getSystemService(PowerManager.class);
+            mActivityManager = mContext.getSystemService(ActivityManager.class);
+            mUserManager = mContext.getSystemService(UserManager.class);
 
-    @GuardedBy("mLock")
-    private void initializeLocked() {
-        mPackageManager = mContext.getPackageManager();
-        mAppOps = mContext.getSystemService(AppOpsManager.class);
-        mPowerManager = mContext.getSystemService(PowerManager.class);
-        mActivityManager = mContext.getSystemService(ActivityManager.class);
-        mUserManager = mContext.getSystemService(UserManager.class);
+            mSettingsStore = new LocationSettingsStore(mContext, mHandler);
+            mLocationFudger = new LocationFudger(mContext, mHandler);
+            mGeofenceManager = new GeofenceManager(mContext, mSettingsStore);
 
-        mSettingsStore = new LocationSettingsStore(mContext, mHandler);
+            PowerManagerInternal localPowerManager =
+                    LocalServices.getService(PowerManagerInternal.class);
 
-        mLocationFudger = new LocationFudger(mContext, mHandler);
-        mGeofenceManager = new GeofenceManager(mContext, mSettingsStore);
-
-        PowerManagerInternal localPowerManager =
-                LocalServices.getService(PowerManagerInternal.class);
-
-        // prepare providers
-        initializeProvidersLocked();
-
-        // add listeners
-        mAppOps.startWatchingMode(
-                AppOpsManager.OP_COARSE_LOCATION,
-                null,
-                AppOpsManager.WATCH_FOREGROUND_CHANGES,
-                new AppOpsManager.OnOpChangedInternalListener() {
-                    public void onOpChanged(int op, String packageName) {
-                        // onOpChanged invoked on ui thread, move to our thread to reduce risk of
+            // add listeners
+            mAppOps.startWatchingMode(
+                    AppOpsManager.OP_COARSE_LOCATION,
+                    null,
+                    AppOpsManager.WATCH_FOREGROUND_CHANGES,
+                    new AppOpsManager.OnOpChangedInternalListener() {
+                        public void onOpChanged(int op, String packageName) {
+                            // onOpChanged invoked on ui thread, move to our thread to reduce risk
+                            // of blocking ui thread
+                            mHandler.post(() -> {
+                                synchronized (mLock) {
+                                    onAppOpChangedLocked();
+                                }
+                            });
+                        }
+                    });
+            mPackageManager.addOnPermissionsChangeListener(
+                    uid -> {
+                        // listener invoked on ui thread, move to our thread to reduce risk of
                         // blocking ui thread
                         mHandler.post(() -> {
                             synchronized (mLock) {
-                                onAppOpChangedLocked();
+                                onPermissionsChangedLocked();
                             }
                         });
-                    }
-                });
-        mPackageManager.addOnPermissionsChangeListener(
-                uid -> {
-                    // listener invoked on ui thread, move to our thread to reduce risk of blocking
-                    // ui thread
-                    mHandler.post(() -> {
-                        synchronized (mLock) {
-                            onPermissionsChangedLocked();
-                        }
                     });
-                });
-        mActivityManager.addOnUidImportanceListener(
-                (uid, importance) -> {
-                    // listener invoked on ui thread, move to our thread to reduce risk of blocking
-                    // ui thread
-                    mHandler.post(() -> {
-                        synchronized (mLock) {
-                            onUidImportanceChangedLocked(uid, importance);
-                        }
+            mActivityManager.addOnUidImportanceListener(
+                    (uid, importance) -> {
+                        // listener invoked on ui thread, move to our thread to reduce risk of
+                        // blocking ui thread
+                        mHandler.post(() -> {
+                            synchronized (mLock) {
+                                onUidImportanceChangedLocked(uid, importance);
+                            }
+                        });
+                    },
+                    FOREGROUND_IMPORTANCE_CUTOFF);
+
+            localPowerManager.registerLowPowerModeObserver(ServiceType.LOCATION,
+                    state -> {
+                        // listener invoked on ui thread, move to our thread to reduce risk of
+                        // blocking ui thread
+                        mHandler.post(() -> {
+                            synchronized (mLock) {
+                                onBatterySaverModeChangedLocked(state.locationMode);
+                            }
+                        });
                     });
-                },
-                FOREGROUND_IMPORTANCE_CUTOFF);
+            mBatterySaverMode = mPowerManager.getLocationPowerSaveMode();
 
-        localPowerManager.registerLowPowerModeObserver(ServiceType.LOCATION,
-                state -> {
-                    // listener invoked on ui thread, move to our thread to reduce risk of blocking
-                    // ui thread
-                    mHandler.post(() -> {
-                        synchronized (mLock) {
-                            onBatterySaverModeChangedLocked(state.locationMode);
-                        }
-                    });
-                });
-        mBatterySaverMode = mPowerManager.getLocationPowerSaveMode();
-
-        mSettingsStore.addOnLocationEnabledChangedListener(() -> {
-            synchronized (mLock) {
-                onLocationModeChangedLocked(true);
-            }
-        });
-        mSettingsStore.addOnLocationProvidersAllowedChangedListener(() -> {
-            synchronized (mLock) {
-                onProviderAllowedChangedLocked();
-            }
-        });
-        mSettingsStore.addOnBackgroundThrottleIntervalChangedListener(() -> {
-            synchronized (mLock) {
-                onBackgroundThrottleIntervalChangedLocked();
-            }
-        });
-        mSettingsStore.addOnBackgroundThrottlePackageWhitelistChangedListener(() -> {
-            synchronized (mLock) {
-                onBackgroundThrottleWhitelistChangedLocked();
-            }
-        });
-        mSettingsStore.addOnIgnoreSettingsPackageWhitelistChangedListener(() -> {
-            synchronized (mLock) {
-                onIgnoreSettingsWhitelistChangedLocked();
-            }
-        });
-
-        new PackageMonitor() {
-            @Override
-            public void onPackageDisappeared(String packageName, int reason) {
+            mSettingsStore.addOnLocationEnabledChangedListener((userId) -> {
                 synchronized (mLock) {
-                    LocationManagerService.this.onPackageDisappearedLocked(packageName);
+                    onLocationModeChangedLocked(userId);
                 }
-            }
-        }.register(mContext, mHandler.getLooper(), true);
-
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
-        intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
-        intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
-        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
-        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
-
-        mContext.registerReceiverAsUser(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                final String action = intent.getAction();
-                if (action == null) {
-                    return;
-                }
+            });
+            mSettingsStore.addOnLocationProvidersAllowedChangedListener((userId) -> {
                 synchronized (mLock) {
-                    switch (action) {
-                        case Intent.ACTION_USER_SWITCHED:
-                            onUserChangedLocked(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
-                            break;
-                        case Intent.ACTION_MANAGED_PROFILE_ADDED:
-                        case Intent.ACTION_MANAGED_PROFILE_REMOVED:
-                            onUserProfilesChangedLocked();
-                            break;
-                        case Intent.ACTION_SCREEN_ON:
-                        case Intent.ACTION_SCREEN_OFF:
-                            onScreenStateChangedLocked();
-                            break;
+                    onProviderAllowedChangedLocked(userId);
+                }
+            });
+            mSettingsStore.addOnBackgroundThrottleIntervalChangedListener(() -> {
+                synchronized (mLock) {
+                    onBackgroundThrottleIntervalChangedLocked();
+                }
+            });
+            mSettingsStore.addOnBackgroundThrottlePackageWhitelistChangedListener(() -> {
+                synchronized (mLock) {
+                    onBackgroundThrottleWhitelistChangedLocked();
+                }
+            });
+            mSettingsStore.addOnIgnoreSettingsPackageWhitelistChangedListener(() -> {
+                synchronized (mLock) {
+                    onIgnoreSettingsWhitelistChangedLocked();
+                }
+            });
+
+            new PackageMonitor() {
+                @Override
+                public void onPackageDisappeared(String packageName, int reason) {
+                    synchronized (mLock) {
+                        LocationManagerService.this.onPackageDisappearedLocked(packageName);
                     }
                 }
-            }
-        }, UserHandle.ALL, intentFilter, null, mHandler);
+            }.register(mContext, mHandler.getLooper(), true);
 
-        // switching the user from null to system here performs the bulk of the initialization work.
-        // the user being changed will cause a reload of all user specific settings, which causes
-        // provider initialization, and propagates changes until a steady state is reached
-        mCurrentUserId = UserHandle.USER_NULL;
-        onUserChangedLocked(ActivityManager.getCurrentUser());
+            IntentFilter intentFilter = new IntentFilter();
+            intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+            intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
+            intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
+            intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
+            intentFilter.addAction(Intent.ACTION_SCREEN_ON);
+
+            mContext.registerReceiverAsUser(new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    final String action = intent.getAction();
+                    if (action == null) {
+                        return;
+                    }
+                    synchronized (mLock) {
+                        switch (action) {
+                            case Intent.ACTION_USER_SWITCHED:
+                                onUserChangedLocked(
+                                        intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+                                break;
+                            case Intent.ACTION_MANAGED_PROFILE_ADDED:
+                            case Intent.ACTION_MANAGED_PROFILE_REMOVED:
+                                onUserProfilesChangedLocked();
+                                break;
+                            case Intent.ACTION_SCREEN_ON:
+                            case Intent.ACTION_SCREEN_OFF:
+                                onScreenStateChangedLocked();
+                                break;
+                        }
+                    }
+                }
+            }, UserHandle.ALL, intentFilter, null, mHandler);
+
+            // switching the user from null to system here performs the bulk of the initialization
+            // work. the user being changed will cause a reload of all user specific settings, which
+            // causes initialization, and propagates changes until a steady state is reached
+            mCurrentUserId = UserHandle.USER_NULL;
+            onUserChangedLocked(ActivityManager.getCurrentUser());
+        }
+    }
+
+    private void onSystemThirdPartyAppsCanStart() {
+        synchronized (mLock) {
+            // prepare providers
+            initializeProvidersLocked();
+        }
     }
 
     @GuardedBy("mLock")
@@ -463,28 +468,24 @@
     }
 
     @GuardedBy("mLock")
-    private void onLocationModeChangedLocked(boolean broadcast) {
+    private void onLocationModeChangedLocked(int userId) {
         if (D) {
-            Log.d(TAG, "location enabled is now " + isLocationEnabled());
+            Log.d(TAG, "[u" + userId + "] location enabled = " + isLocationEnabledForUser(userId));
         }
 
+        Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION);
+        intent.putExtra(LocationManager.EXTRA_LOCATION_ENABLED, isLocationEnabled());
+        mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
+
         for (LocationProvider p : mProviders) {
-            p.onLocationModeChangedLocked();
-        }
-
-        if (broadcast) {
-            // needs to be sent to everyone because we don't know which user may have changed
-            // LOCATION_MODE state.
-            mContext.sendBroadcastAsUser(
-                    new Intent(LocationManager.MODE_CHANGED_ACTION),
-                    UserHandle.ALL);
+            p.onLocationModeChangedLocked(userId);
         }
     }
 
     @GuardedBy("mLock")
-    private void onProviderAllowedChangedLocked() {
+    private void onProviderAllowedChangedLocked(int userId) {
         for (LocationProvider p : mProviders) {
-            p.onAllowedChangedLocked();
+            p.onAllowedChangedLocked(userId);
         }
     }
 
@@ -786,21 +787,14 @@
             Log.d(TAG, "foreground user is changing to " + userId);
         }
 
-        // let providers know the current user is on the way out before changing the user
-        for (LocationProvider p : mProviders) {
-            p.onUserChangingLocked();
-        }
-
+        int oldUserId = userId;
         mCurrentUserId = userId;
         onUserProfilesChangedLocked();
 
-        // if the user changes, per-user settings may also have changed
-        onLocationModeChangedLocked(false);
-        onProviderAllowedChangedLocked();
-
-        // always force useability to be rechecked, even if no per-user settings have changed
+        // let providers know the current user has changed
         for (LocationProvider p : mProviders) {
-            p.onUseableChangedLocked(false);
+            p.onCurrentUserChangedLocked(oldUserId);
+            p.onCurrentUserChangedLocked(mCurrentUserId);
         }
     }
 
@@ -820,7 +814,7 @@
         protected AbstractLocationProvider mProvider;
 
         @GuardedBy("mLock")
-        private boolean mUseable;  // combined state
+        private SparseArray<Boolean> mUseable;  // combined state for each user id
         @GuardedBy("mLock")
         private boolean mAllowed;  // state of LOCATION_PROVIDERS_ALLOWED
         @GuardedBy("mLock")
@@ -839,7 +833,7 @@
             mIsManagedBySettings = isManagedBySettings;
 
             mProvider = null;
-            mUseable = false;
+            mUseable = new SparseArray<>(1);
             mAllowed = !mIsManagedBySettings;
             mEnabled = false;
             mProperties = null;
@@ -864,7 +858,10 @@
             }
 
             mProvider = provider;
-            onUseableChangedLocked(false);
+
+            // it would be more correct to call this for all users, but we know this can only
+            // affect the current user since providers are disabled for non-current users
+            onUseableChangedLocked(false, mCurrentUserId);
         }
 
         public String getName() {
@@ -931,8 +928,8 @@
 
             pw.increaseIndent();
 
-            pw.println("useable=" + mUseable);
-            if (!mUseable) {
+            pw.println("useable=" + isUseableLocked(mCurrentUserId));
+            if (!isUseableLocked(mCurrentUserId)) {
                 pw.println("attached=" + (mProvider != null));
                 if (mIsManagedBySettings) {
                     pw.println("allowed=" + mAllowed);
@@ -997,7 +994,10 @@
                 }
 
                 mEnabled = enabled;
-                onUseableChangedLocked(false);
+
+                // it would be more correct to call this for all users, but we know this can only
+                // affect the current user since providers are disabled for non-current users
+                onUseableChangedLocked(false, mCurrentUserId);
             }
         }
 
@@ -1009,12 +1009,20 @@
         }
 
         @GuardedBy("mLock")
-        public void onLocationModeChangedLocked() {
-            onUseableChangedLocked(false);
+        public void onLocationModeChangedLocked(int userId) {
+            if (!isCurrentProfileLocked(userId)) {
+                return;
+            }
+
+            onUseableChangedLocked(false, userId);
         }
 
         @GuardedBy("mLock")
-        public void onAllowedChangedLocked() {
+        public void onAllowedChangedLocked(int userId) {
+            if (!isCurrentProfileLocked(userId)) {
+                return;
+            }
+
             if (mIsManagedBySettings) {
                 boolean allowed = mSettingsStore.getLocationProvidersAllowed(
                         mCurrentUserId).contains(mName);
@@ -1028,37 +1036,36 @@
                 }
 
                 mAllowed = allowed;
-                onUseableChangedLocked(true);
+                onUseableChangedLocked(true, userId);
             }
         }
 
         @GuardedBy("mLock")
+        public void onCurrentUserChangedLocked(int userId) {
+            onUseableChangedLocked(false, userId);
+        }
+
+        @GuardedBy("mLock")
         public boolean isUseableLocked() {
-            return isUseableForUserLocked(mCurrentUserId);
+            return isUseableLocked(mCurrentUserId);
         }
 
         @GuardedBy("mLock")
-        public boolean isUseableForUserLocked(int userId) {
-            return isCurrentProfileLocked(userId) && mUseable;
+        public boolean isUseableLocked(int userId) {
+            return mUseable.get(userId, Boolean.FALSE);
         }
 
         @GuardedBy("mLock")
-        private boolean isUseableIgnoringAllowedLocked() {
-            return mProvider != null && mProviders.contains(this) && isLocationEnabled()
-                    && mEnabled;
-        }
-
-        @GuardedBy("mLock")
-        public void onUseableChangedLocked(boolean isAllowedChanged) {
+        public void onUseableChangedLocked(boolean isAllowedChanged, int userId) {
             // if any property that contributes to "useability" here changes state, it MUST result
             // in a direct or indrect call to onUseableChangedLocked. this allows the provider to
             // guarantee that it will always eventually reach the correct state.
-            boolean useableIgnoringAllowed = isUseableIgnoringAllowedLocked();
+            boolean useableIgnoringAllowed = mProvider != null && mProviders.contains(this)
+                    && isCurrentProfileLocked(userId) && isLocationEnabledForUser(userId)
+                    && mEnabled;
             boolean useable = useableIgnoringAllowed && mAllowed;
 
-            // update deprecated provider allowed settings for backwards compatibility, and do this
-            // even if there is no change in overall useability state. this may result in trying to
-            // overwrite the same value, but Settings handles deduping this.
+            // update deprecated provider allowed settings for backwards compatibility
             if (mIsManagedBySettings) {
                 // a "-" change derived from the allowed setting should not be overwritten, but a
                 // "+" change should be corrected if necessary
@@ -1067,33 +1074,31 @@
                             mContext.getContentResolver(),
                             Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
                             "+" + mName,
-                            mCurrentUserId);
+                            userId);
                 } else if (!useableIgnoringAllowed) {
                     Settings.Secure.putStringForUser(
                             mContext.getContentResolver(),
                             Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
                             "-" + mName,
-                            mCurrentUserId);
+                            userId);
                 }
 
-                // needs to be sent to all users because whether or not a provider is enabled for
-                // a given user is complicated... we broadcast to everyone and let them figure it
-                // out via isProviderEnabled()
                 Intent intent = new Intent(LocationManager.PROVIDERS_CHANGED_ACTION);
                 intent.putExtra(LocationManager.EXTRA_PROVIDER_NAME, mName);
-                mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+                intent.putExtra(LocationManager.EXTRA_PROVIDER_ENABLED, useable);
+                mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
             }
 
-            if (useable == mUseable) {
+            if (useable == isUseableLocked(userId)) {
                 return;
             }
-            mUseable = useable;
+            mUseable.put(userId, useable);
 
             if (D) {
-                Log.d(TAG, mName + " provider useable is now " + mUseable);
+                Log.d(TAG, "[u" + userId + "] " + mName + " provider useable = " + useable);
             }
 
-            if (!mUseable) {
+            if (!useable) {
                 // If any provider has been disabled, clear all last locations for all
                 // providers. This is to be on the safe side in case a provider has location
                 // derived from this disabled provider.
@@ -1103,15 +1108,6 @@
 
             updateProviderUseableLocked(this);
         }
-
-        @GuardedBy("mLock")
-        public void onUserChangingLocked() {
-            // when the user is about to change, we set this provider to un-useable, and notify all
-            // of the current user clients. when the user is finished changing, useability will be
-            // updated back via onLocationModeChanged() and onAllowedChanged().
-            mUseable = false;
-            updateProviderUseableLocked(this);
-        }
     }
 
     private class MockLocationProvider extends LocationProvider {
@@ -1545,14 +1541,20 @@
 
         mProviders.add(provider);
 
-        provider.onAllowedChangedLocked();  // allowed state may change while provider was inactive
-        provider.onUseableChangedLocked(false);
+        // allowed state may change while provider was inactive
+        provider.onAllowedChangedLocked(mCurrentUserId);
+
+        // it would be more correct to call this for all users, but we know this can only
+        // affect the current user since providers are disabled for non-current users
+        provider.onUseableChangedLocked(false, mCurrentUserId);
     }
 
     @GuardedBy("mLock")
     private void removeProviderLocked(LocationProvider provider) {
         if (mProviders.remove(provider)) {
-            provider.onUseableChangedLocked(false);
+            // it would be more correct to call this for all users, but we know this can only
+            // affect the current user since providers are disabled for non-current users
+            provider.onUseableChangedLocked(false, mCurrentUserId);
         }
     }
 
@@ -2839,7 +2841,7 @@
 
         synchronized (mLock) {
             LocationProvider provider = getLocationProviderLocked(providerName);
-            return provider != null && provider.isUseableForUserLocked(userId);
+            return provider != null && provider.isUseableLocked(userId);
         }
     }
 
@@ -3234,6 +3236,7 @@
         synchronized (mLock) {
             if (mGnssManagerService != null && args.length > 0 && args[0].equals("--gnssmetrics")) {
                 mGnssManagerService.dump(fd, pw, args);
+                return;
             }
 
             ipw.println("Location Manager State:");
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 9efaad8..840b7af 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -18,7 +18,7 @@
 
 import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
 import static android.Manifest.permission.NETWORK_SETTINGS;
-import static android.Manifest.permission.NETWORK_STACK;
+import static android.Manifest.permission.OBSERVE_NETWORK_POLICY;
 import static android.Manifest.permission.SHUTDOWN;
 import static android.net.INetd.FIREWALL_BLACKLIST;
 import static android.net.INetd.FIREWALL_CHAIN_DOZABLE;
@@ -54,6 +54,7 @@
 import android.net.LinkAddress;
 import android.net.Network;
 import android.net.NetworkPolicyManager;
+import android.net.NetworkStack;
 import android.net.NetworkStats;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
@@ -312,13 +313,13 @@
 
     @Override
     public void registerObserver(INetworkManagementEventObserver observer) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         mObservers.register(observer);
     }
 
     @Override
     public void unregisterObserver(INetworkManagementEventObserver observer) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         mObservers.unregister(observer);
     }
 
@@ -453,7 +454,7 @@
 
     @Override
     public void registerTetheringStatsProvider(ITetheringStatsProvider provider, String name) {
-        mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         Preconditions.checkNotNull(provider);
         synchronized(mTetheringStatsProviders) {
             mTetheringStatsProviders.put(provider, name);
@@ -462,7 +463,7 @@
 
     @Override
     public void unregisterTetheringStatsProvider(ITetheringStatsProvider provider) {
-        mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         synchronized(mTetheringStatsProviders) {
             mTetheringStatsProviders.remove(provider);
         }
@@ -470,7 +471,7 @@
 
     @Override
     public void tetherLimitReached(ITetheringStatsProvider provider) {
-        mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         synchronized(mTetheringStatsProviders) {
             if (!mTetheringStatsProviders.containsKey(provider)) {
                 return;
@@ -737,7 +738,9 @@
     //
     @Override
     public String[] listInterfaces() {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        // TODO: Remove CONNECTIVITY_INTERNAL after bluetooth tethering has no longer called these
+        //  APIs.
+        NetworkStack.checkNetworkStackPermissionOr(mContext, CONNECTIVITY_INTERNAL);
         try {
             return mNetdService.interfaceGetList();
         } catch (RemoteException | ServiceSpecificException e) {
@@ -787,7 +790,9 @@
 
     @Override
     public InterfaceConfiguration getInterfaceConfig(String iface) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        // TODO: Remove CONNECTIVITY_INTERNAL after bluetooth tethering has no longer called these
+        //  APIs.
+        NetworkStack.checkNetworkStackPermissionOr(mContext, CONNECTIVITY_INTERNAL);
         final InterfaceConfigurationParcel result;
         try {
             result = mNetdService.interfaceGetCfg(iface);
@@ -805,7 +810,9 @@
 
     @Override
     public void setInterfaceConfig(String iface, InterfaceConfiguration cfg) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        // TODO: Remove CONNECTIVITY_INTERNAL after bluetooth tethering has no longer called these
+        //  APIs.
+        NetworkStack.checkNetworkStackPermissionOr(mContext, CONNECTIVITY_INTERNAL);
         LinkAddress linkAddr = cfg.getLinkAddress();
         if (linkAddr == null || linkAddr.getAddress() == null) {
             throw new IllegalStateException("Null LinkAddress given");
@@ -822,7 +829,7 @@
 
     @Override
     public void setInterfaceDown(String iface) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
         ifcg.setInterfaceDown();
         setInterfaceConfig(iface, ifcg);
@@ -830,7 +837,7 @@
 
     @Override
     public void setInterfaceUp(String iface) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
         ifcg.setInterfaceUp();
         setInterfaceConfig(iface, ifcg);
@@ -838,7 +845,7 @@
 
     @Override
     public void setInterfaceIpv6PrivacyExtensions(String iface, boolean enable) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         try {
             mNetdService.interfaceSetIPv6PrivacyExtensions(iface, enable);
         } catch (RemoteException | ServiceSpecificException e) {
@@ -850,7 +857,7 @@
        IPv6 addresses on interface down, but we need to do full clean up here */
     @Override
     public void clearInterfaceAddresses(String iface) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         try {
             mNetdService.interfaceClearAddrs(iface);
         } catch (RemoteException | ServiceSpecificException e) {
@@ -860,7 +867,7 @@
 
     @Override
     public void enableIpv6(String iface) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         try {
             mNetdService.interfaceSetEnableIPv6(iface, true);
         } catch (RemoteException | ServiceSpecificException e) {
@@ -879,7 +886,7 @@
 
     @Override
     public void disableIpv6(String iface) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         try {
             mNetdService.interfaceSetEnableIPv6(iface, false);
         } catch (RemoteException | ServiceSpecificException e) {
@@ -898,7 +905,7 @@
     }
 
     private void modifyRoute(boolean add, int netId, RouteInfo route) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
 
         final String ifName = route.getInterface();
         final String dst = route.getDestination().toString();
@@ -963,7 +970,7 @@
 
     @Override
     public void setMtu(String iface, int mtu) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
 
         try {
             mNetdService.interfaceSetMtu(iface, mtu);
@@ -982,7 +989,7 @@
 
     @Override
     public boolean getIpForwardingEnabled() throws IllegalStateException{
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
 
         try {
             final boolean isEnabled = mNetdService.ipfwdEnabled();
@@ -994,7 +1001,7 @@
 
     @Override
     public void setIpForwardingEnabled(boolean enable) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         try {
             if (enable) {
                 mNetdService.ipfwdEnableForwarding("tethering");
@@ -1013,7 +1020,7 @@
 
     @Override
     public void startTetheringWithConfiguration(boolean usingLegacyDnsProxy, String[] dhcpRange) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         // an odd number of addrs will fail
         try {
             mNetdService.tetherStartWithConfiguration(usingLegacyDnsProxy, dhcpRange);
@@ -1024,7 +1031,7 @@
 
     @Override
     public void stopTethering() {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         try {
             mNetdService.tetherStop();
         } catch (RemoteException | ServiceSpecificException e) {
@@ -1034,7 +1041,7 @@
 
     @Override
     public boolean isTetheringStarted() {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
 
         try {
             final boolean isEnabled = mNetdService.tetherIsEnabled();
@@ -1046,7 +1053,7 @@
 
     @Override
     public void tetherInterface(String iface) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         try {
             mNetdService.tetherInterfaceAdd(iface);
         } catch (RemoteException | ServiceSpecificException e) {
@@ -1061,7 +1068,7 @@
 
     @Override
     public void untetherInterface(String iface) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         try {
             mNetdService.tetherInterfaceRemove(iface);
         } catch (RemoteException | ServiceSpecificException e) {
@@ -1073,7 +1080,7 @@
 
     @Override
     public String[] listTetheredInterfaces() {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         try {
             return mNetdService.tetherInterfaceList();
         } catch (RemoteException | ServiceSpecificException e) {
@@ -1083,7 +1090,7 @@
 
     @Override
     public void setDnsForwarders(Network network, String[] dns) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
 
         int netId = (network != null) ? network.netId : ConnectivityManager.NETID_UNSET;
 
@@ -1096,7 +1103,7 @@
 
     @Override
     public String[] getDnsForwarders() {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         try {
             return mNetdService.tetherDnsList();
         } catch (RemoteException | ServiceSpecificException e) {
@@ -1127,19 +1134,19 @@
 
     @Override
     public void startInterfaceForwarding(String fromIface, String toIface) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         modifyInterfaceForward(true, fromIface, toIface);
     }
 
     @Override
     public void stopInterfaceForwarding(String fromIface, String toIface) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         modifyInterfaceForward(false, fromIface, toIface);
     }
 
     @Override
     public void enableNat(String internalInterface, String externalInterface) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         try {
             mNetdService.tetherAddForward(internalInterface, externalInterface);
         } catch (RemoteException | ServiceSpecificException e) {
@@ -1149,7 +1156,7 @@
 
     @Override
     public void disableNat(String internalInterface, String externalInterface) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         try {
             mNetdService.tetherRemoveForward(internalInterface, externalInterface);
         } catch (RemoteException | ServiceSpecificException e) {
@@ -1159,7 +1166,7 @@
 
     @Override
     public void addIdleTimer(String iface, int timeout, final int type) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
 
         if (DBG) Slog.d(TAG, "Adding idletimer");
 
@@ -1189,7 +1196,7 @@
 
     @Override
     public void removeIdleTimer(String iface) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
 
         if (DBG) Slog.d(TAG, "Removing idletimer");
 
@@ -1213,7 +1220,7 @@
 
     @Override
     public void setInterfaceQuota(String iface, long quotaBytes) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
 
         synchronized (mQuotaLock) {
             if (mActiveQuotas.containsKey(iface)) {
@@ -1244,7 +1251,7 @@
 
     @Override
     public void removeInterfaceQuota(String iface) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
 
         synchronized (mQuotaLock) {
             if (!mActiveQuotas.containsKey(iface)) {
@@ -1277,7 +1284,7 @@
 
     @Override
     public void setInterfaceAlert(String iface, long alertBytes) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
 
         // quick sanity check
         if (!mActiveQuotas.containsKey(iface)) {
@@ -1301,7 +1308,7 @@
 
     @Override
     public void removeInterfaceAlert(String iface) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
 
         synchronized (mQuotaLock) {
             if (!mActiveAlerts.containsKey(iface)) {
@@ -1321,7 +1328,7 @@
 
     @Override
     public void setGlobalAlert(long alertBytes) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
 
         try {
             mNetdService.bandwidthSetGlobalAlert(alertBytes);
@@ -1331,7 +1338,7 @@
     }
 
     private void setUidOnMeteredNetworkList(int uid, boolean blacklist, boolean enable) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
 
         synchronized (mQuotaLock) {
             boolean oldEnable;
@@ -1431,7 +1438,7 @@
     @Override
     public void setAllowOnlyVpnForUids(boolean add, UidRange[] uidRanges)
             throws ServiceSpecificException {
-        mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         try {
             mNetdService.networkRejectNonSecureVpn(add, toStableParcels(uidRanges));
         } catch (ServiceSpecificException e) {
@@ -1472,7 +1479,7 @@
     @Override
     public void setUidCleartextNetworkPolicy(int uid, int policy) {
         if (Binder.getCallingUid() != uid) {
-            mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+            NetworkStack.checkNetworkStackPermission(mContext);
         }
 
         synchronized (mQuotaLock) {
@@ -1506,7 +1513,6 @@
 
     @Override
     public boolean isBandwidthControlEnabled() {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
         return true;
     }
 
@@ -1557,7 +1563,7 @@
 
     @Override
     public NetworkStats getNetworkStatsTethering(int how) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
 
         final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
         synchronized (mTetheringStatsProviders) {
@@ -1575,7 +1581,7 @@
 
     @Override
     public void addVpnUidRanges(int netId, UidRange[] ranges) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
 
         try {
             mNetdService.networkAddUidRanges(netId, toStableParcels(ranges));
@@ -1586,7 +1592,7 @@
 
     @Override
     public void removeVpnUidRanges(int netId, UidRange[] ranges) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         try {
             mNetdService.networkRemoveUidRanges(netId, toStableParcels(ranges));
         } catch (RemoteException | ServiceSpecificException e) {
@@ -2020,7 +2026,7 @@
     }
 
     private void modifyInterfaceInNetwork(boolean add, int netId, String iface) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
         try {
             if (add) {
                 mNetdService.networkAddInterface(netId, iface);
@@ -2034,7 +2040,7 @@
 
     @Override
     public void addLegacyRouteForNetId(int netId, RouteInfo routeInfo, int uid) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
 
         final LinkAddress la = routeInfo.getDestinationLinkAddress();
         final String ifName = routeInfo.getInterface();
@@ -2055,7 +2061,7 @@
 
     @Override
     public void setDefaultNetId(int netId) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
 
         try {
             mNetdService.networkSetDefault(netId);
@@ -2066,7 +2072,7 @@
 
     @Override
     public void clearDefaultNetId() {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
 
         try {
             mNetdService.networkClearDefault();
@@ -2077,7 +2083,7 @@
 
     @Override
     public void setNetworkPermission(int netId, int permission) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
 
         try {
             mNetdService.networkSetPermissionForNetwork(netId, permission);
@@ -2088,7 +2094,7 @@
 
     @Override
     public void allowProtect(int uid) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
 
         try {
             mNetdService.networkSetProtectAllow(uid);
@@ -2099,7 +2105,7 @@
 
     @Override
     public void denyProtect(int uid) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        NetworkStack.checkNetworkStackPermission(mContext);
 
         try {
             mNetdService.networkSetProtectDeny(uid);
@@ -2145,7 +2151,7 @@
 
     @Override
     public boolean isNetworkRestricted(int uid) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
         return isNetworkRestrictedInternal(uid);
     }
 
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index 3efef01..b9b7bf7 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -16,19 +16,18 @@
 
 package com.android.server;
 
-import android.content.Context;
 import android.content.ContentResolver;
+import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager;
 import android.database.ContentObserver;
+import android.net.NetworkStack;
 import android.net.Uri;
-import android.net.nsd.NsdServiceInfo;
 import android.net.nsd.DnsSdTxtRecord;
 import android.net.nsd.INsdManager;
 import android.net.nsd.NsdManager;
-import android.os.Binder;
-import android.os.HandlerThread;
+import android.net.nsd.NsdServiceInfo;
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.Message;
 import android.os.Messenger;
 import android.os.UserHandle;
@@ -38,6 +37,12 @@
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.net.InetAddress;
@@ -45,13 +50,6 @@
 import java.util.HashMap;
 import java.util.concurrent.CountDownLatch;
 
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.AsyncChannel;
-import com.android.internal.util.DumpUtils;
-import com.android.internal.util.Protocol;
-import com.android.internal.util.State;
-import com.android.internal.util.StateMachine;
-
 /**
  * Network Service Discovery Service handles remote service discovery operation requests by
  * implementing the INsdManager interface.
@@ -565,8 +563,7 @@
     }
 
     public void setEnabled(boolean isEnabled) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL,
-                "NsdService");
+        NetworkStack.checkNetworkStackPermission(mContext);
         mNsdSettings.putEnabledStatus(isEnabled);
         notifyEnabled(isEnabled);
     }
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index a9c38bc..76e0c13 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -4,3 +4,6 @@
 # Vibrator / Threads
 per-file VibratorService.java, DisplayThread.java = michaelwr@google.com
 per-file VibratorService.java, DisplayThread.java = ogunwale@google.com
+
+# Zram writeback
+per-file ZramWriteback.java = minchan@google.com, rajekumar@google.com, srnvs@google.com
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index bc50956..521b393 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -42,6 +42,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.XmlUtils;
 
 import libcore.io.IoUtils;
@@ -56,6 +57,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -80,6 +82,22 @@
     static final String PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED =
             "watchdog_explicit_health_check_enabled";
 
+    public static final int FAILURE_REASON_UNKNOWN = 0;
+    public static final int FAILURE_REASON_NATIVE_CRASH = 1;
+    public static final int FAILURE_REASON_EXPLICIT_HEALTH_CHECK = 2;
+    public static final int FAILURE_REASON_APP_CRASH = 3;
+    public static final int FAILURE_REASON_APP_NOT_RESPONDING = 4;
+
+    @IntDef(prefix = { "FAILURE_REASON_" }, value = {
+            FAILURE_REASON_UNKNOWN,
+            FAILURE_REASON_NATIVE_CRASH,
+            FAILURE_REASON_EXPLICIT_HEALTH_CHECK,
+            FAILURE_REASON_APP_CRASH,
+            FAILURE_REASON_APP_NOT_RESPONDING
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface FailureReasons {}
+
     // Duration to count package failures before it resets to 0
     @VisibleForTesting
     static final int DEFAULT_TRIGGER_FAILURE_DURATION_MS =
@@ -200,7 +218,8 @@
     }
 
     /**
-     * Registers {@code observer} to listen for package failures
+     * Registers {@code observer} to listen for package failures. Add a new ObserverInternal for
+     * this observer if it does not already exist.
      *
      * <p>Observers are expected to call this on boot. It does not specify any packages but
      * it will resume observing any packages requested from a previous boot.
@@ -210,6 +229,11 @@
             ObserverInternal internalObserver = mAllObservers.get(observer.getName());
             if (internalObserver != null) {
                 internalObserver.registeredObserver = observer;
+            } else {
+                internalObserver = new ObserverInternal(observer.getName(), new ArrayList<>());
+                internalObserver.registeredObserver = observer;
+                mAllObservers.put(observer.getName(), internalObserver);
+                syncState("added new observer");
             }
         }
     }
@@ -247,7 +271,14 @@
         List<MonitoredPackage> packages = new ArrayList<>();
         for (int i = 0; i < packageNames.size(); i++) {
             // Health checks not available yet so health check state will start INACTIVE
-            packages.add(new MonitoredPackage(packageNames.get(i), durationMs, false));
+            MonitoredPackage pkg = newMonitoredPackage(packageNames.get(i), durationMs, false);
+            if (pkg != null) {
+                packages.add(pkg);
+            }
+        }
+
+        if (packages.isEmpty()) {
+            return;
         }
 
         // Sync before we add the new packages to the observers. This will #pruneObservers,
@@ -291,14 +322,15 @@
     }
 
     /**
-     * Called when a process fails either due to a crash or ANR.
+     * Called when a process fails due to a crash, ANR or explicit health check.
      *
      * <p>For each package contained in the process, one registered observer with the least user
      * impact will be notified for mitigation.
      *
      * <p>This method could be called frequently if there is a severe problem on the device.
      */
-    public void onPackageFailure(List<VersionedPackage> packages) {
+    public void onPackageFailure(List<VersionedPackage> packages,
+            @FailureReasons int failureReason) {
         mLongTaskHandler.post(() -> {
             synchronized (mLock) {
                 if (mAllObservers.isEmpty()) {
@@ -329,7 +361,7 @@
 
                     // Execute action with least user impact
                     if (currentObserverToNotify != null) {
-                        currentObserverToNotify.execute(versionedPackage);
+                        currentObserverToNotify.execute(versionedPackage, failureReason);
                     }
                 }
             }
@@ -400,7 +432,7 @@
          *
          * @return {@code true} if action was executed successfully, {@code false} otherwise
          */
-        boolean execute(VersionedPackage versionedPackage);
+        boolean execute(VersionedPackage versionedPackage, @FailureReasons int failureReason);
 
         // TODO(b/120598832): Ensure uniqueness?
         /**
@@ -408,6 +440,14 @@
          * watchdog may drop observing packages with the old name.
          */
         String getName();
+
+        /**
+         * An observer will not be pruned if this is set, even if the observer is not explicitly
+         * monitoring any packages.
+         */
+        default boolean isPersistent() {
+            return false;
+        }
     }
 
     long getTriggerFailureCount() {
@@ -619,7 +659,8 @@
             if (!failedPackages.isEmpty()) {
                 onHealthCheckFailed(observer, failedPackages);
             }
-            if (observer.packages.isEmpty()) {
+            if (observer.packages.isEmpty() && (observer.registeredObserver == null
+                    || !observer.registeredObserver.isPersistent())) {
                 Slog.i(TAG, "Discarding observer " + observer.name + ". All packages expired");
                 it.remove();
             }
@@ -634,17 +675,10 @@
                 if (registeredObserver != null) {
                     Iterator<MonitoredPackage> it = failedPackages.iterator();
                     while (it.hasNext()) {
-                        String failedPackage = it.next().getName();
-                        Slog.i(TAG, "Explicit health check failed for package " + failedPackage);
-                        VersionedPackage versionedPkg = getVersionedPackage(failedPackage);
-                        if (versionedPkg == null) {
-                            Slog.w(TAG, "Explicit health check failed but could not find package "
-                                    + failedPackage);
-                            // TODO(b/120598832): Skip. We only continue to pass tests for now since
-                            // the tests don't install any packages
-                            versionedPkg = new VersionedPackage(failedPackage, 0L);
-                        }
-                        registeredObserver.execute(versionedPkg);
+                        VersionedPackage versionedPkg = it.next().mPackage;
+                        Slog.i(TAG, "Explicit health check failed for package " + versionedPkg);
+                        registeredObserver.execute(versionedPkg,
+                                PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK);
                     }
                 }
             }
@@ -654,7 +688,7 @@
     @Nullable
     private VersionedPackage getVersionedPackage(String packageName) {
         final PackageManager pm = mContext.getPackageManager();
-        if (pm == null) {
+        if (pm == null || TextUtils.isEmpty(packageName)) {
             return null;
         }
         try {
@@ -755,7 +789,7 @@
                     final List<VersionedPackage> pkgList = Collections.singletonList(pkg);
                     final long failureCount = getTriggerFailureCount();
                     for (int i = 0; i < failureCount; i++) {
-                        onPackageFailure(pkgList);
+                        onPackageFailure(pkgList, FAILURE_REASON_EXPLICIT_HEALTH_CHECK);
                     }
                 });
     }
@@ -803,6 +837,21 @@
         }
     }
 
+    /** Dump status of every observer in mAllObservers. */
+    public void dump(IndentingPrintWriter pw) {
+        pw.println("Package Watchdog status");
+        pw.increaseIndent();
+        synchronized (mLock) {
+            for (String observerName : mAllObservers.keySet()) {
+                pw.println("Observer name: " + observerName);
+                pw.increaseIndent();
+                ObserverInternal observerInternal = mAllObservers.get(observerName);
+                observerInternal.dump(pw);
+                pw.decreaseIndent();
+            }
+        }
+    }
+
     /**
      * Represents an observer monitoring a set of packages along with the failure thresholds for
      * each package.
@@ -848,7 +897,7 @@
         public void updatePackagesLocked(List<MonitoredPackage> packages) {
             for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
                 MonitoredPackage p = packages.get(pIndex);
-                this.packages.put(p.mName, p);
+                this.packages.put(p.getName(), p);
             }
         }
 
@@ -872,7 +921,7 @@
                 int newState = p.handleElapsedTimeLocked(elapsedMs);
                 if (oldState != HealthCheckState.FAILED
                         && newState == HealthCheckState.FAILED) {
-                    Slog.i(TAG, "Package " + p.mName + " failed health check");
+                    Slog.i(TAG, "Package " + p.getName() + " failed health check");
                     failedPackages.add(p);
                 }
                 if (p.isExpiredLocked()) {
@@ -925,9 +974,10 @@
                                             ATTR_EXPLICIT_HEALTH_CHECK_DURATION));
                             boolean hasPassedHealthCheck = Boolean.parseBoolean(
                                     parser.getAttributeValue(null, ATTR_PASSED_HEALTH_CHECK));
-                            if (!TextUtils.isEmpty(packageName)) {
-                                packages.add(watchdog.new MonitoredPackage(packageName, duration,
-                                        healthCheckDuration, hasPassedHealthCheck));
+                            MonitoredPackage pkg = watchdog.newMonitoredPackage(packageName,
+                                    duration, healthCheckDuration, hasPassedHealthCheck);
+                            if (pkg != null) {
+                                packages.add(pkg);
                             }
                         } catch (NumberFormatException e) {
                             Slog.wtf(TAG, "Skipping package for observer " + observerName, e);
@@ -944,6 +994,22 @@
             }
             return new ObserverInternal(observerName, packages);
         }
+
+        /** Dumps information about this observer and the packages it watches. */
+        public void dump(IndentingPrintWriter pw) {
+            boolean isPersistent = registeredObserver != null && registeredObserver.isPersistent();
+            pw.println("Persistent: " + isPersistent);
+            for (String packageName : packages.keySet()) {
+                MonitoredPackage p = packages.get(packageName);
+                pw.println(packageName +  ": ");
+                pw.increaseIndent();
+                pw.println("# Failures: " + p.mFailureHistory.size());
+                pw.println("Monitoring duration remaining: " + p.mDurationMs + "ms");
+                pw.println("Explicit health check duration: " + p.mHealthCheckDurationMs + "ms");
+                pw.println("Health check state: " + p.toString(p.mHealthCheckState));
+                pw.decreaseIndent();
+            }
+        }
     }
 
     @Retention(SOURCE)
@@ -963,6 +1029,20 @@
         int FAILED = 3;
     }
 
+    MonitoredPackage newMonitoredPackage(
+            String name, long durationMs, boolean hasPassedHealthCheck) {
+        return newMonitoredPackage(name, durationMs, Long.MAX_VALUE, hasPassedHealthCheck);
+    }
+
+    MonitoredPackage newMonitoredPackage(String name, long durationMs, long healthCheckDurationMs,
+            boolean hasPassedHealthCheck) {
+        VersionedPackage pkg = getVersionedPackage(name);
+        if (pkg == null) {
+            return null;
+        }
+        return new MonitoredPackage(pkg, durationMs, healthCheckDurationMs, hasPassedHealthCheck);
+    }
+
     /**
      * Represents a package and its health check state along with the time
      * it should be monitored for.
@@ -971,8 +1051,7 @@
      * instances of this class.
      */
     class MonitoredPackage {
-        //TODO(b/120598832): VersionedPackage?
-        private final String mName;
+        private final VersionedPackage mPackage;
         // Times when package failures happen sorted in ascending order
         @GuardedBy("mLock")
         private final LongArrayQueue mFailureHistory = new LongArrayQueue();
@@ -996,13 +1075,9 @@
         @GuardedBy("mLock")
         private long mHealthCheckDurationMs = Long.MAX_VALUE;
 
-        MonitoredPackage(String name, long durationMs, boolean hasPassedHealthCheck) {
-            this(name, durationMs, Long.MAX_VALUE, hasPassedHealthCheck);
-        }
-
-        MonitoredPackage(String name, long durationMs, long healthCheckDurationMs,
-                boolean hasPassedHealthCheck) {
-            mName = name;
+        private MonitoredPackage(VersionedPackage pkg, long durationMs,
+                long healthCheckDurationMs, boolean hasPassedHealthCheck) {
+            mPackage = pkg;
             mDurationMs = durationMs;
             mHealthCheckDurationMs = healthCheckDurationMs;
             mHasPassedHealthCheck = hasPassedHealthCheck;
@@ -1013,7 +1088,7 @@
         @GuardedBy("mLock")
         public void writeLocked(XmlSerializer out) throws IOException {
             out.startTag(null, TAG_PACKAGE);
-            out.attribute(null, ATTR_NAME, mName);
+            out.attribute(null, ATTR_NAME, getName());
             out.attribute(null, ATTR_DURATION, String.valueOf(mDurationMs));
             out.attribute(null, ATTR_EXPLICIT_HEALTH_CHECK_DURATION,
                     String.valueOf(mHealthCheckDurationMs));
@@ -1053,7 +1128,7 @@
         public int setHealthCheckActiveLocked(long initialHealthCheckDurationMs) {
             if (initialHealthCheckDurationMs <= 0) {
                 Slog.wtf(TAG, "Cannot set non-positive health check duration "
-                        + initialHealthCheckDurationMs + "ms for package " + mName
+                        + initialHealthCheckDurationMs + "ms for package " + getName()
                         + ". Using total duration " + mDurationMs + "ms instead");
                 initialHealthCheckDurationMs = mDurationMs;
             }
@@ -1072,7 +1147,7 @@
         @GuardedBy("mLock")
         public int handleElapsedTimeLocked(long elapsedMs) {
             if (elapsedMs <= 0) {
-                Slog.w(TAG, "Cannot handle non-positive elapsed time for package " + mName);
+                Slog.w(TAG, "Cannot handle non-positive elapsed time for package " + getName());
                 return mHealthCheckState;
             }
             // Transitions to FAILED if now <= 0 and health check not passed
@@ -1105,7 +1180,7 @@
 
         /** Returns the monitored package name. */
         private String getName() {
-            return mName;
+            return mPackage.getPackageName();
         }
 
         /**
@@ -1170,7 +1245,7 @@
             } else {
                 mHealthCheckState = HealthCheckState.ACTIVE;
             }
-            Slog.i(TAG, "Updated health check state for package " + mName + ": "
+            Slog.i(TAG, "Updated health check state for package " + getName() + ": "
                     + toString(oldState) + " -> " + toString(mHealthCheckState));
             return mHealthCheckState;
         }
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index d5f7956..135f6f3 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -45,6 +45,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.DeviceConfig;
 import android.provider.MediaStore;
 import android.provider.Settings;
 import android.system.ErrnoException;
@@ -97,9 +98,12 @@
     private static final int KEY_HOME = 1;
     private static final int KEY_ASSISTANT = 2;
 
-    // Pin the camera application.
-    private static boolean PROP_PIN_CAMERA = SystemProperties.getBoolean(
-            "pinner.pin_camera", true);
+    // Pin the camera application. Default to the system property only if the experiment phenotype
+    // property is not set.
+    private static boolean PROP_PIN_CAMERA =
+            DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT,
+                                    "pin_camera",
+                                    SystemProperties.getBoolean("pinner.pin_camera", true));
     // Pin using pinlist.meta when pinning apps.
     private static boolean PROP_PIN_PINLIST = SystemProperties.getBoolean(
             "pinner.use_pinlist", true);
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index a4bc3bd..822fc90 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -118,6 +118,7 @@
 import android.util.ArrayMap;
 import android.util.AtomicFile;
 import android.util.DataUnit;
+import android.util.FeatureFlagUtils;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
@@ -354,8 +355,7 @@
     @GuardedBy("mLock")
     private String mMoveTargetUuid;
 
-    @Nullable
-    private volatile String mMediaStoreAuthorityPackageName = null;
+    private volatile int mMediaStoreAuthorityAppId = -1;
 
     private volatile int mCurrentUserId = UserHandle.USER_SYSTEM;
 
@@ -819,7 +819,6 @@
                     refreshFuseSettings();
                 });
         refreshIsolatedStorageSettings();
-        refreshFuseSettings();
     }
 
     /**
@@ -883,16 +882,25 @@
         SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE, Boolean.toString(res));
     }
 
+    /**
+     * The most recent flag change takes precedence. Change fuse Settings flag if Device Config is
+     * changed. Settings flag change will in turn change fuse system property (persist.sys.fuse)
+     * whenever the user reboots.
+     */
     private void refreshFuseSettings() {
         int isFuseEnabled = DeviceConfig.getInt(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
                 FUSE_ENABLED, 0);
         if (isFuseEnabled == 1) {
-            SystemProperties.set(StorageManager.PROP_FUSE, "true");
+            Slog.d(TAG, "Device Config flag for FUSE is enabled, turn Settings fuse flag on");
+            SystemProperties.set(FeatureFlagUtils.PERSIST_PREFIX
+                    + FeatureFlagUtils.SETTINGS_FUSE_FLAG, "true");
         } else if (isFuseEnabled == -1) {
-            SystemProperties.set(StorageManager.PROP_FUSE, "false");
+            Slog.d(TAG, "Device Config flag for FUSE is disabled, turn Settings fuse flag off");
+            SystemProperties.set(FeatureFlagUtils.PERSIST_PREFIX
+                    + FeatureFlagUtils.SETTINGS_FUSE_FLAG, "false");
         }
         // else, keep the build config.
-        // This can be overridden be direct adjustment of persist.sys.prop
+        // This can be overridden by direct adjustment of persist.sys.fflag.override.settings_fuse
     }
 
     /**
@@ -1609,6 +1617,23 @@
         }
     }
 
+    /**
+     *  Checks if user changed the persistent settings_fuse flag from Settings UI
+     *  and updates PROP_FUSE (reboots if changed).
+     */
+    private void updateFusePropFromSettings() {
+        Boolean settingsFuseFlag = SystemProperties.getBoolean((FeatureFlagUtils.PERSIST_PREFIX
+                + FeatureFlagUtils.SETTINGS_FUSE_FLAG), false);
+        Slog.d(TAG, "The value of Settings Fuse Flag is " + settingsFuseFlag);
+        if (SystemProperties.getBoolean(StorageManager.PROP_FUSE, false) != settingsFuseFlag) {
+            Slog.d(TAG, "Set persist.sys.fuse to " + settingsFuseFlag);
+            SystemProperties.set(StorageManager.PROP_FUSE, Boolean.toString(settingsFuseFlag));
+            // Perform hard reboot to kick policy into place
+            mContext.getSystemService(PowerManager.class).reboot("Reboot device for FUSE system"
+                    + "property change to take effect");
+        }
+    }
+
     private void start() {
         connectStoraged();
         connectVold();
@@ -1697,7 +1722,7 @@
                 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
                 UserHandle.getUserId(UserHandle.USER_SYSTEM));
         if (provider != null) {
-            mMediaStoreAuthorityPackageName = provider.packageName;
+            mMediaStoreAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid);
         }
 
         try {
@@ -1730,6 +1755,7 @@
     private void bootCompleted() {
         mBootCompleted = true;
         mHandler.obtainMessage(H_BOOT_COMPLETED).sendToTarget();
+        updateFusePropFromSettings();
     }
 
     private void handleBootCompleted() {
@@ -3724,8 +3750,10 @@
                 return Zygote.MOUNT_EXTERNAL_NONE;
             }
 
-            if (mIsFuseEnabled && packageName.equals(mMediaStoreAuthorityPackageName)) {
-                // Determine if caller requires pass_through mount
+            if (mIsFuseEnabled && mMediaStoreAuthorityAppId == UserHandle.getAppId(uid)) {
+                // Determine if caller requires pass_through mount; note that we do this for
+                // all processes that share a UID with MediaProvider; but this is fine, since
+                // those processes anyway share the same rights as MediaProvider.
                 return Zygote.MOUNT_EXTERNAL_PASS_THROUGH;
             }
 
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index dc61261..6105c74 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -17,6 +17,8 @@
 package com.android.server;
 
 import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED;
+import static android.telephony.TelephonyRegistryManager.SIM_ACTIVATION_TYPE_DATA;
+import static android.telephony.TelephonyRegistryManager.SIM_ACTIVATION_TYPE_VOICE;
 
 import static java.util.Arrays.copyOf;
 
@@ -38,6 +40,7 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.telephony.Annotation;
 import android.telephony.Annotation.DataFailureCause;
 import android.telephony.Annotation.RadioPowerState;
 import android.telephony.Annotation.SrvccState;
@@ -50,7 +53,6 @@
 import android.telephony.LocationAccessPolicy;
 import android.telephony.PhoneCapability;
 import android.telephony.PhoneStateListener;
-import android.telephony.PhysicalChannelConfig;
 import android.telephony.PreciseCallState;
 import android.telephony.PreciseDataConnectionState;
 import android.telephony.PreciseDisconnectCause;
@@ -70,7 +72,6 @@
 import com.android.internal.telephony.IOnSubscriptionsChangedListener;
 import com.android.internal.telephony.IPhoneStateListener;
 import com.android.internal.telephony.ITelephonyRegistry;
-import com.android.internal.telephony.PhoneConstantConversions;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.TelephonyPermissions;
@@ -213,8 +214,6 @@
 
     private ArrayList<List<CellInfo>> mCellInfo = null;
 
-    private ArrayList<List<PhysicalChannelConfig>> mPhysicalChannelConfigs;
-
     private Map<Integer, List<EmergencyNumber>> mEmergencyNumberList;
 
     private EmergencyNumber[] mOutgoingSmsEmergencyNumber;
@@ -424,7 +423,6 @@
         if (mNumPhones < oldNumPhones) {
             cutListToSize(mCellInfo, mNumPhones);
             cutListToSize(mImsReasonInfo, mNumPhones);
-            cutListToSize(mPhysicalChannelConfigs, mNumPhones);
             return;
         }
 
@@ -445,7 +443,6 @@
             mCellInfo.add(i, null);
             mImsReasonInfo.add(i, null);
             mSrvccState[i] = TelephonyManager.SRVCC_STATE_HANDOVER_NONE;
-            mPhysicalChannelConfigs.add(i, new ArrayList<>());
             mOtaspMode[i] = TelephonyManager.OTASP_UNKNOWN;
             mCallDisconnectCause[i] = DisconnectCause.NOT_VALID;
             mCallPreciseDisconnectCause[i] = PreciseDisconnectCause.NOT_VALID;
@@ -522,7 +519,6 @@
         mPreciseDataConnectionState = new PreciseDataConnectionState[numPhones];
         mCellInfo = new ArrayList<>();
         mImsReasonInfo = new ArrayList<>();
-        mPhysicalChannelConfigs = new ArrayList<>();
         mEmergencyNumberList = new HashMap<>();
         mOutgoingCallEmergencyNumber = new EmergencyNumber[numPhones];
         mOutgoingSmsEmergencyNumber = new EmergencyNumber[numPhones];
@@ -542,7 +538,6 @@
             mCellInfo.add(i, null);
             mImsReasonInfo.add(i, null);
             mSrvccState[i] = TelephonyManager.SRVCC_STATE_HANDOVER_NONE;
-            mPhysicalChannelConfigs.add(i, new ArrayList<>());
             mOtaspMode[i] = TelephonyManager.OTASP_UNKNOWN;
             mCallDisconnectCause[i] = DisconnectCause.NOT_VALID;
             mCallPreciseDisconnectCause[i] = PreciseDisconnectCause.NOT_VALID;
@@ -961,14 +956,6 @@
                             remove(r.binder);
                         }
                     }
-                    if ((events & PhoneStateListener.LISTEN_PHYSICAL_CHANNEL_CONFIGURATION) != 0) {
-                        try {
-                            r.callback.onPhysicalChannelConfigurationChanged(
-                                    mPhysicalChannelConfigs.get(phoneId));
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
-                    }
                     if ((events & PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST) != 0) {
                         try {
                             r.callback.onEmergencyNumberListChanged(mEmergencyNumberList);
@@ -1215,10 +1202,10 @@
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
                 switch (activationType) {
-                    case TelephonyManager.SIM_ACTIVATION_TYPE_VOICE:
+                    case SIM_ACTIVATION_TYPE_VOICE:
                         mVoiceActivationState[phoneId] = activationState;
                         break;
-                    case TelephonyManager.SIM_ACTIVATION_TYPE_DATA:
+                    case SIM_ACTIVATION_TYPE_DATA:
                         mDataActivationState[phoneId] = activationState;
                         break;
                     default:
@@ -1231,10 +1218,10 @@
                                 + " state=" + activationState);
                     }
                     try {
-                        if ((activationType == TelephonyManager.SIM_ACTIVATION_TYPE_VOICE) &&
-                                r.matchPhoneStateListenerEvent(
-                                        PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE) &&
-                                idMatch(r.subId, subId, phoneId)) {
+                        if ((activationType == SIM_ACTIVATION_TYPE_VOICE)
+                                && r.matchPhoneStateListenerEvent(
+                                        PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE)
+                                && idMatch(r.subId, subId, phoneId)) {
                             if (DBG) {
                                 log("notifyVoiceActivationStateForPhoneId: callback.onVASC r=" + r
                                         + " subId=" + subId + " phoneId=" + phoneId
@@ -1242,10 +1229,10 @@
                             }
                             r.callback.onVoiceActivationStateChanged(activationState);
                         }
-                        if ((activationType == TelephonyManager.SIM_ACTIVATION_TYPE_DATA) &&
-                                r.matchPhoneStateListenerEvent(
-                                        PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE) &&
-                                idMatch(r.subId, subId, phoneId)) {
+                        if ((activationType == SIM_ACTIVATION_TYPE_DATA)
+                                && r.matchPhoneStateListenerEvent(
+                                        PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE)
+                                && idMatch(r.subId, subId, phoneId)) {
                             if (DBG) {
                                 log("notifyDataActivationStateForPhoneId: callback.onDASC r=" + r
                                         + " subId=" + subId + " phoneId=" + phoneId
@@ -1393,43 +1380,6 @@
         }
     }
 
-    /**
-     * Notify physical channel configuration according to subscripton ID and phone ID
-     */
-    public void notifyPhysicalChannelConfigurationForSubscriber(int phoneId, int subId,
-            List<PhysicalChannelConfig> configs) {
-        if (!checkNotifyPermission("notifyPhysicalChannelConfiguration()")) {
-            return;
-        }
-
-        if (VDBG) {
-            log("notifyPhysicalChannelConfiguration: subId=" + subId + " phoneId=" + phoneId
-                    + " configs=" + configs);
-        }
-
-        synchronized (mRecords) {
-            if (validatePhoneId(phoneId)) {
-                mPhysicalChannelConfigs.set(phoneId, configs);
-                for (Record r : mRecords) {
-                    if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_PHYSICAL_CHANNEL_CONFIGURATION)
-                            && idMatch(r.subId, subId, phoneId)) {
-                        try {
-                            if (DBG_LOC) {
-                                log("notifyPhysicalChannelConfiguration: mPhysicalChannelConfigs="
-                                        + configs + " r=" + r);
-                            }
-                            r.callback.onPhysicalChannelConfigurationChanged(configs);
-                        } catch (RemoteException ex) {
-                            mRemoveList.add(r.binder);
-                        }
-                    }
-                }
-            }
-            handleRemoveListLocked();
-        }
-    }
-
     @Override
     public void notifyMessageWaitingChangedForPhoneId(int phoneId, int subId, boolean mwi) {
         if (!checkNotifyPermission("notifyMessageWaitingChanged()")) {
@@ -1576,8 +1526,8 @@
                         && (mDataConnectionState[phoneId] != state
                         || mDataConnectionNetworkType[phoneId] != networkType)) {
                     String str = "onDataConnectionStateChanged("
-                            + TelephonyManager.dataStateToString(state)
-                            + ", " + TelephonyManager.getNetworkTypeName(networkType)
+                            + dataStateToString(state)
+                            + ", " + getNetworkTypeName(networkType)
                             + ") subId=" + subId + ", phoneId=" + phoneId;
                     log(str);
                     mLocalLog.log(str);
@@ -2264,8 +2214,7 @@
         }
 
         Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
-        intent.putExtra(PhoneConstants.STATE_KEY,
-                PhoneConstantConversions.convertCallState(state).toString());
+        intent.putExtra(TelephonyManager.EXTRA_STATE, callStateToString(state));
 
         // If a valid subId was specified, we should fire off a subId-specific state
         // change intent and include the subId.
@@ -2298,6 +2247,18 @@
                         android.Manifest.permission.READ_CALL_LOG});
     }
 
+    /** Converts TelephonyManager#CALL_STATE_* to TelephonyManager#EXTRA_STATE_*. */
+    private static String callStateToString(int callState) {
+        switch (callState) {
+            case TelephonyManager.CALL_STATE_RINGING:
+                return TelephonyManager.EXTRA_STATE_RINGING;
+            case TelephonyManager.CALL_STATE_OFFHOOK:
+                return TelephonyManager.EXTRA_STATE_OFFHOOK;
+            default:
+                return TelephonyManager.EXTRA_STATE_IDLE;
+        }
+    }
+
     private void broadcastDataConnectionStateChanged(int state, boolean isDataAllowed, String apn,
                                                      String apnType, LinkProperties linkProperties,
                                                      NetworkCapabilities networkCapabilities,
@@ -2306,8 +2267,7 @@
         // status bar takes care of that after taking into account all of the
         // required info.
         Intent intent = new Intent(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
-        intent.putExtra(PhoneConstants.STATE_KEY,
-                PhoneConstantConversions.convertDataState(state).toString());
+        intent.putExtra(TelephonyManager.EXTRA_STATE, dataStateToString(state));
         if (!isDataAllowed) {
             intent.putExtra(PhoneConstants.NETWORK_UNAVAILABLE_KEY, true);
         }
@@ -2350,7 +2310,7 @@
             String apnType, String apn, LinkProperties linkProperties,
             @DataFailureCause int failCause) {
         Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED);
-        intent.putExtra(PhoneConstants.STATE_KEY, state);
+        intent.putExtra(TelephonyManager.EXTRA_STATE, state);
         intent.putExtra(PhoneConstants.DATA_NETWORK_TYPE_KEY, networkType);
         if (apnType != null) intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
         if (apn != null) intent.putExtra(PhoneConstants.DATA_APN_KEY, apn);
@@ -2689,4 +2649,74 @@
             }
         }
     }
+
+    /**
+     * Convert TelephonyManager.DATA_* to string.
+     *
+     * @return The data state in string format.
+     */
+    private static String dataStateToString(int state) {
+        switch (state) {
+            case TelephonyManager.DATA_DISCONNECTED: return "DISCONNECTED";
+            case TelephonyManager.DATA_CONNECTING: return "CONNECTING";
+            case TelephonyManager.DATA_CONNECTED: return "CONNECTED";
+            case TelephonyManager.DATA_SUSPENDED: return "SUSPENDED";
+        }
+        return "UNKNOWN(" + state + ")";
+    }
+
+    /**
+     * Returns a string representation of the radio technology (network type)
+     * currently in use on the device.
+     * @param subId for which network type is returned
+     * @return the name of the radio technology
+     *
+     */
+    private String getNetworkTypeName(@Annotation.NetworkType int type) {
+        switch (type) {
+            case TelephonyManager.NETWORK_TYPE_GPRS:
+                return "GPRS";
+            case TelephonyManager.NETWORK_TYPE_EDGE:
+                return "EDGE";
+            case TelephonyManager.NETWORK_TYPE_UMTS:
+                return "UMTS";
+            case TelephonyManager.NETWORK_TYPE_HSDPA:
+                return "HSDPA";
+            case TelephonyManager.NETWORK_TYPE_HSUPA:
+                return "HSUPA";
+            case TelephonyManager.NETWORK_TYPE_HSPA:
+                return "HSPA";
+            case TelephonyManager.NETWORK_TYPE_CDMA:
+                return "CDMA";
+            case TelephonyManager.NETWORK_TYPE_EVDO_0:
+                return "CDMA - EvDo rev. 0";
+            case TelephonyManager.NETWORK_TYPE_EVDO_A:
+                return "CDMA - EvDo rev. A";
+            case TelephonyManager.NETWORK_TYPE_EVDO_B:
+                return "CDMA - EvDo rev. B";
+            case TelephonyManager.NETWORK_TYPE_1xRTT:
+                return "CDMA - 1xRTT";
+            case TelephonyManager.NETWORK_TYPE_LTE:
+                return "LTE";
+            case TelephonyManager.NETWORK_TYPE_EHRPD:
+                return "CDMA - eHRPD";
+            case TelephonyManager.NETWORK_TYPE_IDEN:
+                return "iDEN";
+            case TelephonyManager.NETWORK_TYPE_HSPAP:
+                return "HSPA+";
+            case TelephonyManager.NETWORK_TYPE_GSM:
+                return "GSM";
+            case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
+                return "TD_SCDMA";
+            case TelephonyManager.NETWORK_TYPE_IWLAN:
+                return "IWLAN";
+            case TelephonyManager.NETWORK_TYPE_LTE_CA:
+                return "LTE_CA";
+            case TelephonyManager.NETWORK_TYPE_NR:
+                return "NR";
+            default:
+                return "UNKNOWN";
+        }
+    }
+
 }
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index b570254..b1e2c0f 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -866,14 +866,13 @@
         if (!mHoldingConfiguration) {
             mConfiguration.uiMode = uiMode;
         }
-        // load splash screen instead of screenshot
-        mWindowManager.clearSnapshotCache();
     }
 
     private void sendConfigurationLocked() {
         if (mSetUiMode != mConfiguration.uiMode) {
             mSetUiMode = mConfiguration.uiMode;
-
+            // load splash screen instead of screenshot
+            mWindowManager.clearSnapshotCache();
             try {
                 ActivityTaskManager.getService().updateConfiguration(mConfiguration);
             } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/ZramWriteback.java b/services/core/java/com/android/server/ZramWriteback.java
index 49bf29b..5d97def 100644
--- a/services/core/java/com/android/server/ZramWriteback.java
+++ b/services/core/java/com/android/server/ZramWriteback.java
@@ -60,6 +60,7 @@
     private static final String MARK_IDLE_DELAY_PROP = "ro.zram.mark_idle_delay_mins";
     private static final String FIRST_WB_DELAY_PROP = "ro.zram.first_wb_delay_mins";
     private static final String PERIODIC_WB_DELAY_PROP = "ro.zram.periodic_wb_delay_hours";
+    private static final String FORCE_WRITEBACK_PROP = "zram.force_writeback";
 
     private void markPagesAsIdle() {
         String idlePath = String.format(IDLE_SYS, sZramDeviceId);
@@ -122,11 +123,12 @@
 
     private static void schedNextWriteback(Context context) {
         int nextWbDelay = SystemProperties.getInt(PERIODIC_WB_DELAY_PROP, 24);
+        boolean forceWb = SystemProperties.getBoolean(FORCE_WRITEBACK_PROP, false);
         JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
 
         js.schedule(new JobInfo.Builder(WRITEBACK_IDLE_JOB_ID, sZramWriteback)
                         .setMinimumLatency(TimeUnit.HOURS.toMillis(nextWbDelay))
-                        .setRequiresDeviceIdle(true)
+                        .setRequiresDeviceIdle(!forceWb)
                         .build());
     }
 
@@ -167,6 +169,7 @@
     public static void scheduleZramWriteback(Context context) {
         int markIdleDelay = SystemProperties.getInt(MARK_IDLE_DELAY_PROP, 20);
         int firstWbDelay = SystemProperties.getInt(FIRST_WB_DELAY_PROP, 180);
+        boolean forceWb = SystemProperties.getBoolean(FORCE_WRITEBACK_PROP, false);
 
         JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
 
@@ -182,7 +185,7 @@
         // by ro.zram.periodic_wb_delay_hours.
         js.schedule(new JobInfo.Builder(WRITEBACK_IDLE_JOB_ID, sZramWriteback)
                         .setMinimumLatency(TimeUnit.MINUTES.toMillis(firstWbDelay))
-                        .setRequiresDeviceIdle(true)
+                        .setRequiresDeviceIdle(!forceWb)
                         .build());
     }
 }
diff --git a/services/core/java/com/android/server/am/ActiveInstrumentation.java b/services/core/java/com/android/server/am/ActiveInstrumentation.java
index 9510f59..b2c82f0 100644
--- a/services/core/java/com/android/server/am/ActiveInstrumentation.java
+++ b/services/core/java/com/android/server/am/ActiveInstrumentation.java
@@ -126,26 +126,26 @@
         pw.println(mArguments);
     }
 
-    void writeToProto(ProtoOutputStream proto, long fieldId) {
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
         long token = proto.start(fieldId);
-        mClass.writeToProto(proto, ActiveInstrumentationProto.CLASS);
+        mClass.dumpDebug(proto, ActiveInstrumentationProto.CLASS);
         proto.write(ActiveInstrumentationProto.FINISHED, mFinished);
         for (int i=0; i<mRunningProcesses.size(); i++) {
-            mRunningProcesses.get(i).writeToProto(proto,
+            mRunningProcesses.get(i).dumpDebug(proto,
                     ActiveInstrumentationProto.RUNNING_PROCESSES);
         }
         for (String p : mTargetProcesses) {
             proto.write(ActiveInstrumentationProto.TARGET_PROCESSES, p);
         }
         if (mTargetInfo != null) {
-            mTargetInfo.writeToProto(proto, ActiveInstrumentationProto.TARGET_INFO, 0);
+            mTargetInfo.dumpDebug(proto, ActiveInstrumentationProto.TARGET_INFO, 0);
         }
         proto.write(ActiveInstrumentationProto.PROFILE_FILE, mProfileFile);
         proto.write(ActiveInstrumentationProto.WATCHER, mWatcher.toString());
         proto.write(ActiveInstrumentationProto.UI_AUTOMATION_CONNECTION,
                 mUiAutomationConnection.toString());
         if (mArguments != null) {
-            mArguments.writeToProto(proto, ActiveInstrumentationProto.ARGUMENTS);
+            mArguments.dumpDebug(proto, ActiveInstrumentationProto.ARGUMENTS);
         }
         proto.end(token);
     }
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index eb77fea..dab928a 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -4407,7 +4407,7 @@
         return new ServiceDumper(fd, pw, args, opti, dumpAll, dumpPackage);
     }
 
-    protected void writeToProto(ProtoOutputStream proto, long fieldId) {
+    protected void dumpDebug(ProtoOutputStream proto, long fieldId) {
         synchronized (mAm) {
             final long outterToken = proto.start(fieldId);
             int[] users = mAm.mUserController.getUsers();
@@ -4420,7 +4420,7 @@
                 proto.write(ActiveServicesProto.ServicesByUser.USER_ID, user);
                 ArrayMap<ComponentName, ServiceRecord> alls = smap.mServicesByInstanceName;
                 for (int i=0; i<alls.size(); i++) {
-                    alls.valueAt(i).writeToProto(proto,
+                    alls.valueAt(i).dumpDebug(proto,
                             ActiveServicesProto.ServicesByUser.SERVICE_RECORDS);
                 }
                 proto.end(token);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 770db58..01f3c26 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -568,11 +568,6 @@
     private static final int NATIVE_DUMP_TIMEOUT_MS = 2000; // 2 seconds;
     private static final int JAVA_DUMP_MINIMUM_SIZE = 100; // 100 bytes.
 
-    /**
-     * How long between a process kill and we actually receive its death recipient
-     */
-    private static final long PROC_KILL_TIMEOUT = 5000; // 5 seconds;
-
     OomAdjuster mOomAdjuster;
     final LowMemDetector mLowMemDetector;
 
@@ -858,7 +853,7 @@
                     + " " + reason + " " + pid + " " + token + " }";
         }
 
-        void writeToProto(ProtoOutputStream proto, long fieldId) {
+        void dumpDebug(ProtoOutputStream proto, long fieldId) {
             final long pToken = proto.start(fieldId);
             proto.write(ImportanceTokenProto.PID, pid);
             if (token != null) {
@@ -1192,7 +1187,7 @@
             tag = _tag;
         }
 
-        void writeToProto(ProtoOutputStream proto, long fieldId) {
+        void dumpDebug(ProtoOutputStream proto, long fieldId) {
             final long token = proto.start(fieldId);
             proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.TARGET_UID, targetUid);
             proto.write(ActivityManagerServiceDumpProcessesProto.PendingTempWhitelist.DURATION_MS, duration);
@@ -1436,7 +1431,7 @@
             }
         }
 
-        void writeToProto(ProtoOutputStream proto, long fieldId) {
+        void dumpDebug(ProtoOutputStream proto, long fieldId) {
             final long token = proto.start(fieldId);
             proto.write(UidObserverRegistrationProto.UID, uid);
             proto.write(UidObserverRegistrationProto.PACKAGE, pkg);
@@ -2786,8 +2781,8 @@
                         int total = user + system + iowait + irq + softIrq + idle;
                         if (total == 0) total = 1;
 
-                        EventLog.writeEvent(EventLogTags.CPU,
-                                ((user+system+iowait+irq+softIrq) * 100) / total,
+                        EventLogTags.writeCpu(
+                                ((user + system + iowait + irq + softIrq) * 100) / total,
                                 (user * 100) / total,
                                 (system * 100) / total,
                                 (iowait * 100) / total,
@@ -3656,7 +3651,7 @@
             final ArrayList<ProcessMemInfo> memInfos
                     = doReport ? new ArrayList<ProcessMemInfo>(mProcessList.getLruSizeLocked())
                     : null;
-            EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mProcessList.getLruSizeLocked());
+            EventLogTags.writeAmLowMemory(mProcessList.getLruSizeLocked());
             long now = SystemClock.uptimeMillis();
             for (int i = mProcessList.mLruProcesses.size() - 1; i >= 0; i--) {
                 ProcessRecord rec = mProcessList.mLruProcesses.get(i);
@@ -3737,15 +3732,12 @@
                 mAllowLowerMemLevel = false;
                 doLowMem = false;
             }
-            EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName,
-                    app.setAdj, app.setProcState);
+            EventLogTags.writeAmProcDied(app.userId, app.pid, app.processName, app.setAdj,
+                    app.setProcState);
             if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
                 "Dying app: " + app + ", pid: " + pid + ", thread: " + thread.asBinder());
             handleAppDiedLocked(app, false, true);
 
-            // Execute the callback if there is any.
-            doAppDiedCallbackLocked(app);
-
             if (doOomAdj) {
                 updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_END);
             }
@@ -3758,10 +3750,8 @@
                     "Process " + app.processName + " (pid " + pid
                             + ") has died and restarted (pid " + app.pid + ").", app.info.uid);
 
-            // Execute the callback if there is any.
-            doAppDiedCallbackLocked(app);
-
-            EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName);
+            EventLogTags.writeAmProcDied(app.userId, app.pid, app.processName, app.setAdj,
+                    app.setProcState);
         } else if (DEBUG_PROCESSES) {
             Slog.d(TAG_PROCESSES, "Received spurious death notification for thread "
                     + thread.asBinder());
@@ -3774,39 +3764,6 @@
         }
     }
 
-    @GuardedBy("this")
-    private void doAppDiedCallbackLocked(final ProcessRecord app) {
-        if (app.mAppDiedCallback != null) {
-            app.mAppDiedCallback.run();
-            app.mAppDiedCallback = null;
-        }
-    }
-
-    @GuardedBy("this")
-    private void waitForProcKillLocked(final ProcessRecord app, final String formatString,
-            final long startTime) {
-        app.mAppDiedCallback = () -> {
-            synchronized (ActivityManagerService.this) {
-                // called when this app receives appDiedLocked()
-                ActivityManagerService.this.notifyAll();
-            }
-        };
-        checkTime(startTime, String.format(formatString, "before appDied"));
-        long now = SystemClock.uptimeMillis();
-        long timeout = PROC_KILL_TIMEOUT + now;
-        while (app.mAppDiedCallback != null && timeout > now) {
-            try {
-                wait(timeout - now);
-            } catch (InterruptedException e) {
-            }
-            now = SystemClock.uptimeMillis();
-        }
-        checkTime(startTime, String.format(formatString, "after appDied"));
-        if (app.mAppDiedCallback != null) {
-            Slog.w(TAG, String.format(formatString, "waiting for app killing timed out"));
-        }
-    }
-
     /**
      * If a stack trace dump file is configured, dump process stack traces.
      * @param firstPids of dalvik VM processes to dump stack traces for first
@@ -4755,8 +4712,7 @@
 
         if (gone) {
             Slog.w(TAG, "Process " + app + " failed to attach");
-            EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, app.userId,
-                    pid, app.uid, app.processName);
+            EventLogTags.writeAmProcessStartTimeout(app.userId, pid, app.uid, app.processName);
             mProcessList.removeProcessNameLocked(app.processName, app.uid);
             mAtmInternal.clearHeavyWeightProcessIfEquals(app.getWindowProcessController());
             mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
@@ -4847,7 +4803,7 @@
         if (app == null) {
             Slog.w(TAG, "No pending application record for pid " + pid
                     + " (IApplicationThread " + thread + "); dropping process");
-            EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
+            EventLogTags.writeAmDropProcess(pid);
             if (pid > 0 && pid != MY_PID) {
                 killProcessQuiet(pid);
                 //TODO: killProcessGroup(app.info.uid, pid);
@@ -4885,7 +4841,7 @@
             return false;
         }
 
-        EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);
+        EventLogTags.writeAmProcBound(app.userId, app.pid, app.processName);
 
         app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
         mOomAdjuster.setAttachingSchedGroupLocked(app);
@@ -6738,7 +6694,7 @@
 
     private final long[] mProcessStateStatsLongs = new long[1];
 
-    private boolean isProcessAliveLocked(ProcessRecord proc) {
+    boolean isProcessAliveLocked(ProcessRecord proc) {
         if (proc.pid <= 0) {
             if (DEBUG_OOM_ADJ) Slog.d(TAG, "Process hasn't started yet: " + proc);
             return false;
@@ -6755,7 +6711,10 @@
         final long state = mProcessStateStatsLongs[0];
         if (DEBUG_OOM_ADJ) Slog.d(TAG, "RETRIEVED STATE FOR " + proc.procStatFile + ": "
                 + (char)state);
-        return state != 'Z' && state != 'X' && state != 'x' && state != 'K';
+        if (state != 'Z' && state != 'X' && state != 'x' && state != 'K') {
+            return Process.getUidForPid(proc.pid) == proc.uid;
+        }
+        return false;
     }
 
     private String checkContentProviderAssociation(ProcessRecord callingApp, int callingUid,
@@ -6824,12 +6783,18 @@
 
                 // Note if killedByAm is also set, this means the provider process has just been
                 // killed by AM (in ProcessRecord.kill()), but appDiedLocked() hasn't been called
-                // yet. So we need to wait for appDiedLocked() here and let it clean up.
+                // yet. So we need to call appDiedLocked() here and let it clean up.
                 // (See the commit message on I2c4ba1e87c2d47f2013befff10c49b3dc337a9a7 to see
                 // how to test this case.)
                 if (cpr.proc.killed && cpr.proc.killedByAm) {
-                    waitForProcKillLocked(cpr.proc, "getContentProviderImpl: %s (killedByAm)",
-                            startTime);
+                    final long iden = Binder.clearCallingIdentity();
+                    try {
+                        mProcessList.killProcAndWaitIfNecessaryLocked(cpr.proc, false,
+                                cpr.uid == cpr.proc.uid || cpr.proc.isolated,
+                                "getContentProviderImpl: %s (killedByAm)", startTime);
+                    } finally {
+                        Binder.restoreCallingIdentity(iden);
+                    }
                 }
             }
 
@@ -6933,7 +6898,8 @@
                     Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString()
                             + " is crashing; detaching " + r);
                     boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
-                    waitForProcKillLocked(cpr.proc, "getContentProviderImpl: %s", startTime);
+                    mProcessList.killProcAndWaitIfNecessaryLocked(cpr.proc,
+                            false, true, "getContentProviderImpl: %s", startTime);
                     if (!lastRef) {
                         // This wasn't the last ref our process had on
                         // the provider...  we have now been killed, bail.
@@ -7163,7 +7129,7 @@
                             + cpi.applicationInfo.packageName + "/"
                             + cpi.applicationInfo.uid + " for provider "
                             + name + ": launching app became null");
-                    EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,
+                    EventLogTags.writeAmProviderLostProcess(
                             UserHandle.getUserId(cpi.applicationInfo.uid),
                             cpi.applicationInfo.packageName,
                             cpi.applicationInfo.uid, name);
@@ -8401,6 +8367,31 @@
         requestBugReportWithDescription(null, null, BugreportParams.BUGREPORT_MODE_REMOTE);
     }
 
+    /**
+     * Launches a bugreport-whitelisted app to handle a bugreport.
+     *
+     * <p>Allows a bug report handler app to take bugreports on the user's behalf. The handler can
+     * be predefined in the config, meant to be launched with the primary user. The user can
+     * override this with a different (or same) handler app on possibly a different user. This is
+     * useful for capturing bug reports from work profile, for instance.
+     *
+     * @return true if there is a bugreport-whitelisted app to handle a bugreport, or false
+     * otherwise.
+     */
+    @Override
+    public boolean launchBugReportHandlerApp() {
+        if (!BugReportHandlerUtil.isBugReportHandlerEnabled(mContext)) {
+            return false;
+        }
+
+        // Always log caller, even if it does not have permission to dump.
+        Slog.i(TAG, "launchBugReportHandlerApp requested by UID " + Binder.getCallingUid());
+        enforceCallingPermission(android.Manifest.permission.DUMP,
+                "launchBugReportHandlerApp");
+
+        return BugReportHandlerUtil.launchBugReportHandlerApp(mContext);
+    }
+
     public void registerProcessObserver(IProcessObserver observer) {
         enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
                 "registerProcessObserver()");
@@ -9156,7 +9147,8 @@
         t.traceEnd(); // KillProcesses
 
         Slog.i(TAG, "System now ready");
-        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY, SystemClock.uptimeMillis());
+
+        EventLogTags.writeBootProgressAmsReady(SystemClock.uptimeMillis());
 
         t.traceBegin("updateTopComponentForFactoryTest");
         mAtmInternal.updateTopComponentForFactoryTest();
@@ -9410,7 +9402,8 @@
      */
     void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
             ApplicationErrorReport.CrashInfo crashInfo) {
-        EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
+
+        EventLogTags.writeAmCrash(Binder.getCallingPid(),
                 UserHandle.getUserId(Binder.getCallingUid()), processName,
                 r == null ? -1 : r.info.flags,
                 crashInfo.exceptionClassName,
@@ -9613,7 +9606,7 @@
         final String processName = app == null ? "system_server"
                 : (r == null ? "unknown" : r.processName);
 
-        EventLog.writeEvent(EventLogTags.AM_WTF, UserHandle.getUserId(callingUid), callingPid,
+        EventLogTags.writeAmWtf(UserHandle.getUserId(callingUid), callingPid,
                 processName, r == null ? -1 : r.info.flags, tag, crashInfo.exceptionMessage);
 
         StatsLog.write(StatsLog.WTF_OCCURRED, callingUid, tag, processName,
@@ -10211,7 +10204,7 @@
                 }
             } else if ("service".equals(cmd)) {
                 // output proto is ActivityManagerServiceDumpServicesProto
-                mServices.writeToProto(proto, ActivityManagerServiceDumpServicesProto.ACTIVE_SERVICES);
+                mServices.dumpDebug(proto, ActivityManagerServiceDumpServicesProto.ACTIVE_SERVICES);
             } else if ("processes".equals(cmd) || "p".equals(cmd)) {
                 if (opti < args.length) {
                     dumpPackage = args[opti];
@@ -10233,7 +10226,7 @@
                     proto.end(broadcastToken);
 
                     long serviceToken = proto.start(ActivityManagerServiceProto.SERVICES);
-                    mServices.writeToProto(proto,
+                    mServices.dumpDebug(proto,
                             ActivityManagerServiceDumpServicesProto.ACTIVE_SERVICES);
                     proto.end(serviceToken);
 
@@ -11114,7 +11107,7 @@
                 if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
                     continue;
                 }
-                r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PROCS,
+                r.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.PROCS,
                         mProcessList.mLruProcesses.indexOf(r)
                 );
                 if (r.isPersistent()) {
@@ -11128,7 +11121,7 @@
             if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
                 continue;
             }
-            r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.ISOLATED_PROCS,
+            r.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.ISOLATED_PROCS,
                     mProcessList.mLruProcesses.indexOf(r)
             );
         }
@@ -11139,7 +11132,7 @@
                     && !ai.mTargetInfo.packageName.equals(dumpPackage)) {
                 continue;
             }
-            ai.writeToProto(proto,
+            ai.dumpDebug(proto,
                     ActivityManagerServiceDumpProcessesProto.ACTIVE_INSTRUMENTATIONS);
         }
 
@@ -11149,7 +11142,7 @@
             if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != whichAppId) {
                 continue;
             }
-            uidRec.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.ACTIVE_UIDS);
+            uidRec.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.ACTIVE_UIDS);
         }
 
         for (int i = 0; i < mValidateUids.size(); i++) {
@@ -11157,7 +11150,7 @@
             if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != whichAppId) {
                 continue;
             }
-            uidRec.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.VALIDATE_UIDS);
+            uidRec.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.VALIDATE_UIDS);
         }
 
         if (mProcessList.getLruSizeLocked() > 0) {
@@ -11181,7 +11174,7 @@
                     if (!r.pkgList.containsKey(dumpPackage)) {
                         continue;
                     }
-                    r.writeToProto(proto,
+                    r.dumpDebug(proto,
                             ActivityManagerServiceDumpProcessesProto.PIDS_SELF_LOCKED);
                 }
             }
@@ -11196,7 +11189,7 @@
                             || !r.pkgList.containsKey(dumpPackage))) {
                         continue;
                     }
-                    it.writeToProto(proto,
+                    it.dumpDebug(proto,
                             ActivityManagerServiceDumpProcessesProto.IMPORTANT_PROCS);
                 }
             }
@@ -11207,7 +11200,7 @@
             if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
                 continue;
             }
-            r.writeToProto(proto,
+            r.dumpDebug(proto,
                     ActivityManagerServiceDumpProcessesProto.PERSISTENT_STARTING_PROCS);
         }
 
@@ -11216,7 +11209,7 @@
             if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
                 continue;
             }
-            r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.REMOVED_PROCS);
+            r.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.REMOVED_PROCS);
         }
 
         for (int i=0; i<mProcessesOnHold.size(); i++) {
@@ -11224,17 +11217,17 @@
             if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
                 continue;
             }
-            r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.ON_HOLD_PROCS);
+            r.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.ON_HOLD_PROCS);
         }
 
         writeProcessesToGcToProto(proto, ActivityManagerServiceDumpProcessesProto.GC_PROCS,
                 dumpPackage);
-        mAppErrors.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.APP_ERRORS,
+        mAppErrors.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.APP_ERRORS,
                 dumpPackage);
         mAtmInternal.writeProcessesToProto(proto, dumpPackage, mWakefulness, mTestPssMode);
 
         if (dumpPackage == null) {
-            mUserController.writeToProto(proto,
+            mUserController.dumpDebug(proto,
             ActivityManagerServiceDumpProcessesProto.USER_CONTROLLER);
         }
 
@@ -11243,7 +11236,7 @@
             final UidObserverRegistration reg = (UidObserverRegistration)
                     mUidObservers.getRegisteredCallbackCookie(i);
             if (dumpPackage == null || dumpPackage.equals(reg.pkg)) {
-                reg.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.UID_OBSERVERS);
+                reg.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.UID_OBSERVERS);
             }
         }
 
@@ -11257,7 +11250,7 @@
 
         if (mPendingTempWhitelist.size() > 0) {
             for (int i=0; i < mPendingTempWhitelist.size(); i++) {
-                mPendingTempWhitelist.valueAt(i).writeToProto(proto,
+                mPendingTempWhitelist.valueAt(i).dumpDebug(proto,
                         ActivityManagerServiceDumpProcessesProto.PENDING_TEMP_WHITELIST);
             }
         }
@@ -11327,10 +11320,10 @@
                 final long token = proto.start(ActivityManagerServiceDumpProcessesProto.PROFILE);
                 proto.write(ActivityManagerServiceDumpProcessesProto.Profile.APP_NAME,
                         mProfileData.getProfileApp());
-                mProfileData.getProfileProc().writeToProto(proto,
+                mProfileData.getProfileProc().dumpDebug(proto,
                         ActivityManagerServiceDumpProcessesProto.Profile.PROC);
                 if (mProfileData.getProfilerInfo() != null) {
-                    mProfileData.getProfilerInfo().writeToProto(proto,
+                    mProfileData.getProfilerInfo().dumpDebug(proto,
                             ActivityManagerServiceDumpProcessesProto.Profile.INFO);
                     proto.write(ActivityManagerServiceDumpProcessesProto.Profile.TYPE,
                             mProfileType);
@@ -11373,7 +11366,7 @@
                     continue;
                 }
                 final long token = proto.start(fieldId);
-                r.writeToProto(proto, ProcessToGcProto.PROC);
+                r.dumpDebug(proto, ProcessToGcProto.PROC);
                 proto.write(ProcessToGcProto.REPORT_LOW_MEMORY, r.reportLowMemory);
                 proto.write(ProcessToGcProto.NOW_UPTIME_MS, now);
                 proto.write(ProcessToGcProto.LAST_GCED_MS, r.lastRequestedGc);
@@ -11612,12 +11605,12 @@
             Iterator it = mRegisteredReceivers.values().iterator();
             while (it.hasNext()) {
                 ReceiverList r = (ReceiverList)it.next();
-                r.writeToProto(proto, ActivityManagerServiceDumpBroadcastsProto.RECEIVER_LIST);
+                r.dumpDebug(proto, ActivityManagerServiceDumpBroadcastsProto.RECEIVER_LIST);
             }
         }
-        mReceiverResolver.writeToProto(proto, ActivityManagerServiceDumpBroadcastsProto.RECEIVER_RESOLVER);
+        mReceiverResolver.dumpDebug(proto, ActivityManagerServiceDumpBroadcastsProto.RECEIVER_RESOLVER);
         for (BroadcastQueue q : mBroadcastQueues) {
-            q.writeToProto(proto, ActivityManagerServiceDumpBroadcastsProto.BROADCAST_QUEUE);
+            q.dumpDebug(proto, ActivityManagerServiceDumpBroadcastsProto.BROADCAST_QUEUE);
         }
         for (int user=0; user<mStickyBroadcasts.size(); user++) {
             long token = proto.start(ActivityManagerServiceDumpBroadcastsProto.STICKY_BROADCASTS);
@@ -11627,7 +11620,7 @@
                 long actionToken = proto.start(StickyBroadcastProto.ACTIONS);
                 proto.write(StickyBroadcastProto.StickyAction.NAME, ent.getKey());
                 for (Intent intent : ent.getValue()) {
-                    intent.writeToProto(proto, StickyBroadcastProto.StickyAction.INTENTS,
+                    intent.dumpDebug(proto, StickyBroadcastProto.StickyAction.INTENTS,
                             false, true, true, false);
                 }
                 proto.end(actionToken);
@@ -11637,7 +11630,7 @@
 
         long handlerToken = proto.start(ActivityManagerServiceDumpBroadcastsProto.HANDLER);
         proto.write(ActivityManagerServiceDumpBroadcastsProto.MainHandler.HANDLER, mHandler.toString());
-        mHandler.getLooper().writeToProto(proto,
+        mHandler.getLooper().dumpDebug(proto,
             ActivityManagerServiceDumpBroadcastsProto.MainHandler.LOOPER);
         proto.end(handlerToken);
     }
@@ -11979,18 +11972,18 @@
             proto.write(ProcessOomProto.STATE,
                     ProcessList.makeProcStateProtoEnum(r.getCurProcState()));
             proto.write(ProcessOomProto.TRIM_MEMORY_LEVEL, r.trimMemoryLevel);
-            r.writeToProto(proto, ProcessOomProto.PROC);
+            r.dumpDebug(proto, ProcessOomProto.PROC);
             proto.write(ProcessOomProto.ADJ_TYPE, r.adjType);
             if (r.adjSource != null || r.adjTarget != null) {
                 if (r.adjTarget instanceof  ComponentName) {
                     ComponentName cn = (ComponentName) r.adjTarget;
-                    cn.writeToProto(proto, ProcessOomProto.ADJ_TARGET_COMPONENT_NAME);
+                    cn.dumpDebug(proto, ProcessOomProto.ADJ_TARGET_COMPONENT_NAME);
                 } else if (r.adjTarget != null) {
                     proto.write(ProcessOomProto.ADJ_TARGET_OBJECT, r.adjTarget.toString());
                 }
                 if (r.adjSource instanceof ProcessRecord) {
                     ProcessRecord p = (ProcessRecord) r.adjSource;
-                    p.writeToProto(proto, ProcessOomProto.ADJ_SOURCE_PROC);
+                    p.dumpDebug(proto, ProcessOomProto.ADJ_SOURCE_PROC);
                 } else if (r.adjSource != null) {
                     proto.write(ProcessOomProto.ADJ_SOURCE_OBJECT, r.adjSource.toString());
                 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 908ec6b..7f1d5a3 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -3065,7 +3065,7 @@
             pw.println("          even if in the background.");
             pw.println("  instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]");
             pw.println("          [--user <USER_ID> | current]");
-            pw.println("          [--no-hidden-api-checks [--no-test-api-checks]]");
+            pw.println("          [--no-hidden-api-checks [--no-test-api-access]]");
             pw.println("          [--no-isolated-storage]");
             pw.println("          [--no-window-animation] [--abi <ABI>] <COMPONENT>");
             pw.println("      Start an Instrumentation.  Typically this target <COMPONENT> is in the");
@@ -3085,7 +3085,7 @@
             pw.println("      --user <USER_ID> | current: Specify user instrumentation runs in;");
             pw.println("          current user if not specified.");
             pw.println("      --no-hidden-api-checks: disable restrictions on use of hidden API.");
-            pw.println("      --no-test-api-checks: disable restrictions to test APIs, if hidden");
+            pw.println("      --no-test-api-access: do not allow access to test APIs, if hidden");
             pw.println("          API checks are enabled.");
             pw.println("      --no-isolated-storage: don't use isolated storage sandbox and ");
             pw.println("          mount full external storage");
diff --git a/services/core/java/com/android/server/am/AppBindRecord.java b/services/core/java/com/android/server/am/AppBindRecord.java
index 9870420..28756a4 100644
--- a/services/core/java/com/android/server/am/AppBindRecord.java
+++ b/services/core/java/com/android/server/am/AppBindRecord.java
@@ -62,7 +62,7 @@
             + " " + service.shortInstanceName + ":" + client.processName + "}";
     }
 
-    void writeToProto(ProtoOutputStream proto, long fieldId) {
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
         long token = proto.start(fieldId);
         proto.write(AppBindRecordProto.SERVICE_NAME, service.shortInstanceName);
         proto.write(AppBindRecordProto.CLIENT_PROC_NAME, client.processName);
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 8095020..83a7341 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -106,7 +106,7 @@
         mPackageWatchdog = watchdog;
     }
 
-    void writeToProto(ProtoOutputStream proto, long fieldId, String dumpPackage) {
+    void dumpDebug(ProtoOutputStream proto, long fieldId, String dumpPackage) {
         if (mProcessCrashTimes.getMap().isEmpty() && mBadProcesses.getMap().isEmpty()) {
             return;
         }
@@ -446,7 +446,8 @@
                 RescueParty.noteAppCrash(mContext, r.uid);
             }
 
-            mPackageWatchdog.onPackageFailure(r.getPackageListWithVersionCode());
+            mPackageWatchdog.onPackageFailure(r.getPackageListWithVersionCode(),
+                    PackageWatchdog.FAILURE_REASON_APP_CRASH);
         }
 
         final int relaunchReason = r != null
@@ -900,7 +901,8 @@
         }
         // Notify PackageWatchdog without the lock held
         if (packageList != null) {
-            mPackageWatchdog.onPackageFailure(packageList);
+            mPackageWatchdog.onPackageFailure(packageList,
+                    PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/AppTimeTracker.java b/services/core/java/com/android/server/am/AppTimeTracker.java
index debe0a9..2da6a33 100644
--- a/services/core/java/com/android/server/am/AppTimeTracker.java
+++ b/services/core/java/com/android/server/am/AppTimeTracker.java
@@ -122,7 +122,7 @@
         }
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId, boolean details) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId, boolean details) {
         final long token = proto.start(fieldId);
         proto.write(AppTimeTrackerProto.RECEIVER, mReceiver.toString());
         proto.write(AppTimeTrackerProto.TOTAL_DURATION_MS, mTotalTime);
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 0524f91..cf996a5 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -15,22 +15,20 @@
  */
 package com.android.server.am;
 
-import static android.net.wifi.WifiManager.WIFI_FEATURE_LINK_LAYER_STATS;
-
 import android.annotation.Nullable;
 import android.bluetooth.BluetoothActivityEnergyInfo;
 import android.bluetooth.BluetoothAdapter;
 import android.content.Context;
-import android.net.wifi.IWifiManager;
-import android.net.wifi.WifiActivityEnergyInfo;
+import android.net.wifi.WifiManager;
 import android.os.BatteryStats;
+import android.os.Bundle;
 import android.os.Parcelable;
 import android.os.Process;
-import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SynchronousResultReceiver;
 import android.os.SystemClock;
 import android.os.ThreadLocalWorkSource;
+import android.os.connectivity.WifiActivityEnergyInfo;
 import android.telephony.ModemActivityInfo;
 import android.telephony.TelephonyManager;
 import android.util.IntArray;
@@ -45,6 +43,7 @@
 import libcore.util.EmptyArray;
 
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.ScheduledExecutorService;
@@ -117,7 +116,7 @@
     private final Object mWorkerLock = new Object();
 
     @GuardedBy("mWorkerLock")
-    private IWifiManager mWifiManager = null;
+    private WifiManager mWifiManager = null;
 
     @GuardedBy("mWorkerLock")
     private TelephonyManager mTelephony = null;
@@ -126,7 +125,7 @@
     // Keep the last WiFi stats so we can compute a delta.
     @GuardedBy("mWorkerLock")
     private WifiActivityEnergyInfo mLastInfo =
-            new WifiActivityEnergyInfo(0, 0, 0, new long[]{0}, 0, 0, 0, 0);
+            new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0);
 
     /**
      * Timestamp at which all external stats were last collected in
@@ -411,21 +410,33 @@
 
         if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI) != 0) {
             // We were asked to fetch WiFi data.
-            if (mWifiManager == null) {
-                mWifiManager = IWifiManager.Stub.asInterface(ServiceManager.getService(
-                        Context.WIFI_SERVICE));
+            if (mWifiManager == null && ServiceManager.getService(Context.WIFI_SERVICE) != null) {
+                // this code is reached very early in the boot process, before Wifi Service has
+                // been registered. Check that ServiceManager.getService() returns a non null
+                // value before calling mContext.getSystemService(), since otherwise
+                // getSystemService() will throw a ServiceNotFoundException.
+                mWifiManager = mContext.getSystemService(WifiManager.class);
             }
 
-            if (mWifiManager != null) {
-                try {
-                    // Only fetch WiFi power data if it is supported.
-                    if ((mWifiManager.getSupportedFeatures() & WIFI_FEATURE_LINK_LAYER_STATS) != 0) {
-                        wifiReceiver = new SynchronousResultReceiver("wifi");
-                        mWifiManager.requestActivityInfo(wifiReceiver);
-                    }
-                } catch (RemoteException e) {
-                    // Oh well.
-                }
+            // Only fetch WiFi power data if it is supported.
+            if (mWifiManager != null && mWifiManager.isEnhancedPowerReportingSupported()) {
+                SynchronousResultReceiver tempWifiReceiver = new SynchronousResultReceiver("wifi");
+                mWifiManager.getWifiActivityEnergyInfoAsync(
+                        new Executor() {
+                            @Override
+                            public void execute(Runnable runnable) {
+                                // run the listener on the binder thread, if it was run on the main
+                                // thread it would deadlock since we would be waiting on ourselves
+                                runnable.run();
+                            }
+                        },
+                        info -> {
+                            Bundle bundle = new Bundle();
+                            bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, info);
+                            tempWifiReceiver.send(0, bundle);
+                        }
+                );
+                wifiReceiver = tempWifiReceiver;
             }
             synchronized (mStats) {
                 mStats.updateRailStatsLocked();
@@ -548,42 +559,45 @@
 
     @GuardedBy("mWorkerLock")
     private WifiActivityEnergyInfo extractDeltaLocked(WifiActivityEnergyInfo latest) {
-        final long timePeriodMs = latest.mTimestamp - mLastInfo.mTimestamp;
-        final long lastScanMs = mLastInfo.mControllerScanTimeMs;
-        final long lastIdleMs = mLastInfo.mControllerIdleTimeMs;
-        final long lastTxMs = mLastInfo.mControllerTxTimeMs;
-        final long lastRxMs = mLastInfo.mControllerRxTimeMs;
-        final long lastEnergy = mLastInfo.mControllerEnergyUsed;
+        final long timePeriodMs = latest.getTimeSinceBootMillis()
+                - mLastInfo.getTimeSinceBootMillis();
+        final long lastScanMs = mLastInfo.getControllerScanDurationMillis();
+        final long lastIdleMs = mLastInfo.getControllerIdleDurationMillis();
+        final long lastTxMs = mLastInfo.getControllerTxDurationMillis();
+        final long lastRxMs = mLastInfo.getControllerRxDurationMillis();
+        final long lastEnergy = mLastInfo.getControllerEnergyUsedMicroJoules();
 
         // We will modify the last info object to be the delta, and store the new
         // WifiActivityEnergyInfo object as our last one.
         final WifiActivityEnergyInfo delta = mLastInfo;
-        delta.mTimestamp = latest.getTimeStamp();
-        delta.mStackState = latest.getStackState();
+        delta.setTimeSinceBootMillis(latest.getTimeSinceBootMillis());
+        delta.setStackState(latest.getStackState());
 
-        final long txTimeMs = latest.mControllerTxTimeMs - lastTxMs;
-        final long rxTimeMs = latest.mControllerRxTimeMs - lastRxMs;
-        final long idleTimeMs = latest.mControllerIdleTimeMs - lastIdleMs;
-        final long scanTimeMs = latest.mControllerScanTimeMs - lastScanMs;
+        final long txTimeMs = latest.getControllerTxDurationMillis() - lastTxMs;
+        final long rxTimeMs = latest.getControllerRxDurationMillis() - lastRxMs;
+        final long idleTimeMs = latest.getControllerIdleDurationMillis() - lastIdleMs;
+        final long scanTimeMs = latest.getControllerScanDurationMillis() - lastScanMs;
 
         if (txTimeMs < 0 || rxTimeMs < 0 || scanTimeMs < 0 || idleTimeMs < 0) {
             // The stats were reset by the WiFi system (which is why our delta is negative).
             // Returns the unaltered stats. The total on time should not exceed the time
             // duartion between reports.
-            final long totalOnTimeMs = latest.mControllerTxTimeMs + latest.mControllerRxTimeMs
-                        + latest.mControllerIdleTimeMs;
+            final long totalOnTimeMs = latest.getControllerTxDurationMillis()
+                    + latest.getControllerRxDurationMillis()
+                    + latest.getControllerIdleDurationMillis();
             if (totalOnTimeMs <= timePeriodMs + MAX_WIFI_STATS_SAMPLE_ERROR_MILLIS) {
-                delta.mControllerEnergyUsed = latest.mControllerEnergyUsed;
-                delta.mControllerRxTimeMs = latest.mControllerRxTimeMs;
-                delta.mControllerTxTimeMs = latest.mControllerTxTimeMs;
-                delta.mControllerIdleTimeMs = latest.mControllerIdleTimeMs;
-                delta.mControllerScanTimeMs = latest.mControllerScanTimeMs;
+                delta.setControllerEnergyUsedMicroJoules(
+                        latest.getControllerEnergyUsedMicroJoules());
+                delta.setControllerRxDurationMillis(latest.getControllerRxDurationMillis());
+                delta.setControllerTxDurationMillis(latest.getControllerTxDurationMillis());
+                delta.setControllerIdleDurationMillis(latest.getControllerIdleDurationMillis());
+                delta.setControllerScanDurationMillis(latest.getControllerScanDurationMillis());
             } else {
-                delta.mControllerEnergyUsed = 0;
-                delta.mControllerRxTimeMs = 0;
-                delta.mControllerTxTimeMs = 0;
-                delta.mControllerIdleTimeMs = 0;
-                delta.mControllerScanTimeMs = 0;
+                delta.setControllerEnergyUsedMicroJoules(0);
+                delta.setControllerRxDurationMillis(0);
+                delta.setControllerTxDurationMillis(0);
+                delta.setControllerIdleDurationMillis(0);
+                delta.setControllerScanDurationMillis(0);
             }
             Slog.v(TAG, "WiFi energy data was reset, new WiFi energy data is " + delta);
         } else {
@@ -608,28 +622,30 @@
                     sb.append(" e=").append(lastEnergy);
                     sb.append("\n");
                     sb.append("Current WiFi snapshot: ").append("idle=");
-                    TimeUtils.formatDuration(latest.mControllerIdleTimeMs, sb);
+                    TimeUtils.formatDuration(latest.getControllerIdleDurationMillis(), sb);
                     sb.append(" rx=");
-                    TimeUtils.formatDuration(latest.mControllerRxTimeMs, sb);
+                    TimeUtils.formatDuration(latest.getControllerRxDurationMillis(), sb);
                     sb.append(" tx=");
-                    TimeUtils.formatDuration(latest.mControllerTxTimeMs, sb);
-                    sb.append(" e=").append(latest.mControllerEnergyUsed);
+                    TimeUtils.formatDuration(latest.getControllerTxDurationMillis(), sb);
+                    sb.append(" e=").append(latest.getControllerEnergyUsedMicroJoules());
                     Slog.wtf(TAG, sb.toString());
                 }
             } else {
                 maxExpectedIdleTimeMs = timePeriodMs - totalActiveTimeMs;
             }
             // These times seem to be the most reliable.
-            delta.mControllerTxTimeMs = txTimeMs;
-            delta.mControllerRxTimeMs = rxTimeMs;
-            delta.mControllerScanTimeMs = scanTimeMs;
+            delta.setControllerTxDurationMillis(txTimeMs);
+            delta.setControllerRxDurationMillis(rxTimeMs);
+            delta.setControllerScanDurationMillis(scanTimeMs);
             // WiFi calculates the idle time as a difference from the on time and the various
             // Rx + Tx times. There seems to be some missing time there because this sometimes
             // becomes negative. Just cap it at 0 and ensure that it is less than the expected idle
             // time from the difference in timestamps.
             // b/21613534
-            delta.mControllerIdleTimeMs = Math.min(maxExpectedIdleTimeMs, Math.max(0, idleTimeMs));
-            delta.mControllerEnergyUsed = Math.max(0, latest.mControllerEnergyUsed - lastEnergy);
+            delta.setControllerIdleDurationMillis(
+                    Math.min(maxExpectedIdleTimeMs, Math.max(0, idleTimeMs)));
+            delta.setControllerEnergyUsedMicroJoules(
+                    Math.max(0, latest.getControllerEnergyUsedMicroJoules() - lastEnergy));
         }
 
         mLastInfo = latest;
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 8c60d0c..37026fd 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -23,7 +23,6 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.net.wifi.WifiActivityEnergyInfo;
 import android.os.BatteryStats;
 import android.os.BatteryStatsInternal;
 import android.os.Binder;
@@ -43,6 +42,7 @@
 import android.os.WorkSource;
 import android.os.connectivity.CellularBatteryStats;
 import android.os.connectivity.GpsBatteryStats;
+import android.os.connectivity.WifiActivityEnergyInfo;
 import android.os.connectivity.WifiBatteryStats;
 import android.os.health.HealthStatsParceler;
 import android.os.health.HealthStatsWriter;
diff --git a/services/core/java/com/android/server/am/BroadcastDispatcher.java b/services/core/java/com/android/server/am/BroadcastDispatcher.java
index f8a3d1e..8afd52e 100644
--- a/services/core/java/com/android/server/am/BroadcastDispatcher.java
+++ b/services/core/java/com/android/server/am/BroadcastDispatcher.java
@@ -73,9 +73,9 @@
             return broadcasts.isEmpty();
         }
 
-        void writeToProto(ProtoOutputStream proto, long fieldId) {
+        void dumpDebug(ProtoOutputStream proto, long fieldId) {
             for (BroadcastRecord br : broadcasts) {
-                br.writeToProto(proto, fieldId);
+                br.dumpDebug(proto, fieldId);
             }
         }
 
@@ -415,18 +415,18 @@
     /**
      * Standard proto dump entry point
      */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         if (mCurrentBroadcast != null) {
-            mCurrentBroadcast.writeToProto(proto, fieldId);
+            mCurrentBroadcast.dumpDebug(proto, fieldId);
         }
         for (Deferrals d : mAlarmBroadcasts) {
-            d.writeToProto(proto, fieldId);
+            d.dumpDebug(proto, fieldId);
         }
         for (BroadcastRecord br : mOrderedBroadcasts) {
-            br.writeToProto(proto, fieldId);
+            br.dumpDebug(proto, fieldId);
         }
         for (Deferrals d : mDeferredBroadcasts) {
-            d.writeToProto(proto, fieldId);
+            d.dumpDebug(proto, fieldId);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/BroadcastFilter.java b/services/core/java/com/android/server/am/BroadcastFilter.java
index 34fca23..1ec8db0 100644
--- a/services/core/java/com/android/server/am/BroadcastFilter.java
+++ b/services/core/java/com/android/server/am/BroadcastFilter.java
@@ -46,9 +46,9 @@
         visibleToInstantApp = _visibleToInstantApp;
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         long token = proto.start(fieldId);
-        super.writeToProto(proto, BroadcastFilterProto.INTENT_FILTER);
+        super.dumpDebug(proto, BroadcastFilterProto.INTENT_FILTER);
         if (requiredPermission != null) {
             proto.write(BroadcastFilterProto.REQUIRED_PERMISSION, requiredPermission);
         }
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 1d03b36..10492a7 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -1915,17 +1915,17 @@
         }
     }
 
-    void writeToProto(ProtoOutputStream proto, long fieldId) {
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
         long token = proto.start(fieldId);
         proto.write(BroadcastQueueProto.QUEUE_NAME, mQueueName);
         int N;
         N = mParallelBroadcasts.size();
         for (int i = N - 1; i >= 0; i--) {
-            mParallelBroadcasts.get(i).writeToProto(proto, BroadcastQueueProto.PARALLEL_BROADCASTS);
+            mParallelBroadcasts.get(i).dumpDebug(proto, BroadcastQueueProto.PARALLEL_BROADCASTS);
         }
-        mDispatcher.writeToProto(proto, BroadcastQueueProto.ORDERED_BROADCASTS);
+        mDispatcher.dumpDebug(proto, BroadcastQueueProto.ORDERED_BROADCASTS);
         if (mPendingBroadcast != null) {
-            mPendingBroadcast.writeToProto(proto, BroadcastQueueProto.PENDING_BROADCAST);
+            mPendingBroadcast.dumpDebug(proto, BroadcastQueueProto.PENDING_BROADCAST);
         }
 
         int lastIndex = mHistoryNext;
@@ -1936,7 +1936,7 @@
             ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_HISTORY);
             BroadcastRecord r = mBroadcastHistory[ringIndex];
             if (r != null) {
-                r.writeToProto(proto, BroadcastQueueProto.HISTORICAL_BROADCASTS);
+                r.dumpDebug(proto, BroadcastQueueProto.HISTORICAL_BROADCASTS);
             }
         } while (ringIndex != lastIndex);
 
@@ -1948,7 +1948,7 @@
                 continue;
             }
             long summaryToken = proto.start(BroadcastQueueProto.HISTORICAL_BROADCASTS_SUMMARY);
-            intent.writeToProto(proto, BroadcastQueueProto.BroadcastSummary.INTENT,
+            intent.dumpDebug(proto, BroadcastQueueProto.BroadcastSummary.INTENT,
                     false, true, true, false);
             proto.write(BroadcastQueueProto.BroadcastSummary.ENQUEUE_CLOCK_TIME_MS,
                     mSummaryHistoryEnqueueTime[ringIndex]);
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 1352504..f263886 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -417,7 +417,7 @@
             + " u" + userId + " " + intent.getAction() + "}";
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         long token = proto.start(fieldId);
         proto.write(BroadcastRecordProto.USER_ID, userId);
         proto.write(BroadcastRecordProto.INTENT_ACTION, intent.getAction());
diff --git a/services/core/java/com/android/server/am/BugReportHandlerUtil.java b/services/core/java/com/android/server/am/BugReportHandlerUtil.java
new file mode 100644
index 0000000..ba89fce
--- /dev/null
+++ b/services/core/java/com/android/server/am/BugReportHandlerUtil.java
@@ -0,0 +1,179 @@
+/*
+ * 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.am;
+
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.app.BroadcastOptions;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Binder;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.server.SystemConfig;
+
+import java.util.List;
+
+/**
+ * Static utility methods related to BugReportHandler.
+ */
+public final class BugReportHandlerUtil {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "BugReportHandlerUtil" : TAG_AM;
+    private static final String SHELL_APP_PACKAGE = "com.android.shell";
+    private static final String INTENT_BUGREPORT_REQUESTED =
+            "com.android.internal.intent.action.BUGREPORT_REQUESTED";
+
+    /**
+     * Check is BugReportHandler enabled on the device.
+     *
+     * @param context Context
+     * @return true if BugReportHandler is enabled, or false otherwise
+     */
+    static boolean isBugReportHandlerEnabled(Context context) {
+        return context.getResources().getBoolean(
+                com.android.internal.R.bool.config_bugReportHandlerEnabled);
+    }
+
+    /**
+     * Launches a bugreport-whitelisted app to handle a bugreport.
+     *
+     * <p>Allows a bug report handler app to take bugreports on the user's behalf. The handler can
+     * be predefined in the config, meant to be launched with the primary user. The user can
+     * override this with a different (or same) handler app on possibly a different user. This is
+     * useful for capturing bug reports from work profile, for instance.
+     *
+     * @param context Context
+     * @return true if there is a bugreport-whitelisted app to handle a bugreport, or false
+     * otherwise
+     */
+    static boolean launchBugReportHandlerApp(Context context) {
+        if (!isBugReportHandlerEnabled(context)) {
+            return false;
+        }
+
+        String handlerApp = getCustomBugReportHandlerApp(context);
+        if (isShellApp(handlerApp)) {
+            return false;
+        }
+
+        int handlerUser = getCustomBugReportHandlerUser(context);
+        if (!isValidBugReportHandlerApp(handlerApp)) {
+            handlerApp = getDefaultBugReportHandlerApp(context);
+            handlerUser = UserHandle.USER_SYSTEM;
+        } else if (getBugReportHandlerAppReceivers(context, handlerApp, handlerUser).isEmpty()) {
+            // It looks like the settings are outdated, reset outdated settings.
+            //
+            // i.e.
+            // If user chooses which profile and which bugreport-whitelisted app in that
+            // profile to handle a bugreport, then user remove the profile.
+            // === RESULT ===
+            // The chosen bugreport handler app is outdated because the profile is removed,
+            // so reset the chosen app and profile
+            handlerApp = getDefaultBugReportHandlerApp(context);
+            handlerUser = UserHandle.USER_SYSTEM;
+            resetCustomBugreportHandlerAppAndUser(context);
+        }
+
+        if (isShellApp(handlerApp) || !isValidBugReportHandlerApp(handlerApp)
+                || getBugReportHandlerAppReceivers(context, handlerApp, handlerUser).isEmpty()) {
+            return false;
+        }
+
+        Slog.i(TAG, "Launching bug report handler app: " + handlerApp);
+        Intent intent = new Intent(INTENT_BUGREPORT_REQUESTED);
+        intent.setPackage(handlerApp);
+        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+        // Send broadcast to the receiver while allowing starting activity from background
+        final BroadcastOptions options = BroadcastOptions.makeBasic();
+        options.setBackgroundActivityStartsAllowed(true);
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            context.sendBroadcastAsUser(intent, UserHandle.of(handlerUser),
+                    android.Manifest.permission.DUMP,
+                    options.toBundle());
+        } catch (RuntimeException e) {
+            Slog.e(TAG, "Error while trying to launch bugreport handler app.", e);
+            return false;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+        return true;
+    }
+
+    private static String getCustomBugReportHandlerApp(Context context) {
+        // Get the package of custom bugreport handler app
+        return Settings.Global.getString(context.getContentResolver(),
+                Settings.Global.CUSTOM_BUGREPORT_HANDLER_APP);
+    }
+
+    private static int getCustomBugReportHandlerUser(Context context) {
+        return Settings.Global.getInt(context.getContentResolver(),
+                Settings.Global.CUSTOM_BUGREPORT_HANDLER_USER, UserHandle.USER_NULL);
+    }
+
+    private static boolean isShellApp(String app) {
+        return SHELL_APP_PACKAGE.equals(app);
+    }
+
+    private static boolean isValidBugReportHandlerApp(String app) {
+        return !TextUtils.isEmpty(app) && isBugreportWhitelistedApp(app);
+    }
+
+    private static boolean isBugreportWhitelistedApp(String app) {
+        // Verify the app is bugreport-whitelisted
+        final ArraySet<String> whitelistedApps = SystemConfig.getInstance()
+                .getBugreportWhitelistedPackages();
+        return whitelistedApps.contains(app);
+    }
+
+    private static List<ResolveInfo> getBugReportHandlerAppReceivers(Context context,
+            String handlerApp, int handlerUser) {
+        // Use the app package and the user id to retrieve the receiver that can handle a
+        // broadcast of the intent.
+        Intent intent = new Intent(INTENT_BUGREPORT_REQUESTED);
+        intent.setPackage(handlerApp);
+        return context.getPackageManager()
+                .queryBroadcastReceiversAsUser(intent, PackageManager.MATCH_SYSTEM_ONLY,
+                        handlerUser);
+    }
+
+    private static String getDefaultBugReportHandlerApp(Context context) {
+        return context.getResources().getString(
+                com.android.internal.R.string.config_defaultBugReportHandlerApp);
+    }
+
+    private static void resetCustomBugreportHandlerAppAndUser(Context context) {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            Settings.Global.putString(context.getContentResolver(),
+                    Settings.Global.CUSTOM_BUGREPORT_HANDLER_APP,
+                    getDefaultBugReportHandlerApp(context));
+            Settings.Global.putInt(context.getContentResolver(),
+                    Settings.Global.CUSTOM_BUGREPORT_HANDLER_USER, UserHandle.USER_SYSTEM);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java
index 183e059..ebfc2a0 100644
--- a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java
+++ b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java
@@ -66,9 +66,7 @@
         setCancelable(false);
         Resources res = getContext().getResources();
         // Custom view due to alignment and font size requirements
-        // TODO (b/145021634): disabled because it's delaying user switch by 3 seconds
-        // getContext()
-        // .setTheme(R.style.Theme_DeviceDefault_Light_Dialog_Alert_UserSwitchingDialog);
+        getContext().setTheme(R.style.Theme_DeviceDefault_Light_Dialog_Alert_UserSwitchingDialog);
         View view = LayoutInflater.from(getContext()).inflate(
                 R.layout.car_user_switching_dialog,
                 null);
diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java
index 4595084..6d9d3fb 100644
--- a/services/core/java/com/android/server/am/ConnectionRecord.java
+++ b/services/core/java/com/android/server/am/ConnectionRecord.java
@@ -232,7 +232,7 @@
         return stringName = sb.toString();
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         if (binding == null) return; // if binding is null, don't write data, something is wrong.
         long token = proto.start(fieldId);
         proto.write(ConnectionRecordProto.HEX_HASH,
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index cf0de06..23674bb 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -13,32 +13,14 @@
 # Do not change these names without updating the checkin_events setting in
 # google3/googledata/wireless/android/provisioning/gservices.config !!
 #
-# An activity is being finished:
-30001 am_finish_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3),(Reason|3)
-# A task is being brought to the front of the screen:
-30002 am_task_to_front (User|1|5),(Task|1|5)
-# An existing activity is being given a new intent:
-30003 am_new_intent (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3),(Action|3),(MIME Type|3),(URI|3),(Flags|1|5)
-# A new task is being created:
-30004 am_create_task (User|1|5),(Task ID|1|5)
-# A new activity is being created in an existing task:
-30005 am_create_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3),(Action|3),(MIME Type|3),(URI|3),(Flags|1|5)
-# An activity has been resumed into the foreground but was not already running:
-30006 am_restart_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3)
-# An activity has been resumed and is now in the foreground:
-30007 am_resume_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3)
 # Application Not Responding
 30008 am_anr (User|1|5),(pid|1|5),(Package Name|3),(Flags|1|5),(reason|3)
-# Activity launch time
-30009 am_activity_launch_time (User|1|5),(Token|1|5),(Component Name|3),(time|2|3)
+
 # Application process bound to work
 30010 am_proc_bound (User|1|5),(PID|1|5),(Process Name|3)
 # Application process died
 30011 am_proc_died (User|1|5),(PID|1|5),(Process Name|3),(OomAdj|1|5),(ProcState|1|5)
-# The Activity Manager failed to pause the given activity.
-30012 am_failed_to_pause (User|1|5),(Token|1|5),(Wanting to pause|3),(Currently pausing|3)
-# Attempting to pause the current activity
-30013 am_pause_activity (User|1|5),(Token|1|5),(Component Name|3),(User Leaving|3)
+
 # Application process has been started
 30014 am_proc_start (User|1|5),(PID|1|5),(UID|1|5),(Process Name|3),(Type|3),(Component|3)
 # An application process has been marked as bad
@@ -47,16 +29,7 @@
 30016 am_proc_good (User|1|5),(UID|1|5),(Process Name|3)
 # Reporting to applications that memory is low
 30017 am_low_memory (Num Processes|1|1)
-# An activity is being destroyed:
-30018 am_destroy_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3),(Reason|3)
-# An activity has been relaunched, resumed, and is now in the foreground:
-30019 am_relaunch_resume_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3)
-# An activity has been relaunched:
-30020 am_relaunch_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3)
-# The activity's onPause has been called.
-30021 am_on_paused_called (Token|1|5),(Component Name|3),(Reason|3)
-# The activity's onResume has been called.
-30022 am_on_resume_called (Token|1|5),(Component Name|3),(Reason|3)
+
 # Kill a process to reclaim memory.
 30023 am_kill (User|1|5),(PID|1|5),(Process Name|3),(OomAdj|1|5),(Reason|3)
 # Discard an undelivered serialized broadcast (timeout/ANR/crash)
@@ -87,12 +60,6 @@
 # User switched
 30041 am_switch_user (id|1|5)
 
-# Activity set to resumed
-30043 am_set_resumed_activity (User|1|5),(Component Name|3),(Reason|3)
-
-# Stack focus
-30044 am_focused_stack (User|1|5),(Display Id|1|5),(Focused Stack Id|1|5),(Last Focused Stack Id|1|5),(Reason|3)
-
 # Running pre boot receiver
 30045 am_pre_boot (User|1|5),(Package|3)
 
@@ -101,11 +68,6 @@
 # Report collection of memory used by a process
 30047 am_pss (Pid|1|5),(UID|1|5),(Process Name|3),(Pss|2|2),(Uss|2|2),(SwapPss|2|2),(Rss|2|2),(StatType|1|5),(ProcState|1|5),(TimeToCollect|2|2)
 
-# Attempting to stop an activity
-30048 am_stop_activity (User|1|5),(Token|1|5),(Component Name|3)
-# The activity's onStop has been called.
-30049 am_on_stop_called (Token|1|5),(Component Name|3),(Reason|3)
-
 # Report changing memory conditions (Values are ProcessStats.ADJ_MEM_FACTOR* constants)
 30050 am_mem_factor (Current|1|5),(Previous|1|5)
 
@@ -123,30 +85,6 @@
 # Note when a service is being forcibly stopped because its app went idle.
 30056 am_stop_idle_service (UID|1|5),(Component Name|3)
 
-# The activity's onCreate has been called.
-30057 am_on_create_called (Token|1|5),(Component Name|3),(Reason|3)
-# The activity's onRestart has been called.
-30058 am_on_restart_called (Token|1|5),(Component Name|3),(Reason|3)
-# The activity's onStart has been called.
-30059 am_on_start_called (Token|1|5),(Component Name|3),(Reason|3)
-# The activity's onDestroy has been called.
-30060 am_on_destroy_called (Token|1|5),(Component Name|3),(Reason|3)
-# The activity's onActivityResult has been called.
-30062 am_on_activity_result_called (Token|1|5),(Component Name|3),(Reason|3)
-
-# The task is being removed from its parent stack
-30061 am_remove_task (Task ID|1|5), (Stack ID|1|5)
-
 # The task is being compacted
 30063 am_compact (Pid|1|5),(Process Name|3),(Action|3),(BeforeRssTotal|2|2),(BeforeRssFile|2|2),(BeforeRssAnon|2|2),(BeforeRssSwap|2|2),(DeltaRssTotal|2|2),(DeltaRssFile|2|2),(DeltaRssAnon|2|2),(DeltaRssSwap|2|2),(Time|2|3),(LastAction|1|2),(LastActionTimestamp|2|3),(setAdj|1|2),(procState|1|2),(BeforeZRAMFree|2|2),(DeltaZRAMFree|2|2)
 
-# The activity's onTopResumedActivityChanged(true) has been called.
-30064 am_on_top_resumed_gained_called (Token|1|5),(Component Name|3),(Reason|3)
-# The activity's onTopResumedActivityChanged(false) has been called.
-30065 am_on_top_resumed_lost_called (Token|1|5),(Component Name|3),(Reason|3)
-
-# An activity been add into stopping list
-30066 am_add_to_stopping (User|1|5),(Token|1|5),(Component Name|3),(Reason|3)
-
-# Keyguard status changed
-+30067 am_set_keyguard_shown (keyguardShowing|1),(aodShowing|1),(keyguardGoingAway|1),(Reason|3)
\ No newline at end of file
diff --git a/services/core/java/com/android/server/am/IntentBindRecord.java b/services/core/java/com/android/server/am/IntentBindRecord.java
index 90aef3e..e622013 100644
--- a/services/core/java/com/android/server/am/IntentBindRecord.java
+++ b/services/core/java/com/android/server/am/IntentBindRecord.java
@@ -108,10 +108,10 @@
         return stringName = sb.toString();
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         long token = proto.start(fieldId);
         if (intent != null) {
-            intent.getIntent().writeToProto(proto,
+            intent.getIntent().dumpDebug(proto,
                     IntentBindRecordProto.INTENT, false, true, false, false);
         }
         if (binder != null) {
@@ -128,7 +128,7 @@
         for (int i=0; i<N; i++) {
             AppBindRecord a = apps.valueAt(i);
             if (a != null) {
-                a.writeToProto(proto, IntentBindRecordProto.APPS);
+                a.dumpDebug(proto, IntentBindRecordProto.APPS);
             }
         }
         proto.end(token);
diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS
index 2f9a5c9..7cc2e8eb 100644
--- a/services/core/java/com/android/server/am/OWNERS
+++ b/services/core/java/com/android/server/am/OWNERS
@@ -35,3 +35,5 @@
 narayan@google.com
 
 per-file SettingsToPropertiesMapper.java = omakoto@google.com, svetoslavganov@google.com, yamasani@google.com
+
+per-file CarUserSwitchingDialog.java = keunyoung@google.com, felipeal@google.com, gurunagarajan@google.com
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 0591704..12f4656 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -376,7 +376,11 @@
                 ConnectionRecord cr = pr.connections.valueAt(i);
                 ProcessRecord service = (cr.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0
                         ? cr.binding.service.isolatedProc : cr.binding.service.app;
-                if (service == null || service == pr || (containsCycle |= service.mReachable)) {
+                if (service == null || service == pr) {
+                    continue;
+                }
+                containsCycle |= service.mReachable;
+                if (service.mReachable) {
                     continue;
                 }
                 if ((cr.flags & (Context.BIND_WAIVE_PRIORITY
@@ -394,6 +398,10 @@
                 if (provider == null || provider == pr || (containsCycle |= provider.mReachable)) {
                     continue;
                 }
+                containsCycle |= provider.mReachable;
+                if (provider.mReachable) {
+                    continue;
+                }
                 queue.offer(provider);
                 provider.mReachable = true;
             }
@@ -482,12 +490,15 @@
         // need to reset cycle state before calling computeOomAdjLocked because of service conns
         for (int i = numProc - 1; i >= 0; i--) {
             ProcessRecord app = activeProcesses.get(i);
-            app.containsCycle = false;
             app.mReachable = false;
-            app.setCurRawProcState(PROCESS_STATE_CACHED_EMPTY);
-            app.setCurRawAdj(ProcessList.UNKNOWN_ADJ);
-            app.setCapability = PROCESS_CAPABILITY_NONE;
-            app.resetCachedInfo();
+            // No need to compute again it has been evaluated in previous iteration
+            if (app.adjSeq != mAdjSeq) {
+                app.containsCycle = false;
+                app.setCurRawProcState(PROCESS_STATE_CACHED_EMPTY);
+                app.setCurRawAdj(ProcessList.UNKNOWN_ADJ);
+                app.setCapability = PROCESS_CAPABILITY_NONE;
+                app.resetCachedInfo();
+            }
         }
         for (int i = numProc - 1; i >= 0; i--) {
             ProcessRecord app = activeProcesses.get(i);
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 2bb7035..32975d7 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -78,6 +78,9 @@
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageManagerInternal;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.EventLog;
@@ -283,6 +286,16 @@
     // lmkd reconnect delay in msecs
     private final static long LMDK_RECONNECT_DELAY_MS = 1000;
 
+    /**
+     * How long between a process kill and we actually receive its death recipient
+     */
+    private static final long PROC_KILL_TIMEOUT = 2000; // 2 seconds;
+
+    /**
+     * How long between polls to check if the given process is dead or not.
+     */
+    private static final long PROC_DEATH_POLL_INTERVAL = 100;
+
     ActivityManagerService mService = null;
 
     // To kill process groups asynchronously
@@ -1421,7 +1434,7 @@
         if (app.pendingStart) {
             return true;
         }
-        long startTime = SystemClock.elapsedRealtime();
+        long startTime = SystemClock.uptimeMillis();
         if (app.pid > 0 && app.pid != ActivityManagerService.MY_PID) {
             checkSlow(startTime, "startProcess: removing from pids map");
             mService.mPidsSelfLocked.remove(app);
@@ -1856,7 +1869,7 @@
             boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord,
             boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
             String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
-        long startTime = SystemClock.elapsedRealtime();
+        long startTime = SystemClock.uptimeMillis();
         ProcessRecord app;
         if (!isolated) {
             app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
@@ -1917,10 +1930,9 @@
             // An application record is attached to a previous process,
             // clean it up now.
             if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App died: " + app);
-            checkSlow(startTime, "startProcess: bad proc running, killing");
-            ProcessList.killProcessGroup(app.uid, app.pid);
-            mService.handleAppDiedLocked(app, true, true);
-            checkSlow(startTime, "startProcess: done killing old proc");
+            // do the killing
+            killProcAndWaitIfNecessaryLocked(app, true, app.uid == info.uid || app.isolated,
+                    "startProcess: bad proc running, killing: %s", startTime);
         }
 
         if (app == null) {
@@ -1961,6 +1973,70 @@
         return success ? app : null;
     }
 
+    /**
+     * A lite version of checking if a process is alive or not, by using kill(2) with signal 0.
+     *
+     * <p>
+     * Note that, zombie processes are stil "alive" in this case, use the {@link
+     * ActivityManagerService#isProcessAliveLocked} if zombie processes need to be excluded.
+     * </p>
+     */
+    @GuardedBy("mService")
+    private boolean isProcessAliveLiteLocked(ProcessRecord app) {
+        try {
+            Os.kill(app.pid, 0);
+        } catch (ErrnoException e) {
+            return e.errno != OsConstants.ESRCH;
+        }
+        return true;
+    }
+
+    /**
+     * Kill (if asked to) and wait for the given process died if necessary
+     * @param app - The process record to kill
+     * @param doKill - Kill the given process record
+     * @param wait - Wait for the death of the given process
+     * @param formatString - The log message for slow operation
+     * @param startTime - The start timestamp of the operation
+     */
+    @GuardedBy("mService")
+    void killProcAndWaitIfNecessaryLocked(final ProcessRecord app, final boolean doKill,
+            final boolean wait, final String formatString, final long startTime) {
+
+        checkSlow(startTime, String.format(formatString, "before appDied"));
+
+        if (doKill) {
+            // do the killing
+            ProcessList.killProcessGroup(app.uid, app.pid);
+        }
+
+        // wait for the death
+        if (wait) {
+            boolean isAlive = true;
+            // ideally we should use pidfd_open(2) but it's available on kernel 5.3 or later
+
+            final long timeout = SystemClock.uptimeMillis() + PROC_KILL_TIMEOUT;
+            isAlive = isProcessAliveLiteLocked(app);
+            while (timeout > SystemClock.uptimeMillis() && isAlive) {
+                try {
+                    Thread.sleep(PROC_DEATH_POLL_INTERVAL);
+                } catch (InterruptedException e) {
+                }
+                isAlive = isProcessAliveLiteLocked(app);
+            }
+
+            if (isAlive) {
+                // Maybe the process goes into zombie, use an expensive API to check again.
+                if (mService.isProcessAliveLocked(app)) {
+                    Slog.w(TAG, String.format(formatString,
+                              "waiting for app killing timed out"));
+                }
+            }
+        }
+
+        checkSlow(startTime, String.format(formatString, "after appDied"));
+    }
+
     @GuardedBy("mService")
     private String isProcStartValidLocked(ProcessRecord app, long expectedStartSeq) {
         StringBuilder sb = null;
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 867571a..6f6f193 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -329,9 +329,6 @@
 
     boolean mReachable; // Whether or not this process is reachable from given process
 
-    // A callback that should be executed on app died; after that it'll be set to null
-    Runnable mAppDiedCallback;
-
     void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo,
             long startTime) {
         this.startUid = startUid;
@@ -807,11 +804,11 @@
     }
 
     @Override
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
-        writeToProto(proto, fieldId, -1);
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+        dumpDebug(proto, fieldId, -1);
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId, int lruIndex) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId, int lruIndex) {
         long token = proto.start(fieldId);
         proto.write(ProcessRecordProto.PID, pid);
         proto.write(ProcessRecordProto.PROCESS_NAME, processName);
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index 5c840ad..3ada0c3 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -611,7 +611,7 @@
                 try {
                     FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]);
                     final ProtoOutputStream proto = new ProtoOutputStream(fout);
-                    stats.writeToProto(proto, stats.mTimePeriodEndRealtime, section);
+                    stats.dumpDebug(proto, stats.mTimePeriodEndRealtime, section);
                     proto.flush();
                     fout.close();
                 } catch (IOException e) {
@@ -1213,7 +1213,7 @@
             return;
         }
         final long token = proto.start(fieldId);
-        stats.writeToProto(proto, now, ProcessStats.REPORT_ALL);
+        stats.dumpDebug(proto, now, ProcessStats.REPORT_ALL);
         proto.end(token);
     }
 
@@ -1225,7 +1225,7 @@
         synchronized (mAm) {
             now = SystemClock.uptimeMillis();
             final long token = proto.start(ProcessStatsServiceDumpProto.PROCSTATS_NOW);
-            mProcessStats.writeToProto(proto, now, ProcessStats.REPORT_ALL);
+            mProcessStats.dumpDebug(proto, now, ProcessStats.REPORT_ALL);
             proto.end(token);
         }
 
diff --git a/services/core/java/com/android/server/am/ReceiverList.java b/services/core/java/com/android/server/am/ReceiverList.java
index 5e31b2e..ff34fd3 100644
--- a/services/core/java/com/android/server/am/ReceiverList.java
+++ b/services/core/java/com/android/server/am/ReceiverList.java
@@ -80,20 +80,20 @@
         return false;
     }
 
-    void writeToProto(ProtoOutputStream proto, long fieldId) {
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
         long token = proto.start(fieldId);
-        app.writeToProto(proto, ReceiverListProto.APP);
+        app.dumpDebug(proto, ReceiverListProto.APP);
         proto.write(ReceiverListProto.PID, pid);
         proto.write(ReceiverListProto.UID, uid);
         proto.write(ReceiverListProto.USER, userId);
         if (curBroadcast != null) {
-            curBroadcast.writeToProto(proto, ReceiverListProto.CURRENT);
+            curBroadcast.dumpDebug(proto, ReceiverListProto.CURRENT);
         }
         proto.write(ReceiverListProto.LINKED_TO_DEATH, linkedToDeath);
         final int N = size();
         for (int i=0; i<N; i++) {
             BroadcastFilter bf = get(i);
-            bf.writeToProto(proto, ReceiverListProto.FILTERS);
+            bf.dumpDebug(proto, ReceiverListProto.FILTERS);
         }
         proto.write(ReceiverListProto.HEX_HASH, Integer.toHexString(System.identityHashCode(this)));
         proto.end(token);
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 5106b0e4..ad316d5 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -177,7 +177,7 @@
             }
         }
 
-        public void writeToProto(ProtoOutputStream proto, long fieldId, long now) {
+        public void dumpDebug(ProtoOutputStream proto, long fieldId, long now) {
             long token = proto.start(fieldId);
             proto.write(ServiceRecordProto.StartItem.ID, id);
             ProtoUtils.toDuration(proto,
@@ -185,14 +185,14 @@
             proto.write(ServiceRecordProto.StartItem.DELIVERY_COUNT, deliveryCount);
             proto.write(ServiceRecordProto.StartItem.DONE_EXECUTING_COUNT, doneExecutingCount);
             if (intent != null) {
-                intent.writeToProto(proto, ServiceRecordProto.StartItem.INTENT, true, true,
+                intent.dumpDebug(proto, ServiceRecordProto.StartItem.INTENT, true, true,
                         true, false);
             }
             if (neededGrants != null) {
-                neededGrants.writeToProto(proto, ServiceRecordProto.StartItem.NEEDED_GRANTS);
+                neededGrants.dumpDebug(proto, ServiceRecordProto.StartItem.NEEDED_GRANTS);
             }
             if (uriPermissions != null) {
-                uriPermissions.writeToProto(proto, ServiceRecordProto.StartItem.URI_PERMISSIONS);
+                uriPermissions.dumpDebug(proto, ServiceRecordProto.StartItem.URI_PERMISSIONS);
             }
             proto.end(token);
         }
@@ -247,7 +247,7 @@
         }
     }
 
-    void writeToProto(ProtoOutputStream proto, long fieldId) {
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
         long token = proto.start(fieldId);
         proto.write(ServiceRecordProto.SHORT_NAME, this.shortInstanceName);
         proto.write(ServiceRecordProto.IS_RUNNING, app != null);
@@ -255,7 +255,7 @@
             proto.write(ServiceRecordProto.PID, app.pid);
         }
         if (intent != null) {
-            intent.getIntent().writeToProto(proto, ServiceRecordProto.INTENT, false, true, false,
+            intent.getIntent().dumpDebug(proto, ServiceRecordProto.INTENT, false, true, false,
                     false);
         }
         proto.write(ServiceRecordProto.PACKAGE_NAME, packageName);
@@ -274,17 +274,17 @@
             proto.end(appInfoToken);
         }
         if (app != null) {
-            app.writeToProto(proto, ServiceRecordProto.APP);
+            app.dumpDebug(proto, ServiceRecordProto.APP);
         }
         if (isolatedProc != null) {
-            isolatedProc.writeToProto(proto, ServiceRecordProto.ISOLATED_PROC);
+            isolatedProc.dumpDebug(proto, ServiceRecordProto.ISOLATED_PROC);
         }
         proto.write(ServiceRecordProto.WHITELIST_MANAGER, whitelistManager);
         proto.write(ServiceRecordProto.DELAYED, delayed);
         if (isForeground || foregroundId != 0) {
             long fgToken = proto.start(ServiceRecordProto.FOREGROUND);
             proto.write(ServiceRecordProto.Foreground.ID, foregroundId);
-            foregroundNoti.writeToProto(proto, ServiceRecordProto.Foreground.NOTIFICATION);
+            foregroundNoti.dumpDebug(proto, ServiceRecordProto.Foreground.NOTIFICATION);
             proto.end(fgToken);
         }
         ProtoUtils.toDuration(proto, ServiceRecordProto.CREATE_REAL_TIME, createRealTime, nowReal);
@@ -327,21 +327,21 @@
         if (deliveredStarts.size() > 0) {
             final int N = deliveredStarts.size();
             for (int i = 0; i < N; i++) {
-                deliveredStarts.get(i).writeToProto(proto,
+                deliveredStarts.get(i).dumpDebug(proto,
                         ServiceRecordProto.DELIVERED_STARTS, now);
             }
         }
         if (pendingStarts.size() > 0) {
             final int N = pendingStarts.size();
             for (int i = 0; i < N; i++) {
-                pendingStarts.get(i).writeToProto(proto, ServiceRecordProto.PENDING_STARTS, now);
+                pendingStarts.get(i).dumpDebug(proto, ServiceRecordProto.PENDING_STARTS, now);
             }
         }
         if (bindings.size() > 0) {
             final int N = bindings.size();
             for (int i=0; i<N; i++) {
                 IntentBindRecord b = bindings.valueAt(i);
-                b.writeToProto(proto, ServiceRecordProto.BINDINGS);
+                b.dumpDebug(proto, ServiceRecordProto.BINDINGS);
             }
         }
         if (connections.size() > 0) {
@@ -349,7 +349,7 @@
             for (int conni=0; conni<N; conni++) {
                 ArrayList<ConnectionRecord> c = connections.valueAt(conni);
                 for (int i=0; i<c.size(); i++) {
-                    c.get(i).writeToProto(proto, ServiceRecordProto.CONNECTIONS);
+                    c.get(i).dumpDebug(proto, ServiceRecordProto.CONNECTIONS);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index e6cf287..acf8b2e 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -156,7 +156,7 @@
     }
 
 
-    void writeToProto(ProtoOutputStream proto, long fieldId) {
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
         long token = proto.start(fieldId);
         proto.write(UidRecordProto.UID, uid);
         proto.write(UidRecordProto.CURRENT, ProcessList.makeProcStateProtoEnum(mCurProcState));
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 53ac4ec..728291d 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2100,14 +2100,14 @@
         }
     }
 
-    void writeToProto(ProtoOutputStream proto, long fieldId) {
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
         synchronized (mLock) {
             long token = proto.start(fieldId);
             for (int i = 0; i < mStartedUsers.size(); i++) {
                 UserState uss = mStartedUsers.valueAt(i);
                 final long uToken = proto.start(UserControllerProto.STARTED_USERS);
                 proto.write(UserControllerProto.User.ID, uss.mHandle.getIdentifier());
-                uss.writeToProto(proto, UserControllerProto.User.STATE);
+                uss.dumpDebug(proto, UserControllerProto.User.STATE);
                 proto.end(uToken);
             }
             for (int i = 0; i < mStartedUserArray.length; i++) {
diff --git a/services/core/java/com/android/server/am/UserState.java b/services/core/java/com/android/server/am/UserState.java
index f51b3c6..1fe7608 100644
--- a/services/core/java/com/android/server/am/UserState.java
+++ b/services/core/java/com/android/server/am/UserState.java
@@ -139,7 +139,7 @@
         pw.println();
     }
 
-    void writeToProto(ProtoOutputStream proto, long fieldId) {
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(UserStateProto.STATE, stateToProtoEnum(state));
         proto.write(UserStateProto.SWITCHING, switching);
diff --git a/services/core/java/com/android/server/am/UserSwitchingDialog.java b/services/core/java/com/android/server/am/UserSwitchingDialog.java
index bbf5772..3dbf2c6 100644
--- a/services/core/java/com/android/server/am/UserSwitchingDialog.java
+++ b/services/core/java/com/android/server/am/UserSwitchingDialog.java
@@ -24,6 +24,7 @@
 import android.os.Message;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.util.Slog;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewTreeObserver;
@@ -46,6 +47,9 @@
     // Time to wait for the onWindowShown() callback before continuing the user switch
     private static final int WINDOW_SHOWN_TIMEOUT_MS = 3000;
 
+    // User switching doesn't happen that frequently, so it doesn't hurt to have it always on
+    protected static final boolean DEBUG = true;
+
     private final ActivityManagerService mService;
     private final int mUserId;
     private static final int MSG_START_USER = 1;
@@ -118,7 +122,7 @@
 
     @Override
     public void show() {
-        // Slog.v(TAG, "show called");
+        if (DEBUG) Slog.d(TAG, "show called");
         super.show();
         final View decorView = getWindow().getDecorView();
         if (decorView != null) {
@@ -132,13 +136,14 @@
 
     @Override
     public void onWindowShown() {
-        // Slog.v(TAG, "onWindowShown called");
+        if (DEBUG) Slog.d(TAG, "onWindowShown called");
         startUser();
     }
 
     void startUser() {
         synchronized (this) {
             if (!mStartedUser) {
+                Slog.i(TAG, "starting user " + mUserId);
                 mService.mUserController.startUserInForeground(mUserId);
                 dismiss();
                 mStartedUser = true;
@@ -147,6 +152,8 @@
                     decorView.getViewTreeObserver().removeOnWindowShownListener(this);
                 }
                 mHandler.removeMessages(MSG_START_USER);
+            } else {
+                Slog.i(TAG, "user " + mUserId + " already started");
             }
         }
     }
@@ -156,6 +163,8 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_START_USER:
+                    Slog.w(TAG, "user switch window not shown in "
+                            + WINDOW_SHOWN_TIMEOUT_MS + " ms");
                     startUser();
                     break;
             }
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 7e9a17b..366766e 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -1115,6 +1115,7 @@
                     // There is some actively running operation...  need to find it
                     // and appropriately update its state.
                     final long now = System.currentTimeMillis();
+                    final long nowElapsed = SystemClock.elapsedRealtime();
                     for (int i = uidState.pkgOps.size() - 1; i >= 0; i--) {
                         final Ops ops = uidState.pkgOps.valueAt(i);
                         for (int j = ops.size() - 1; j >= 0; j--) {
@@ -1136,7 +1137,7 @@
                                     featureOp.finished(now, duration, oldPendingState,
                                             AppOpsManager.OP_FLAG_SELF);
                                     // Start the op in the new state
-                                    featureOp.startRealtime = now;
+                                    featureOp.startRealtime = nowElapsed;
                                     featureOp.started(now, newState, AppOpsManager.OP_FLAG_SELF);
                                 }
                             }
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 5983785..2175ca0 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -46,7 +46,6 @@
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.internal.os.AtomicDirectory;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.ArrayUtils;
@@ -128,6 +127,7 @@
 
     private static final String PARAMETER_DELIMITER = ",";
     private static final String PARAMETER_ASSIGNMENT = "=";
+    private static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled";
 
     @GuardedBy("mLock")
     private @NonNull LinkedList<HistoricalOps> mPendingWrites = new LinkedList<>();
@@ -701,7 +701,7 @@
     private static boolean isApiEnabled() {
         return Binder.getCallingUid() == Process.myUid()
                 || DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
-                SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, false);
+                PROPERTY_PERMISSIONS_HUB_ENABLED, false);
     }
 
     private static final class Persistence {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 6010b1dc..8144a71 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -24,6 +24,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.media.AudioDeviceAddress;
 import android.media.AudioManager;
 import android.media.AudioRoutesInfo;
 import android.media.AudioSystem;
@@ -400,6 +401,15 @@
         }
     }
 
+    /*package*/ int setPreferredDeviceForStrategySync(int strategy,
+                                                      @NonNull AudioDeviceAddress device) {
+        return mDeviceInventory.setPreferredDeviceForStrategySync(strategy, device);
+    }
+
+    /*package*/ int removePreferredDeviceForStrategySync(int strategy) {
+        return mDeviceInventory.removePreferredDeviceForStrategySync(strategy);
+    }
+
     //---------------------------------------------------------------------
     // Communication with (to) AudioService
     //TODO check whether the AudioService methods are candidates to move here
@@ -533,6 +543,15 @@
         sendLMsgNoDelay(MSG_L_SCOCLIENT_DIED, SENDMSG_QUEUE, obj);
     }
 
+    /*package*/ void postSaveSetPreferredDeviceForStrategy(int strategy, AudioDeviceAddress device)
+    {
+        sendILMsgNoDelay(MSG_IL_SAVE_PREF_DEVICE_FOR_STRATEGY, SENDMSG_QUEUE, strategy, device);
+    }
+
+    /*package*/ void postSaveRemovePreferredDeviceForStrategy(int strategy) {
+        sendIMsgNoDelay(MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY, SENDMSG_QUEUE, strategy);
+    }
+
     //---------------------------------------------------------------------
     // Method forwarding between the helper classes (BtHelper, AudioDeviceInventory)
     // only call from a "handle"* method or "on"* method
@@ -631,6 +650,7 @@
         } else {
             pw.println("Message handler is null");
         }
+        mDeviceInventory.dump(pw, prefix);
     }
 
     //---------------------------------------------------------------------
@@ -890,6 +910,15 @@
                                 info.mDevice, info.mState, info.mSupprNoisy, info.mMusicDevice);
                     }
                 } break;
+                case MSG_IL_SAVE_PREF_DEVICE_FOR_STRATEGY: {
+                    final int strategy = msg.arg1;
+                    final AudioDeviceAddress device = (AudioDeviceAddress) msg.obj;
+                    mDeviceInventory.onSaveSetPreferredDevice(strategy, device);
+                } break;
+                case MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY: {
+                    final int strategy = msg.arg1;
+                    mDeviceInventory.onSaveRemovePreferredDevice(strategy);
+                } break;
                 default:
                     Log.wtf(TAG, "Invalid message " + msg.what);
             }
@@ -941,6 +970,8 @@
     private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 31;
     // a ScoClient died in BtHelper
     private static final int MSG_L_SCOCLIENT_DIED = 32;
+    private static final int MSG_IL_SAVE_PREF_DEVICE_FOR_STRATEGY = 33;
+    private static final int MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY = 34;
 
 
     private static boolean isMessageHandledUnderWakelock(int msgId) {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index a2b3574..661451b 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -23,6 +23,7 @@
 import android.bluetooth.BluetoothHearingAid;
 import android.bluetooth.BluetoothProfile;
 import android.content.Intent;
+import android.media.AudioDeviceAddress;
 import android.media.AudioDevicePort;
 import android.media.AudioFormat;
 import android.media.AudioManager;
@@ -43,8 +44,10 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.Set;
 
 /**
@@ -58,7 +61,10 @@
 
     // Actual list of connected devices
     // Key for map created from DeviceInfo.makeDeviceListKey()
-    private final ArrayMap<String, DeviceInfo> mConnectedDevices = new ArrayMap<>();
+    private final LinkedHashMap<String, DeviceInfo> mConnectedDevices = new LinkedHashMap<>();
+
+    // List of preferred devices for strategies
+    private final ArrayMap<Integer, AudioDeviceAddress> mPreferredDevices = new ArrayMap<>();
 
     private @NonNull AudioDeviceBroker mDeviceBroker;
 
@@ -140,16 +146,23 @@
     }
 
     //------------------------------------------------------------
+    /*package*/ void dump(PrintWriter pw, String prefix) {
+        pw.println("\n" + prefix + "Preferred devices for strategy:");
+        mPreferredDevices.forEach((strategy, device) -> {
+            pw.println("  " + prefix + "strategy:" + strategy + " device:" + device); });
+    }
+
+    //------------------------------------------------------------
     // Message handling from AudioDeviceBroker
 
     /**
      * Restore previously connected devices. Use in case of audio server crash
      * (see AudioService.onAudioServerDied() method)
      */
+    // Always executed on AudioDeviceBroker message queue
     /*package*/ void onRestoreDevices() {
         synchronized (mConnectedDevices) {
-            for (int i = 0; i < mConnectedDevices.size(); i++) {
-                DeviceInfo di = mConnectedDevices.valueAt(i);
+            for (DeviceInfo di : mConnectedDevices.values()) {
                 AudioSystem.setDeviceConnectionState(
                         di.mDeviceType,
                         AudioSystem.DEVICE_STATE_AVAILABLE,
@@ -158,6 +171,11 @@
                         di.mDeviceCodecFormat);
             }
         }
+
+        synchronized (mPreferredDevices) {
+            mPreferredDevices.forEach((strategy, device) -> {
+                AudioSystem.setPreferredDeviceForStrategy(strategy, device); });
+        }
     }
 
     // only public for mocking/spying
@@ -432,9 +450,41 @@
                     "android"); // reconnect
         }
     }
+
+    /*package*/ void onSaveSetPreferredDevice(int strategy, @NonNull AudioDeviceAddress device) {
+        mPreferredDevices.put(strategy, device);
+    }
+
+    /*package*/ void onSaveRemovePreferredDevice(int strategy) {
+        mPreferredDevices.remove(strategy);
+    }
+
     //------------------------------------------------------------
     //
 
+    /*package*/ int setPreferredDeviceForStrategySync(int strategy,
+                                                      @NonNull AudioDeviceAddress device) {
+        final long identity = Binder.clearCallingIdentity();
+        final int status = AudioSystem.setPreferredDeviceForStrategy(strategy, device);
+        Binder.restoreCallingIdentity(identity);
+
+        if (status == AudioSystem.SUCCESS) {
+            mDeviceBroker.postSaveSetPreferredDeviceForStrategy(strategy, device);
+        }
+        return status;
+    }
+
+    /*package*/ int removePreferredDeviceForStrategySync(int strategy) {
+        final long identity = Binder.clearCallingIdentity();
+        final int status = AudioSystem.removePreferredDeviceForStrategy(strategy);
+        Binder.restoreCallingIdentity(identity);
+
+        if (status == AudioSystem.SUCCESS) {
+            mDeviceBroker.postSaveRemovePreferredDeviceForStrategy(strategy);
+        }
+        return status;
+    }
+
     /**
      * Implements the communication with AudioSystem to (dis)connect a device in the native layers
      * @param connect true if connection
@@ -799,11 +849,10 @@
         }
         int delay = 0;
         Set<Integer> devices = new HashSet<>();
-        for (int i = 0; i < mConnectedDevices.size(); i++) {
-            int dev = mConnectedDevices.valueAt(i).mDeviceType;
-            if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
-                    && BECOMING_NOISY_INTENT_DEVICES_SET.contains(dev)) {
-                devices.add(dev);
+        for (DeviceInfo di : mConnectedDevices.values()) {
+            if (((di.mDeviceType & AudioSystem.DEVICE_BIT_IN) == 0)
+                    && BECOMING_NOISY_INTENT_DEVICES_SET.contains(di.mDeviceType)) {
+                devices.add(di.mDeviceType);
             }
         }
         if (musicDevice == AudioSystem.DEVICE_NONE) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index e426c6c..1a62eb2 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -63,6 +63,8 @@
 import android.hardware.usb.UsbManager;
 import android.hidl.manager.V1_0.IServiceManager;
 import android.media.AudioAttributes;
+import android.media.AudioDeviceAddress;
+import android.media.AudioDeviceInfo;
 import android.media.AudioFocusInfo;
 import android.media.AudioFocusRequest;
 import android.media.AudioFormat;
@@ -269,6 +271,7 @@
     private static final int MSG_OBSERVE_DEVICES_FOR_ALL_STREAMS = 27;
     private static final int MSG_HDMI_VOLUME_CHECK = 28;
     private static final int MSG_PLAYBACK_CONFIG_CHANGE = 29;
+    private static final int MSG_BROADCAST_MICROPHONE_MUTE = 30;
     // start of messages handled under wakelock
     //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
     //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -1632,6 +1635,60 @@
     ///////////////////////////////////////////////////////////////////////////
     // IPC methods
     ///////////////////////////////////////////////////////////////////////////
+    /** @see AudioManager#setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceInfo) */
+    public int setPreferredDeviceForStrategy(int strategy, AudioDeviceAddress device) {
+        if (device == null) {
+            return AudioSystem.ERROR;
+        }
+        enforceModifyAudioRoutingPermission();
+        final String logString = String.format(
+                "setPreferredDeviceForStrategy u/pid:%d/%d strat:%d dev:%s",
+                Binder.getCallingUid(), Binder.getCallingPid(), strategy, device.toString());
+        sDeviceLogger.log(new AudioEventLogger.StringEvent(logString).printLog(TAG));
+        if (device.getRole() == AudioDeviceAddress.ROLE_INPUT) {
+            Log.e(TAG, "Unsupported input routing in " + logString);
+            return AudioSystem.ERROR;
+        }
+
+        final int status = mDeviceBroker.setPreferredDeviceForStrategySync(strategy, device);
+        if (status != AudioSystem.SUCCESS) {
+            Log.e(TAG, String.format("Error %d in %s)", status, logString));
+        }
+
+        return status;
+    }
+
+    /** @see AudioManager#removePreferredDeviceForStrategy(AudioProductStrategy) */
+    public int removePreferredDeviceForStrategy(int strategy) {
+        enforceModifyAudioRoutingPermission();
+        final String logString =
+                String.format("removePreferredDeviceForStrategy strat:%d", strategy);
+        sDeviceLogger.log(new AudioEventLogger.StringEvent(logString).printLog(TAG));
+
+        final int status = mDeviceBroker.removePreferredDeviceForStrategySync(strategy);
+        if (status != AudioSystem.SUCCESS) {
+            Log.e(TAG, String.format("Error %d in %s)", status, logString));
+        }
+        return status;
+    }
+
+    /** @see AudioManager#getPreferredDeviceForStrategy(AudioProductStrategy) */
+    public AudioDeviceAddress getPreferredDeviceForStrategy(int strategy) {
+        enforceModifyAudioRoutingPermission();
+        AudioDeviceAddress[] devices = new AudioDeviceAddress[1];
+        final long identity = Binder.clearCallingIdentity();
+        final int status = AudioSystem.getPreferredDeviceForStrategy(strategy, devices);
+        Binder.restoreCallingIdentity(identity);
+        if (status != AudioSystem.SUCCESS) {
+            Log.e(TAG, String.format("Error %d in getPreferredDeviceForStrategy(%d)",
+                    status, strategy));
+            return null;
+        } else {
+            return devices[0];
+        }
+    }
+
+
     /** @see AudioManager#adjustVolume(int, int) */
     public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
             String callingPackage, String caller) {
@@ -2925,9 +2982,8 @@
             AudioSystem.muteMicrophone(muted);
             try {
                 if (muted != currentMute) {
-                    mContext.sendBroadcastAsUser(
-                        new Intent(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED)
-                                .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL);
+                    sendMsg(mAudioHandler, MSG_BROADCAST_MICROPHONE_MUTE,
+                                SENDMSG_NOOP, 0, 0, null, 0);
                 }
             } finally {
                 Binder.restoreCallingIdentity(identity);
@@ -5236,6 +5292,13 @@
                 case MSG_PLAYBACK_CONFIG_CHANGE:
                     onPlaybackConfigChange((List<AudioPlaybackConfiguration>) msg.obj);
                     break;
+
+                case MSG_BROADCAST_MICROPHONE_MUTE:
+                    mContext.sendBroadcastAsUser(
+                            new Intent(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED)
+                                    .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
+                                    UserHandle.ALL);
+                    break;
             }
         }
     }
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 9f1a6bd..36332c0 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -295,6 +295,7 @@
                             && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
                         mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
                     }
+                    broadcast = false;
                     break;
                 default:
                     // do not broadcast CONNECTING or invalid state
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index 8762435..2eec419 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -38,10 +38,24 @@
  */
 public final class CompatChange extends CompatibilityChangeInfo {
 
+    /**
+     * Callback listener for when compat changes are updated for a package.
+     * See {@link #registerListener(ChangeListener)} for more details.
+     */
+    public interface ChangeListener {
+        /**
+         * Called upon an override change for packageName and the change this listener is
+         * registered for. Called before the app is killed.
+         */
+        void onCompatChange(String packageName);
+    }
+
+    ChangeListener mListener = null;
+
     private Map<String, Boolean> mPackageOverrides;
 
     public CompatChange(long changeId) {
-        this(changeId, null, -1, false);
+        this(changeId, null, -1, false, null);
     }
 
     /**
@@ -52,8 +66,8 @@
      * @param disabled If {@code true}, overrides any {@code enableAfterTargetSdk} set.
      */
     public CompatChange(long changeId, @Nullable String name, int enableAfterTargetSdk,
-            boolean disabled) {
-        super(changeId, name, enableAfterTargetSdk, disabled);
+            boolean disabled, String description) {
+        super(changeId, name, enableAfterTargetSdk, disabled, description);
     }
 
     /**
@@ -61,9 +75,18 @@
      */
     public CompatChange(Change change) {
         super(change.getId(), change.getName(), change.getEnableAfterTargetSdk(),
-                change.getDisabled());
+                change.getDisabled(), change.getDescription());
     }
 
+    void registerListener(ChangeListener listener) {
+        if (mListener != null) {
+            throw new IllegalStateException(
+                    "Listener for change " + toString() + " already registered.");
+        }
+        mListener = listener;
+    }
+
+
     /**
      * Force the enabled state of this change for a given package name. The change will only take
      * effect after that packages process is killed and restarted.
@@ -78,6 +101,7 @@
             mPackageOverrides = new HashMap<>();
         }
         mPackageOverrides.put(pname, enabled);
+        notifyListener(pname);
     }
 
     /**
@@ -89,7 +113,9 @@
      */
     void removePackageOverride(String pname) {
         if (mPackageOverrides != null) {
-            mPackageOverrides.remove(pname);
+            if (mPackageOverrides.remove(pname) != null) {
+                notifyListener(pname);
+            }
         }
     }
 
@@ -131,4 +157,10 @@
         }
         return sb.append(")").toString();
     }
+
+    private void notifyListener(String packageName) {
+        if (mListener != null) {
+            mListener.onCompatChange(packageName);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 490cce3..cf83dd6 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -228,7 +228,7 @@
 
     /**
      * Removes all overrides previously added via {@link #addOverride(long, String, boolean)} or
-     * {@link #addAppOverrides(CompatibilityChangeConfig, String)} for a certain package.
+     * {@link #addOverrides(CompatibilityChangeConfig, String)} for a certain package.
      *
      * <p>This restores the default behaviour for the given change and app, once any app
      * processes have been restarted.
@@ -243,6 +243,27 @@
         }
     }
 
+    boolean registerListener(long changeId, CompatChange.ChangeListener listener) {
+        boolean alreadyKnown = true;
+        synchronized (mChanges) {
+            CompatChange c = mChanges.get(changeId);
+            if (c == null) {
+                alreadyKnown = false;
+                c = new CompatChange(changeId);
+                addChange(c);
+            }
+            c.registerListener(listener);
+        }
+        return alreadyKnown;
+    }
+
+    @VisibleForTesting
+    void clearChanges() {
+        synchronized (mChanges) {
+            mChanges.clear();
+        }
+    }
+
     /**
      * Dumps the current list of compatibility config information.
      *
@@ -298,7 +319,8 @@
                 changeInfos[i] = new CompatibilityChangeInfo(change.getId(),
                         change.getName(),
                         change.getEnableAfterTargetSdk(),
-                        change.getDisabled());
+                        change.getDisabled(),
+                        change.getDescription());
             }
             return changeInfos;
         }
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 311e24f..6ec4b9f 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -108,6 +108,23 @@
         return enabled;
     }
 
+    /**
+     * Register a listener for change state overrides. Only one listener per change is allowed.
+     *
+     * <p>{@code listener.onCompatChange(String)} method is guaranteed to be called with
+     * packageName before the app is killed upon an override change. The state of a change is not
+     * guaranteed to change when {@code listener.onCompatChange(String)} is called.
+     *
+     * @param changeId to get updates for
+     * @param listener the listener that will be called upon a potential change for package.
+     * @throws IllegalStateException if a listener was already registered for changeId
+     * @returns {@code true} if a change with changeId was already known, or (@code false}
+     * otherwise.
+     */
+    public boolean registerListener(long changeId, CompatChange.ChangeListener listener) {
+        return CompatConfig.get().registerListener(changeId, listener);
+    }
+
     @Override
     public void setOverrides(CompatibilityChangeConfig overrides, String packageName) {
         CompatConfig.get().addOverrides(overrides, packageName);
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
index 79b56c6..33f6ed5 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
@@ -20,6 +20,7 @@
 import android.net.ConnectivityMetricsEvent;
 import android.net.IIpConnectivityMetrics;
 import android.net.INetdEventCallback;
+import android.net.NetworkStack;
 import android.net.metrics.ApfProgramEvent;
 import android.net.metrics.IpConnectivityLog;
 import android.os.Binder;
@@ -276,7 +277,7 @@
 
         @Override
         public int logEvent(ConnectivityMetricsEvent event) {
-            enforceConnectivityInternalPermission();
+            NetworkStack.checkNetworkStackPermission(getContext());
             return append(event);
         }
 
@@ -299,10 +300,6 @@
             }
         }
 
-        private void enforceConnectivityInternalPermission() {
-            enforcePermission(android.Manifest.permission.CONNECTIVITY_INTERNAL);
-        }
-
         private void enforceDumpPermission() {
             enforcePermission(android.Manifest.permission.DUMP);
         }
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 24a5b7f..bb7f862 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -580,7 +580,7 @@
         // semantics of WakeupMessage guarantee that if cancel is called then the alarm will
         // never call its callback (handleLingerComplete), even if it has already fired.
         // WakeupMessage makes no such guarantees about rescheduling a message, so if mLingerMessage
-        // has already been dispatched, rescheduling to some time in the future it won't stop it
+        // has already been dispatched, rescheduling to some time in the future won't stop it
         // from calling its callback immediately.
         if (mLingerMessage != null) {
             mLingerMessage.cancel();
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index bc83780..2179518 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -31,7 +31,6 @@
 import android.net.StringNetworkSpecifier;
 import android.net.wifi.WifiInfo;
 import android.os.UserHandle;
-import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
@@ -105,8 +104,7 @@
         return -1;
     }
 
-    // TODO: Remove @TransportType or change it to @Transport.
-    private static String getTransportName(@TransportType int transportType) {
+    private static String getTransportName(final int transportType) {
         Resources r = Resources.getSystem();
         String[] networkTypes = r.getStringArray(R.array.network_switch_type_name);
         try {
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 56f4959..f0b7150 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -17,7 +17,6 @@
 package com.android.server.connectivity;
 
 import static android.Manifest.permission.CHANGE_NETWORK_STATE;
-import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
 import static android.Manifest.permission.INTERNET;
 import static android.Manifest.permission.NETWORK_STACK;
@@ -25,6 +24,7 @@
 import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
 import static android.content.pm.PackageManager.GET_PERMISSIONS;
 import static android.content.pm.PackageManager.MATCH_ANY_USER;
+import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
 import static android.os.Process.INVALID_UID;
 import static android.os.Process.SYSTEM_UID;
 
@@ -259,7 +259,8 @@
                 return true;
             }
         }
-        return hasPermission(app, CONNECTIVITY_INTERNAL)
+
+        return hasPermission(app, PERMISSION_MAINLINE_NETWORK_STACK)
                 || hasPermission(app, NETWORK_STACK)
                 || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
     }
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
deleted file mode 100644
index acedc36..0000000
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ /dev/null
@@ -1,1980 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.hardware.usb.UsbManager.USB_CONFIGURED;
-import static android.hardware.usb.UsbManager.USB_CONNECTED;
-import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
-import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
-import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
-import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY;
-import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER;
-import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER;
-import static android.net.ConnectivityManager.EXTRA_ERRORED_TETHER;
-import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
-import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
-import static android.net.ConnectivityManager.TETHERING_INVALID;
-import static android.net.ConnectivityManager.TETHERING_USB;
-import static android.net.ConnectivityManager.TETHERING_WIFI;
-import static android.net.ConnectivityManager.TETHERING_WIFI_P2P;
-import static android.net.ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL;
-import static android.net.ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
-import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
-import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
-import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
-import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
-import static android.net.wifi.WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR;
-import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY;
-import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
-import static android.net.wifi.WifiManager.IFACE_IP_MODE_UNSPECIFIED;
-import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
-import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
-import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-
-import static com.android.server.ConnectivityService.SHORT_ARG;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothPan;
-import android.bluetooth.BluetoothProfile;
-import android.bluetooth.BluetoothProfile.ServiceListener;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Resources;
-import android.hardware.usb.UsbManager;
-import android.net.INetworkPolicyManager;
-import android.net.INetworkStatsService;
-import android.net.ITetheringEventCallback;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkInfo;
-import android.net.NetworkState;
-import android.net.NetworkUtils;
-import android.net.ip.IpServer;
-import android.net.util.InterfaceSet;
-import android.net.util.PrefixUtils;
-import android.net.util.SharedLog;
-import android.net.util.VersionedBroadcastListener;
-import android.net.wifi.WifiManager;
-import android.net.wifi.p2p.WifiP2pGroup;
-import android.net.wifi.p2p.WifiP2pInfo;
-import android.net.wifi.p2p.WifiP2pManager;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.INetworkManagementService;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteCallbackList;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.os.UserManagerInternal;
-import android.os.UserManagerInternal.UserRestrictionsListener;
-import android.telephony.PhoneStateListener;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.internal.notification.SystemNotificationChannels;
-import com.android.internal.util.DumpUtils;
-import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.MessageUtils;
-import com.android.internal.util.Protocol;
-import com.android.internal.util.State;
-import com.android.internal.util.StateMachine;
-import com.android.server.LocalServices;
-import com.android.server.connectivity.tethering.EntitlementManager;
-import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
-import com.android.server.connectivity.tethering.OffloadController;
-import com.android.server.connectivity.tethering.TetheringConfiguration;
-import com.android.server.connectivity.tethering.TetheringDependencies;
-import com.android.server.connectivity.tethering.TetheringInterfaceUtils;
-import com.android.server.connectivity.tethering.UpstreamNetworkMonitor;
-import com.android.server.net.BaseNetworkObserver;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * @hide
- *
- * This class holds much of the business logic to allow Android devices
- * to act as IP gateways via USB, BT, and WiFi interfaces.
- */
-public class Tethering extends BaseNetworkObserver {
-
-    private final static String TAG = Tethering.class.getSimpleName();
-    private final static boolean DBG = false;
-    private final static boolean VDBG = false;
-
-    private static final Class[] messageClasses = {
-            Tethering.class, TetherMasterSM.class, IpServer.class
-    };
-    private static final SparseArray<String> sMagicDecoderRing =
-            MessageUtils.findMessageNames(messageClasses);
-
-    private static class TetherState {
-        public final IpServer ipServer;
-        public int lastState;
-        public int lastError;
-
-        public TetherState(IpServer ipServer) {
-            this.ipServer = ipServer;
-            // Assume all state machines start out available and with no errors.
-            lastState = IpServer.STATE_AVAILABLE;
-            lastError = TETHER_ERROR_NO_ERROR;
-        }
-
-        public boolean isCurrentlyServing() {
-            switch (lastState) {
-                case IpServer.STATE_TETHERED:
-                case IpServer.STATE_LOCAL_ONLY:
-                    return true;
-                default:
-                    return false;
-            }
-        }
-    }
-
-    private final SharedLog mLog = new SharedLog(TAG);
-
-    // used to synchronize public access to members
-    private final Object mPublicSync;
-    private final Context mContext;
-    private final ArrayMap<String, TetherState> mTetherStates;
-    private final BroadcastReceiver mStateReceiver;
-    private final INetworkManagementService mNMService;
-    private final INetworkStatsService mStatsService;
-    private final INetworkPolicyManager mPolicyManager;
-    private final Looper mLooper;
-    private final StateMachine mTetherMasterSM;
-    private final OffloadController mOffloadController;
-    private final UpstreamNetworkMonitor mUpstreamNetworkMonitor;
-    // TODO: Figure out how to merge this and other downstream-tracking objects
-    // into a single coherent structure.
-    private final HashSet<IpServer> mForwardedDownstreams;
-    private final VersionedBroadcastListener mCarrierConfigChange;
-    private final TetheringDependencies mDeps;
-    private final EntitlementManager mEntitlementMgr;
-    private final Handler mHandler;
-    private final RemoteCallbackList<ITetheringEventCallback> mTetheringEventCallbacks =
-            new RemoteCallbackList<>();
-    private final PhoneStateListener mPhoneStateListener;
-    private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID;
-
-    private volatile TetheringConfiguration mConfig;
-    private InterfaceSet mCurrentUpstreamIfaceSet;
-    private Notification.Builder mTetheredNotificationBuilder;
-    private int mLastNotificationId;
-
-    private boolean mRndisEnabled;       // track the RNDIS function enabled state
-    // True iff. WiFi tethering should be started when soft AP is ready.
-    private boolean mWifiTetherRequested;
-    private Network mTetherUpstream;
-
-    public Tethering(Context context, INetworkManagementService nmService,
-            INetworkStatsService statsService, INetworkPolicyManager policyManager,
-            Looper looper, MockableSystemProperties systemProperties,
-            TetheringDependencies deps) {
-        mLog.mark("constructed");
-        mContext = context;
-        mNMService = nmService;
-        mStatsService = statsService;
-        mPolicyManager = policyManager;
-        mLooper = looper;
-        mDeps = deps;
-
-        mPublicSync = new Object();
-
-        mTetherStates = new ArrayMap<>();
-
-        mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper, deps);
-        mTetherMasterSM.start();
-
-        mHandler = mTetherMasterSM.getHandler();
-        mOffloadController = new OffloadController(mHandler,
-                mDeps.getOffloadHardwareInterface(mHandler, mLog),
-                mContext.getContentResolver(), mNMService,
-                mLog);
-        mUpstreamNetworkMonitor = deps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog,
-                TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
-        mForwardedDownstreams = new HashSet<>();
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(ACTION_CARRIER_CONFIG_CHANGED);
-        // EntitlementManager will send EVENT_UPSTREAM_PERMISSION_CHANGED when cellular upstream
-        // permission is changed according to entitlement check result.
-        mEntitlementMgr = mDeps.getEntitlementManager(mContext, mTetherMasterSM, mLog,
-                TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED, systemProperties);
-        mEntitlementMgr.setOnUiEntitlementFailedListener((int downstream) -> {
-            mLog.log("OBSERVED UiEnitlementFailed");
-            stopTethering(downstream);
-        });
-        mEntitlementMgr.setTetheringConfigurationFetcher(() -> {
-            return mConfig;
-        });
-
-        mCarrierConfigChange = new VersionedBroadcastListener(
-                "CarrierConfigChangeListener", mContext, mHandler, filter,
-                (Intent ignored) -> {
-                    mLog.log("OBSERVED carrier config change");
-                    updateConfiguration();
-                    mEntitlementMgr.reevaluateSimCardProvisioning(mConfig);
-                });
-
-        mPhoneStateListener = new PhoneStateListener(mLooper) {
-            @Override
-            public void onActiveDataSubscriptionIdChanged(int subId) {
-                mLog.log("OBSERVED active data subscription change, from " + mActiveDataSubId
-                        + " to " + subId);
-                if (subId == mActiveDataSubId) return;
-
-                mActiveDataSubId = subId;
-                updateConfiguration();
-                // To avoid launching unexpected provisioning checks, ignore re-provisioning when
-                // no CarrierConfig loaded yet. Assume reevaluateSimCardProvisioning() will be
-                // triggered again when CarrierConfig is loaded.
-                if (mEntitlementMgr.getCarrierConfig(mConfig) != null) {
-                    mEntitlementMgr.reevaluateSimCardProvisioning(mConfig);
-                } else {
-                    mLog.log("IGNORED reevaluate provisioning due to no carrier config loaded");
-                }
-            }
-        };
-
-        mStateReceiver = new StateReceiver();
-
-        // Load tethering configuration.
-        updateConfiguration();
-
-        startStateMachineUpdaters(mHandler);
-    }
-
-    private void startStateMachineUpdaters(Handler handler) {
-        mCarrierConfigChange.startListening();
-        mContext.getSystemService(TelephonyManager.class).listen(
-                mPhoneStateListener, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(UsbManager.ACTION_USB_STATE);
-        filter.addAction(CONNECTIVITY_ACTION);
-        filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
-        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
-        filter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
-        mContext.registerReceiver(mStateReceiver, filter, null, handler);
-
-        filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_MEDIA_SHARED);
-        filter.addAction(Intent.ACTION_MEDIA_UNSHARED);
-        filter.addDataScheme("file");
-        mContext.registerReceiver(mStateReceiver, filter, null, handler);
-
-        final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
-        // This check is useful only for some unit tests; example: ConnectivityServiceTest.
-        if (umi != null) {
-            umi.addUserRestrictionsListener(new TetheringUserRestrictionListener(this));
-        }
-    }
-
-    private WifiManager getWifiManager() {
-        return (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
-    }
-
-    // NOTE: This is always invoked on the mLooper thread.
-    private void updateConfiguration() {
-        mConfig = mDeps.generateTetheringConfiguration(mContext, mLog, mActiveDataSubId);
-        mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired);
-    }
-
-    private void maybeDunSettingChanged() {
-        final boolean isDunRequired = TetheringConfiguration.checkDunRequired(
-                mContext, mActiveDataSubId);
-        if (isDunRequired == mConfig.isDunRequired) return;
-        updateConfiguration();
-    }
-
-    @Override
-    public void interfaceStatusChanged(String iface, boolean up) {
-        // Never called directly: only called from interfaceLinkStateChanged.
-        // See NetlinkHandler.cpp:71.
-        if (VDBG) Log.d(TAG, "interfaceStatusChanged " + iface + ", " + up);
-        synchronized (mPublicSync) {
-            if (up) {
-                maybeTrackNewInterfaceLocked(iface);
-            } else {
-                if (ifaceNameToType(iface) == TETHERING_BLUETOOTH) {
-                    stopTrackingInterfaceLocked(iface);
-                } else {
-                    // Ignore usb0 down after enabling RNDIS.
-                    // We will handle disconnect in interfaceRemoved.
-                    // Similarly, ignore interface down for WiFi.  We monitor WiFi AP status
-                    // through the WifiManager.WIFI_AP_STATE_CHANGED_ACTION intent.
-                    if (VDBG) Log.d(TAG, "ignore interface down for " + iface);
-                }
-            }
-        }
-    }
-
-    @Override
-    public void interfaceLinkStateChanged(String iface, boolean up) {
-        interfaceStatusChanged(iface, up);
-    }
-
-    private int ifaceNameToType(String iface) {
-        final TetheringConfiguration cfg = mConfig;
-
-        if (cfg.isWifi(iface)) {
-            return TETHERING_WIFI;
-        } else if (cfg.isWifiP2p(iface)) {
-            return TETHERING_WIFI_P2P;
-        } else if (cfg.isUsb(iface)) {
-            return TETHERING_USB;
-        } else if (cfg.isBluetooth(iface)) {
-            return TETHERING_BLUETOOTH;
-        }
-        return TETHERING_INVALID;
-    }
-
-    @Override
-    public void interfaceAdded(String iface) {
-        if (VDBG) Log.d(TAG, "interfaceAdded " + iface);
-        synchronized (mPublicSync) {
-            maybeTrackNewInterfaceLocked(iface);
-        }
-    }
-
-    @Override
-    public void interfaceRemoved(String iface) {
-        if (VDBG) Log.d(TAG, "interfaceRemoved " + iface);
-        synchronized (mPublicSync) {
-            stopTrackingInterfaceLocked(iface);
-        }
-    }
-
-    public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
-        mEntitlementMgr.startProvisioningIfNeeded(type, showProvisioningUi);
-        enableTetheringInternal(type, true /* enabled */, receiver);
-    }
-
-    public void stopTethering(int type) {
-        enableTetheringInternal(type, false /* disabled */, null);
-        mEntitlementMgr.stopProvisioningIfNeeded(type);
-    }
-
-    /**
-     * Enables or disables tethering for the given type. If provisioning is required, it will
-     * schedule provisioning rechecks for the specified interface.
-     */
-    private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) {
-        int result;
-        switch (type) {
-            case TETHERING_WIFI:
-                result = setWifiTethering(enable);
-                sendTetherResult(receiver, result);
-                break;
-            case TETHERING_USB:
-                result = setUsbTethering(enable);
-                sendTetherResult(receiver, result);
-                break;
-            case TETHERING_BLUETOOTH:
-                setBluetoothTethering(enable, receiver);
-                break;
-            default:
-                Log.w(TAG, "Invalid tether type.");
-                sendTetherResult(receiver, TETHER_ERROR_UNKNOWN_IFACE);
-        }
-    }
-
-    private void sendTetherResult(ResultReceiver receiver, int result) {
-        if (receiver != null) {
-            receiver.send(result, null);
-        }
-    }
-
-    private int setWifiTethering(final boolean enable) {
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            synchronized (mPublicSync) {
-                final WifiManager mgr = getWifiManager();
-                if (mgr == null) {
-                    mLog.e("setWifiTethering: failed to get WifiManager!");
-                    return TETHER_ERROR_SERVICE_UNAVAIL;
-                }
-                if ((enable && mgr.startSoftAp(null /* use existing wifi config */)) ||
-                    (!enable && mgr.stopSoftAp())) {
-                    mWifiTetherRequested = enable;
-                    return TETHER_ERROR_NO_ERROR;
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-
-        return TETHER_ERROR_MASTER_ERROR;
-    }
-
-    private void setBluetoothTethering(final boolean enable, final ResultReceiver receiver) {
-        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        if (adapter == null || !adapter.isEnabled()) {
-            Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: " +
-                    (adapter == null));
-            sendTetherResult(receiver, TETHER_ERROR_SERVICE_UNAVAIL);
-            return;
-        }
-
-        adapter.getProfileProxy(mContext, new ServiceListener() {
-            @Override
-            public void onServiceDisconnected(int profile) { }
-
-            @Override
-            public void onServiceConnected(int profile, BluetoothProfile proxy) {
-                // Clear identify is fine because caller already pass tethering permission at
-                // ConnectivityService#startTethering()(or stopTethering) before the control comes
-                // here. Bluetooth will check tethering permission again that there is
-                // Context#getOpPackageName() under BluetoothPan#setBluetoothTethering() to get
-                // caller's package name for permission check.
-                // Calling BluetoothPan#setBluetoothTethering() here means the package name always
-                // be system server. If calling identity is not cleared, that package's uid might
-                // not match calling uid and end up in permission denied.
-                final long identityToken = Binder.clearCallingIdentity();
-                try {
-                    ((BluetoothPan) proxy).setBluetoothTethering(enable);
-                } finally {
-                    Binder.restoreCallingIdentity(identityToken);
-                }
-                // TODO: Enabling bluetooth tethering can fail asynchronously here.
-                // We should figure out a way to bubble up that failure instead of sending success.
-                final int result = (((BluetoothPan) proxy).isTetheringOn() == enable)
-                        ? TETHER_ERROR_NO_ERROR
-                        : TETHER_ERROR_MASTER_ERROR;
-                sendTetherResult(receiver, result);
-                adapter.closeProfileProxy(BluetoothProfile.PAN, proxy);
-            }
-        }, BluetoothProfile.PAN);
-    }
-
-    public int tether(String iface) {
-        return tether(iface, IpServer.STATE_TETHERED);
-    }
-
-    private int tether(String iface, int requestedState) {
-        if (DBG) Log.d(TAG, "Tethering " + iface);
-        synchronized (mPublicSync) {
-            TetherState tetherState = mTetherStates.get(iface);
-            if (tetherState == null) {
-                Log.e(TAG, "Tried to Tether an unknown iface: " + iface + ", ignoring");
-                return TETHER_ERROR_UNKNOWN_IFACE;
-            }
-            // Ignore the error status of the interface.  If the interface is available,
-            // the errors are referring to past tethering attempts anyway.
-            if (tetherState.lastState != IpServer.STATE_AVAILABLE) {
-                Log.e(TAG, "Tried to Tether an unavailable iface: " + iface + ", ignoring");
-                return TETHER_ERROR_UNAVAIL_IFACE;
-            }
-            // NOTE: If a CMD_TETHER_REQUESTED message is already in the TISM's
-            // queue but not yet processed, this will be a no-op and it will not
-            // return an error.
-            //
-            // TODO: reexamine the threading and messaging model.
-            tetherState.ipServer.sendMessage(IpServer.CMD_TETHER_REQUESTED, requestedState);
-            return TETHER_ERROR_NO_ERROR;
-        }
-    }
-
-    public int untether(String iface) {
-        if (DBG) Log.d(TAG, "Untethering " + iface);
-        synchronized (mPublicSync) {
-            TetherState tetherState = mTetherStates.get(iface);
-            if (tetherState == null) {
-                Log.e(TAG, "Tried to Untether an unknown iface :" + iface + ", ignoring");
-                return TETHER_ERROR_UNKNOWN_IFACE;
-            }
-            if (!tetherState.isCurrentlyServing()) {
-                Log.e(TAG, "Tried to untether an inactive iface :" + iface + ", ignoring");
-                return TETHER_ERROR_UNAVAIL_IFACE;
-            }
-            tetherState.ipServer.sendMessage(IpServer.CMD_TETHER_UNREQUESTED);
-            return TETHER_ERROR_NO_ERROR;
-        }
-    }
-
-    public void untetherAll() {
-        stopTethering(TETHERING_WIFI);
-        stopTethering(TETHERING_WIFI_P2P);
-        stopTethering(TETHERING_USB);
-        stopTethering(TETHERING_BLUETOOTH);
-    }
-
-    public int getLastTetherError(String iface) {
-        synchronized (mPublicSync) {
-            TetherState tetherState = mTetherStates.get(iface);
-            if (tetherState == null) {
-                Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface +
-                        ", ignoring");
-                return TETHER_ERROR_UNKNOWN_IFACE;
-            }
-            return tetherState.lastError;
-        }
-    }
-
-    // TODO: Figure out how to update for local hotspot mode interfaces.
-    private void sendTetherStateChangedBroadcast() {
-        if (!mDeps.isTetheringSupported()) return;
-
-        final ArrayList<String> availableList = new ArrayList<>();
-        final ArrayList<String> tetherList = new ArrayList<>();
-        final ArrayList<String> localOnlyList = new ArrayList<>();
-        final ArrayList<String> erroredList = new ArrayList<>();
-
-        boolean wifiTethered = false;
-        boolean usbTethered = false;
-        boolean bluetoothTethered = false;
-
-        final TetheringConfiguration cfg = mConfig;
-
-        synchronized (mPublicSync) {
-            for (int i = 0; i < mTetherStates.size(); i++) {
-                TetherState tetherState = mTetherStates.valueAt(i);
-                String iface = mTetherStates.keyAt(i);
-                if (tetherState.lastError != TETHER_ERROR_NO_ERROR) {
-                    erroredList.add(iface);
-                } else if (tetherState.lastState == IpServer.STATE_AVAILABLE) {
-                    availableList.add(iface);
-                } else if (tetherState.lastState == IpServer.STATE_LOCAL_ONLY) {
-                    localOnlyList.add(iface);
-                } else if (tetherState.lastState == IpServer.STATE_TETHERED) {
-                    if (cfg.isUsb(iface)) {
-                        usbTethered = true;
-                    } else if (cfg.isWifi(iface)) {
-                        wifiTethered = true;
-                    } else if (cfg.isBluetooth(iface)) {
-                        bluetoothTethered = true;
-                    }
-                    tetherList.add(iface);
-                }
-            }
-        }
-        final Intent bcast = new Intent(ACTION_TETHER_STATE_CHANGED);
-        bcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
-                Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-        bcast.putStringArrayListExtra(EXTRA_AVAILABLE_TETHER, availableList);
-        bcast.putStringArrayListExtra(EXTRA_ACTIVE_LOCAL_ONLY, localOnlyList);
-        bcast.putStringArrayListExtra(EXTRA_ACTIVE_TETHER, tetherList);
-        bcast.putStringArrayListExtra(EXTRA_ERRORED_TETHER, erroredList);
-        mContext.sendStickyBroadcastAsUser(bcast, UserHandle.ALL);
-        if (DBG) {
-            Log.d(TAG, String.format(
-                    "sendTetherStateChangedBroadcast %s=[%s] %s=[%s] %s=[%s] %s=[%s]",
-                    "avail", TextUtils.join(",", availableList),
-                    "local_only", TextUtils.join(",", localOnlyList),
-                    "tether", TextUtils.join(",", tetherList),
-                    "error", TextUtils.join(",", erroredList)));
-        }
-
-        if (usbTethered) {
-            if (wifiTethered || bluetoothTethered) {
-                showTetheredNotification(SystemMessage.NOTE_TETHER_GENERAL);
-            } else {
-                showTetheredNotification(SystemMessage.NOTE_TETHER_USB);
-            }
-        } else if (wifiTethered) {
-            if (bluetoothTethered) {
-                showTetheredNotification(SystemMessage.NOTE_TETHER_GENERAL);
-            } else {
-                /* We now have a status bar icon for WifiTethering, so drop the notification */
-                clearTetheredNotification();
-            }
-        } else if (bluetoothTethered) {
-            showTetheredNotification(SystemMessage.NOTE_TETHER_BLUETOOTH);
-        } else {
-            clearTetheredNotification();
-        }
-    }
-
-    private void showTetheredNotification(int id) {
-        showTetheredNotification(id, true);
-    }
-
-    @VisibleForTesting
-    protected void showTetheredNotification(int id, boolean tetheringOn) {
-        NotificationManager notificationManager =
-                (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
-        if (notificationManager == null) {
-            return;
-        }
-        int icon = 0;
-        switch(id) {
-          case SystemMessage.NOTE_TETHER_USB:
-            icon = com.android.internal.R.drawable.stat_sys_tether_usb;
-            break;
-          case SystemMessage.NOTE_TETHER_BLUETOOTH:
-            icon = com.android.internal.R.drawable.stat_sys_tether_bluetooth;
-            break;
-          case SystemMessage.NOTE_TETHER_GENERAL:
-          default:
-            icon = com.android.internal.R.drawable.stat_sys_tether_general;
-            break;
-        }
-
-        if (mLastNotificationId != 0) {
-            if (mLastNotificationId == icon) {
-                return;
-            }
-            notificationManager.cancelAsUser(null, mLastNotificationId,
-                    UserHandle.ALL);
-            mLastNotificationId = 0;
-        }
-
-        Intent intent = new Intent();
-        intent.setClassName("com.android.settings", "com.android.settings.TetherSettings");
-        intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
-
-        PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0, intent, 0,
-                null, UserHandle.CURRENT);
-
-        Resources r = Resources.getSystem();
-        final CharSequence title;
-        final CharSequence message;
-
-        if (tetheringOn) {
-            title = r.getText(com.android.internal.R.string.tethered_notification_title);
-            message = r.getText(com.android.internal.R.string.tethered_notification_message);
-        } else {
-            title = r.getText(com.android.internal.R.string.disable_tether_notification_title);
-            message = r.getText(com.android.internal.R.string.disable_tether_notification_message);
-        }
-
-        if (mTetheredNotificationBuilder == null) {
-            mTetheredNotificationBuilder =
-                    new Notification.Builder(mContext, SystemNotificationChannels.NETWORK_STATUS);
-            mTetheredNotificationBuilder.setWhen(0)
-                    .setOngoing(true)
-                    .setColor(mContext.getColor(
-                            com.android.internal.R.color.system_notification_accent_color))
-                    .setVisibility(Notification.VISIBILITY_PUBLIC)
-                    .setCategory(Notification.CATEGORY_STATUS);
-        }
-        mTetheredNotificationBuilder.setSmallIcon(icon)
-                .setContentTitle(title)
-                .setContentText(message)
-                .setContentIntent(pi);
-        mLastNotificationId = id;
-
-        notificationManager.notifyAsUser(null, mLastNotificationId,
-                mTetheredNotificationBuilder.buildInto(new Notification()), UserHandle.ALL);
-    }
-
-    @VisibleForTesting
-    protected void clearTetheredNotification() {
-        NotificationManager notificationManager =
-            (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
-        if (notificationManager != null && mLastNotificationId != 0) {
-            notificationManager.cancelAsUser(null, mLastNotificationId,
-                    UserHandle.ALL);
-            mLastNotificationId = 0;
-        }
-    }
-
-    private class StateReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context content, Intent intent) {
-            final String action = intent.getAction();
-            if (action == null) return;
-
-            if (action.equals(UsbManager.ACTION_USB_STATE)) {
-                handleUsbAction(intent);
-            } else if (action.equals(CONNECTIVITY_ACTION)) {
-                handleConnectivityAction(intent);
-            } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
-                handleWifiApAction(intent);
-            } else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) {
-                handleWifiP2pAction(intent);
-            } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
-                mLog.log("OBSERVED configuration changed");
-                updateConfiguration();
-            }
-        }
-
-        private void handleConnectivityAction(Intent intent) {
-            final NetworkInfo networkInfo =
-                    (NetworkInfo) intent.getParcelableExtra(EXTRA_NETWORK_INFO);
-            if (networkInfo == null ||
-                    networkInfo.getDetailedState() == NetworkInfo.DetailedState.FAILED) {
-                return;
-            }
-
-            if (VDBG) Log.d(TAG, "Tethering got CONNECTIVITY_ACTION: " + networkInfo.toString());
-            mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);
-        }
-
-        private void handleUsbAction(Intent intent) {
-            final boolean usbConnected = intent.getBooleanExtra(USB_CONNECTED, false);
-            final boolean usbConfigured = intent.getBooleanExtra(USB_CONFIGURED, false);
-            final boolean rndisEnabled = intent.getBooleanExtra(USB_FUNCTION_RNDIS, false);
-
-            mLog.log(String.format("USB bcast connected:%s configured:%s rndis:%s",
-                    usbConnected, usbConfigured, rndisEnabled));
-
-            // There are three types of ACTION_USB_STATE:
-            //
-            //     - DISCONNECTED (USB_CONNECTED and USB_CONFIGURED are 0)
-            //       Meaning: USB connection has ended either because of
-            //       software reset or hard unplug.
-            //
-            //     - CONNECTED (USB_CONNECTED is 1, USB_CONFIGURED is 0)
-            //       Meaning: the first stage of USB protocol handshake has
-            //       occurred but it is not complete.
-            //
-            //     - CONFIGURED (USB_CONNECTED and USB_CONFIGURED are 1)
-            //       Meaning: the USB handshake is completely done and all the
-            //       functions are ready to use.
-            //
-            // For more explanation, see b/62552150 .
-            synchronized (Tethering.this.mPublicSync) {
-                if (!usbConnected && mRndisEnabled) {
-                    // Turn off tethering if it was enabled and there is a disconnect.
-                    tetherMatchingInterfaces(IpServer.STATE_AVAILABLE, TETHERING_USB);
-                    mEntitlementMgr.stopProvisioningIfNeeded(TETHERING_USB);
-                } else if (usbConfigured && rndisEnabled) {
-                    // Tether if rndis is enabled and usb is configured.
-                    tetherMatchingInterfaces(IpServer.STATE_TETHERED, TETHERING_USB);
-                }
-                mRndisEnabled = usbConfigured && rndisEnabled;
-            }
-        }
-
-        private void handleWifiApAction(Intent intent) {
-            final int curState = intent.getIntExtra(EXTRA_WIFI_AP_STATE, WIFI_AP_STATE_DISABLED);
-            final String ifname = intent.getStringExtra(EXTRA_WIFI_AP_INTERFACE_NAME);
-            final int ipmode = intent.getIntExtra(EXTRA_WIFI_AP_MODE, IFACE_IP_MODE_UNSPECIFIED);
-
-            synchronized (Tethering.this.mPublicSync) {
-                switch (curState) {
-                    case WifiManager.WIFI_AP_STATE_ENABLING:
-                        // We can see this state on the way to both enabled and failure states.
-                        break;
-                    case WifiManager.WIFI_AP_STATE_ENABLED:
-                        enableWifiIpServingLocked(ifname, ipmode);
-                        break;
-                    case WifiManager.WIFI_AP_STATE_DISABLED:
-                    case WifiManager.WIFI_AP_STATE_DISABLING:
-                    case WifiManager.WIFI_AP_STATE_FAILED:
-                    default:
-                        disableWifiIpServingLocked(ifname, curState);
-                        break;
-                }
-            }
-        }
-
-        private void handleWifiP2pAction(Intent intent) {
-            if (mConfig.isWifiP2pLegacyTetheringMode()) return;
-
-            final WifiP2pInfo p2pInfo =
-                    (WifiP2pInfo) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO);
-            final WifiP2pGroup group =
-                    (WifiP2pGroup) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP);
-
-            if (VDBG) {
-                Log.d(TAG, "WifiP2pAction: P2pInfo: " + p2pInfo + " Group: " + group);
-            }
-
-            if (p2pInfo == null) return;
-            // When a p2p group is disconnected, p2pInfo would be cleared.
-            // group is still valid for detecting whether this device is group owner.
-            if (group == null || !group.isGroupOwner()
-                    || TextUtils.isEmpty(group.getInterface())) return;
-
-            synchronized (Tethering.this.mPublicSync) {
-                // Enter below only if this device is Group Owner with a valid interface.
-                if (p2pInfo.groupFormed) {
-                    TetherState tetherState = mTetherStates.get(group.getInterface());
-                    if (tetherState == null
-                            || (tetherState.lastState != IpServer.STATE_TETHERED
-                                && tetherState.lastState != IpServer.STATE_LOCAL_ONLY)) {
-                        enableWifiIpServingLocked(group.getInterface(), IFACE_IP_MODE_LOCAL_ONLY);
-                    }
-                } else {
-                    disableWifiP2pIpServingLocked(group.getInterface());
-                }
-            }
-        }
-    }
-
-    @VisibleForTesting
-    protected static class TetheringUserRestrictionListener implements UserRestrictionsListener {
-        private final Tethering mWrapper;
-
-        public TetheringUserRestrictionListener(Tethering wrapper) {
-            mWrapper = wrapper;
-        }
-
-        public void onUserRestrictionsChanged(int userId,
-                                              Bundle newRestrictions,
-                                              Bundle prevRestrictions) {
-            final boolean newlyDisallowed =
-                    newRestrictions.getBoolean(UserManager.DISALLOW_CONFIG_TETHERING);
-            final boolean previouslyDisallowed =
-                    prevRestrictions.getBoolean(UserManager.DISALLOW_CONFIG_TETHERING);
-            final boolean tetheringDisallowedChanged = (newlyDisallowed != previouslyDisallowed);
-
-            if (!tetheringDisallowedChanged) {
-                return;
-            }
-
-            mWrapper.clearTetheredNotification();
-            final boolean isTetheringActiveOnDevice = (mWrapper.getTetheredIfaces().length != 0);
-
-            if (newlyDisallowed && isTetheringActiveOnDevice) {
-                mWrapper.showTetheredNotification(
-                        com.android.internal.R.drawable.stat_sys_tether_general, false);
-                mWrapper.untetherAll();
-            }
-        }
-    }
-
-    private void disableWifiIpServingLockedCommon(int tetheringType, String ifname, int apState) {
-        mLog.log("Canceling WiFi tethering request -"
-                + " type=" + tetheringType
-                + " interface=" + ifname
-                + " state=" + apState);
-
-        if (!TextUtils.isEmpty(ifname)) {
-            final TetherState ts = mTetherStates.get(ifname);
-            if (ts != null) {
-                ts.ipServer.unwanted();
-                return;
-            }
-        }
-
-        for (int i = 0; i < mTetherStates.size(); i++) {
-            final IpServer ipServer = mTetherStates.valueAt(i).ipServer;
-            if (ipServer.interfaceType() == tetheringType) {
-                ipServer.unwanted();
-                return;
-            }
-        }
-
-        mLog.log("Error disabling Wi-Fi IP serving; " +
-                (TextUtils.isEmpty(ifname) ? "no interface name specified"
-                                           : "specified interface: " + ifname));
-    }
-
-    private void disableWifiIpServingLocked(String ifname, int apState) {
-        // Regardless of whether we requested this transition, the AP has gone
-        // down.  Don't try to tether again unless we're requested to do so.
-        // TODO: Remove this altogether, once Wi-Fi reliably gives us an
-        // interface name with every broadcast.
-        mWifiTetherRequested = false;
-
-        disableWifiIpServingLockedCommon(TETHERING_WIFI, ifname, apState);
-    }
-
-    private void disableWifiP2pIpServingLocked(String ifname) {
-        disableWifiIpServingLockedCommon(TETHERING_WIFI_P2P, ifname, /* dummy */ 0);
-    }
-
-    private void enableWifiIpServingLocked(String ifname, int wifiIpMode) {
-        // Map wifiIpMode values to IpServer.Callback serving states, inferring
-        // from mWifiTetherRequested as a final "best guess".
-        final int ipServingMode;
-        switch (wifiIpMode) {
-            case IFACE_IP_MODE_TETHERED:
-                ipServingMode = IpServer.STATE_TETHERED;
-                break;
-            case IFACE_IP_MODE_LOCAL_ONLY:
-                ipServingMode = IpServer.STATE_LOCAL_ONLY;
-                break;
-            default:
-                mLog.e("Cannot enable IP serving in unknown WiFi mode: " + wifiIpMode);
-                return;
-        }
-
-        if (!TextUtils.isEmpty(ifname)) {
-            maybeTrackNewInterfaceLocked(ifname);
-            changeInterfaceState(ifname, ipServingMode);
-        } else {
-            mLog.e(String.format(
-                   "Cannot enable IP serving in mode %s on missing interface name",
-                   ipServingMode));
-        }
-    }
-
-    // TODO: Consider renaming to something more accurate in its description.
-    // This method:
-    //     - allows requesting either tethering or local hotspot serving states
-    //     - handles both enabling and disabling serving states
-    //     - only tethers the first matching interface in listInterfaces()
-    //       order of a given type
-    private void tetherMatchingInterfaces(int requestedState, int interfaceType) {
-        if (VDBG) {
-            Log.d(TAG, "tetherMatchingInterfaces(" + requestedState + ", " + interfaceType + ")");
-        }
-
-        String[] ifaces = null;
-        try {
-            ifaces = mNMService.listInterfaces();
-        } catch (Exception e) {
-            Log.e(TAG, "Error listing Interfaces", e);
-            return;
-        }
-        String chosenIface = null;
-        if (ifaces != null) {
-            for (String iface : ifaces) {
-                if (ifaceNameToType(iface) == interfaceType) {
-                    chosenIface = iface;
-                    break;
-                }
-            }
-        }
-        if (chosenIface == null) {
-            Log.e(TAG, "could not find iface of type " + interfaceType);
-            return;
-        }
-
-        changeInterfaceState(chosenIface, requestedState);
-    }
-
-    private void changeInterfaceState(String ifname, int requestedState) {
-        final int result;
-        switch (requestedState) {
-            case IpServer.STATE_UNAVAILABLE:
-            case IpServer.STATE_AVAILABLE:
-                result = untether(ifname);
-                break;
-            case IpServer.STATE_TETHERED:
-            case IpServer.STATE_LOCAL_ONLY:
-                result = tether(ifname, requestedState);
-                break;
-            default:
-                Log.wtf(TAG, "Unknown interface state: " + requestedState);
-                return;
-        }
-        if (result != TETHER_ERROR_NO_ERROR) {
-            Log.e(TAG, "unable start or stop tethering on iface " + ifname);
-            return;
-        }
-    }
-
-    public TetheringConfiguration getTetheringConfiguration() {
-        return mConfig;
-    }
-
-    public boolean hasTetherableConfiguration() {
-        final TetheringConfiguration cfg = mConfig;
-        final boolean hasDownstreamConfiguration =
-                (cfg.tetherableUsbRegexs.length != 0)
-                || (cfg.tetherableWifiRegexs.length != 0)
-                || (cfg.tetherableBluetoothRegexs.length != 0);
-        final boolean hasUpstreamConfiguration = !cfg.preferredUpstreamIfaceTypes.isEmpty()
-                || cfg.chooseUpstreamAutomatically;
-
-        return hasDownstreamConfiguration && hasUpstreamConfiguration;
-    }
-
-    // TODO - update callers to use getTetheringConfiguration(),
-    // which has only final members.
-    public String[] getTetherableUsbRegexs() {
-        return copy(mConfig.tetherableUsbRegexs);
-    }
-
-    public String[] getTetherableWifiRegexs() {
-        return copy(mConfig.tetherableWifiRegexs);
-    }
-
-    public String[] getTetherableBluetoothRegexs() {
-        return copy(mConfig.tetherableBluetoothRegexs);
-    }
-
-    public int setUsbTethering(boolean enable) {
-        if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")");
-        UsbManager usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
-        if (usbManager == null) {
-            mLog.e("setUsbTethering: failed to get UsbManager!");
-            return TETHER_ERROR_SERVICE_UNAVAIL;
-        }
-
-        synchronized (mPublicSync) {
-            usbManager.setCurrentFunctions(enable ? UsbManager.FUNCTION_RNDIS
-                    : UsbManager.FUNCTION_NONE);
-        }
-        return TETHER_ERROR_NO_ERROR;
-    }
-
-    // TODO review API - figure out how to delete these entirely.
-    public String[] getTetheredIfaces() {
-        ArrayList<String> list = new ArrayList<String>();
-        synchronized (mPublicSync) {
-            for (int i = 0; i < mTetherStates.size(); i++) {
-                TetherState tetherState = mTetherStates.valueAt(i);
-                if (tetherState.lastState == IpServer.STATE_TETHERED) {
-                    list.add(mTetherStates.keyAt(i));
-                }
-            }
-        }
-        return list.toArray(new String[list.size()]);
-    }
-
-    public String[] getTetherableIfaces() {
-        ArrayList<String> list = new ArrayList<String>();
-        synchronized (mPublicSync) {
-            for (int i = 0; i < mTetherStates.size(); i++) {
-                TetherState tetherState = mTetherStates.valueAt(i);
-                if (tetherState.lastState == IpServer.STATE_AVAILABLE) {
-                    list.add(mTetherStates.keyAt(i));
-                }
-            }
-        }
-        return list.toArray(new String[list.size()]);
-    }
-
-    public String[] getTetheredDhcpRanges() {
-        // TODO: this is only valid for the old DHCP server. Latest search suggests it is only used
-        // by WifiP2pServiceImpl to start dnsmasq: remove/deprecate after migrating callers.
-        return mConfig.legacyDhcpRanges;
-    }
-
-    public String[] getErroredIfaces() {
-        ArrayList<String> list = new ArrayList<String>();
-        synchronized (mPublicSync) {
-            for (int i = 0; i < mTetherStates.size(); i++) {
-                TetherState tetherState = mTetherStates.valueAt(i);
-                if (tetherState.lastError != TETHER_ERROR_NO_ERROR) {
-                    list.add(mTetherStates.keyAt(i));
-                }
-            }
-        }
-        return list.toArray(new String[list.size()]);
-    }
-
-    private void logMessage(State state, int what) {
-        mLog.log(state.getName() + " got " + sMagicDecoderRing.get(what, Integer.toString(what)));
-    }
-
-    private boolean upstreamWanted() {
-        if (!mForwardedDownstreams.isEmpty()) return true;
-
-        synchronized (mPublicSync) {
-            return mWifiTetherRequested;
-        }
-    }
-
-    // Needed because the canonical source of upstream truth is just the
-    // upstream interface set, |mCurrentUpstreamIfaceSet|.
-    private boolean pertainsToCurrentUpstream(NetworkState ns) {
-        if (ns != null && ns.linkProperties != null && mCurrentUpstreamIfaceSet != null) {
-            for (String ifname : ns.linkProperties.getAllInterfaceNames()) {
-                if (mCurrentUpstreamIfaceSet.ifnames.contains(ifname)) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    class TetherMasterSM extends StateMachine {
-        private static final int BASE_MASTER                    = Protocol.BASE_TETHERING;
-        // an interface SM has requested Tethering/Local Hotspot
-        static final int EVENT_IFACE_SERVING_STATE_ACTIVE       = BASE_MASTER + 1;
-        // an interface SM has unrequested Tethering/Local Hotspot
-        static final int EVENT_IFACE_SERVING_STATE_INACTIVE     = BASE_MASTER + 2;
-        // upstream connection change - do the right thing
-        static final int CMD_UPSTREAM_CHANGED                   = BASE_MASTER + 3;
-        // we don't have a valid upstream conn, check again after a delay
-        static final int CMD_RETRY_UPSTREAM                     = BASE_MASTER + 4;
-        // Events from NetworkCallbacks that we process on the master state
-        // machine thread on behalf of the UpstreamNetworkMonitor.
-        static final int EVENT_UPSTREAM_CALLBACK                = BASE_MASTER + 5;
-        // we treated the error and want now to clear it
-        static final int CMD_CLEAR_ERROR                        = BASE_MASTER + 6;
-        static final int EVENT_IFACE_UPDATE_LINKPROPERTIES      = BASE_MASTER + 7;
-        // Events from EntitlementManager to choose upstream again.
-        static final int EVENT_UPSTREAM_PERMISSION_CHANGED      = BASE_MASTER + 8;
-
-        private final State mInitialState;
-        private final State mTetherModeAliveState;
-
-        private final State mSetIpForwardingEnabledErrorState;
-        private final State mSetIpForwardingDisabledErrorState;
-        private final State mStartTetheringErrorState;
-        private final State mStopTetheringErrorState;
-        private final State mSetDnsForwardersErrorState;
-
-        // This list is a little subtle.  It contains all the interfaces that currently are
-        // requesting tethering, regardless of whether these interfaces are still members of
-        // mTetherStates.  This allows us to maintain the following predicates:
-        //
-        // 1) mTetherStates contains the set of all currently existing, tetherable, link state up
-        //    interfaces.
-        // 2) mNotifyList contains all state machines that may have outstanding tethering state
-        //    that needs to be torn down.
-        //
-        // Because we excise interfaces immediately from mTetherStates, we must maintain mNotifyList
-        // so that the garbage collector does not clean up the state machine before it has a chance
-        // to tear itself down.
-        private final ArrayList<IpServer> mNotifyList;
-        private final IPv6TetheringCoordinator mIPv6TetheringCoordinator;
-        private final OffloadWrapper mOffload;
-
-        private static final int UPSTREAM_SETTLE_TIME_MS     = 10000;
-
-        TetherMasterSM(String name, Looper looper, TetheringDependencies deps) {
-            super(name, looper);
-
-            mInitialState = new InitialState();
-            mTetherModeAliveState = new TetherModeAliveState();
-            mSetIpForwardingEnabledErrorState = new SetIpForwardingEnabledErrorState();
-            mSetIpForwardingDisabledErrorState = new SetIpForwardingDisabledErrorState();
-            mStartTetheringErrorState = new StartTetheringErrorState();
-            mStopTetheringErrorState = new StopTetheringErrorState();
-            mSetDnsForwardersErrorState = new SetDnsForwardersErrorState();
-
-            addState(mInitialState);
-            addState(mTetherModeAliveState);
-            addState(mSetIpForwardingEnabledErrorState);
-            addState(mSetIpForwardingDisabledErrorState);
-            addState(mStartTetheringErrorState);
-            addState(mStopTetheringErrorState);
-            addState(mSetDnsForwardersErrorState);
-
-            mNotifyList = new ArrayList<>();
-            mIPv6TetheringCoordinator = deps.getIPv6TetheringCoordinator(mNotifyList, mLog);
-            mOffload = new OffloadWrapper();
-
-            setInitialState(mInitialState);
-        }
-
-        class InitialState extends State {
-            @Override
-            public boolean processMessage(Message message) {
-                logMessage(this, message.what);
-                switch (message.what) {
-                    case EVENT_IFACE_SERVING_STATE_ACTIVE: {
-                        final IpServer who = (IpServer) message.obj;
-                        if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
-                        handleInterfaceServingStateActive(message.arg1, who);
-                        transitionTo(mTetherModeAliveState);
-                        break;
-                    }
-                    case EVENT_IFACE_SERVING_STATE_INACTIVE: {
-                        final IpServer who = (IpServer) message.obj;
-                        if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
-                        handleInterfaceServingStateInactive(who);
-                        break;
-                    }
-                    case EVENT_IFACE_UPDATE_LINKPROPERTIES:
-                        // Silently ignore these for now.
-                        break;
-                    default:
-                        return NOT_HANDLED;
-                }
-                return HANDLED;
-            }
-        }
-
-        protected boolean turnOnMasterTetherSettings() {
-            final TetheringConfiguration cfg = mConfig;
-            try {
-                mNMService.setIpForwardingEnabled(true);
-            } catch (Exception e) {
-                mLog.e(e);
-                transitionTo(mSetIpForwardingEnabledErrorState);
-                return false;
-            }
-            // TODO: Randomize DHCPv4 ranges, especially in hotspot mode.
-            // Legacy DHCP server is disabled if passed an empty ranges array
-            final String[] dhcpRanges = cfg.enableLegacyDhcpServer
-                    ? cfg.legacyDhcpRanges
-                    : new String[0];
-            try {
-                // TODO: Find a more accurate method name (startDHCPv4()?).
-                mNMService.startTethering(dhcpRanges);
-            } catch (Exception e) {
-                try {
-                    mNMService.stopTethering();
-                    mNMService.startTethering(dhcpRanges);
-                } catch (Exception ee) {
-                    mLog.e(ee);
-                    transitionTo(mStartTetheringErrorState);
-                    return false;
-                }
-            }
-            mLog.log("SET master tether settings: ON");
-            return true;
-        }
-
-        protected boolean turnOffMasterTetherSettings() {
-            try {
-                mNMService.stopTethering();
-            } catch (Exception e) {
-                mLog.e(e);
-                transitionTo(mStopTetheringErrorState);
-                return false;
-            }
-            try {
-                mNMService.setIpForwardingEnabled(false);
-            } catch (Exception e) {
-                mLog.e(e);
-                transitionTo(mSetIpForwardingDisabledErrorState);
-                return false;
-            }
-            transitionTo(mInitialState);
-            mLog.log("SET master tether settings: OFF");
-            return true;
-        }
-
-        protected void chooseUpstreamType(boolean tryCell) {
-            // We rebuild configuration on ACTION_CONFIGURATION_CHANGED, but we
-            // do not currently know how to watch for changes in DUN settings.
-            maybeDunSettingChanged();
-
-            final TetheringConfiguration config = mConfig;
-            final NetworkState ns = (config.chooseUpstreamAutomatically)
-                    ? mUpstreamNetworkMonitor.getCurrentPreferredUpstream()
-                    : mUpstreamNetworkMonitor.selectPreferredUpstreamType(
-                            config.preferredUpstreamIfaceTypes);
-            if (ns == null) {
-                if (tryCell) {
-                    mUpstreamNetworkMonitor.registerMobileNetworkRequest();
-                    // We think mobile should be coming up; don't set a retry.
-                } else {
-                    sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
-                }
-            }
-            setUpstreamNetwork(ns);
-            final Network newUpstream = (ns != null) ? ns.network : null;
-            if (mTetherUpstream != newUpstream) {
-                mTetherUpstream = newUpstream;
-                mUpstreamNetworkMonitor.setCurrentUpstream(mTetherUpstream);
-                reportUpstreamChanged(mTetherUpstream);
-            }
-        }
-
-        protected void setUpstreamNetwork(NetworkState ns) {
-            InterfaceSet ifaces = null;
-            if (ns != null) {
-                // Find the interface with the default IPv4 route. It may be the
-                // interface described by linkProperties, or one of the interfaces
-                // stacked on top of it.
-                mLog.i("Looking for default routes on: " + ns.linkProperties);
-                ifaces = TetheringInterfaceUtils.getTetheringInterfaces(ns);
-                mLog.i("Found upstream interface(s): " + ifaces);
-            }
-
-            if (ifaces != null) {
-                setDnsForwarders(ns.network, ns.linkProperties);
-            }
-            notifyDownstreamsOfNewUpstreamIface(ifaces);
-            if (ns != null && pertainsToCurrentUpstream(ns)) {
-                // If we already have NetworkState for this network update it immediately.
-                handleNewUpstreamNetworkState(ns);
-            } else if (mCurrentUpstreamIfaceSet == null) {
-                // There are no available upstream networks.
-                handleNewUpstreamNetworkState(null);
-            }
-        }
-
-        protected void setDnsForwarders(final Network network, final LinkProperties lp) {
-            // TODO: Set v4 and/or v6 DNS per available connectivity.
-            String[] dnsServers = mConfig.defaultIPv4DNS;
-            final Collection<InetAddress> dnses = lp.getDnsServers();
-            // TODO: Properly support the absence of DNS servers.
-            if (dnses != null && !dnses.isEmpty()) {
-                // TODO: remove this invocation of NetworkUtils.makeStrings().
-                dnsServers = NetworkUtils.makeStrings(dnses);
-            }
-            try {
-                mNMService.setDnsForwarders(network, dnsServers);
-                mLog.log(String.format(
-                        "SET DNS forwarders: network=%s dnsServers=%s",
-                        network, Arrays.toString(dnsServers)));
-            } catch (Exception e) {
-                // TODO: Investigate how this can fail and what exactly
-                // happens if/when such failures occur.
-                mLog.e("setting DNS forwarders failed, " + e);
-                transitionTo(mSetDnsForwardersErrorState);
-            }
-        }
-
-        protected void notifyDownstreamsOfNewUpstreamIface(InterfaceSet ifaces) {
-            mCurrentUpstreamIfaceSet = ifaces;
-            for (IpServer ipServer : mNotifyList) {
-                ipServer.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED, ifaces);
-            }
-        }
-
-        protected void handleNewUpstreamNetworkState(NetworkState ns) {
-            mIPv6TetheringCoordinator.updateUpstreamNetworkState(ns);
-            mOffload.updateUpstreamNetworkState(ns);
-        }
-
-        private void handleInterfaceServingStateActive(int mode, IpServer who) {
-            if (mNotifyList.indexOf(who) < 0) {
-                mNotifyList.add(who);
-                mIPv6TetheringCoordinator.addActiveDownstream(who, mode);
-            }
-
-            if (mode == IpServer.STATE_TETHERED) {
-                // No need to notify OffloadController just yet as there are no
-                // "offload-able" prefixes to pass along. This will handled
-                // when the TISM informs Tethering of its LinkProperties.
-                mForwardedDownstreams.add(who);
-            } else {
-                mOffload.excludeDownstreamInterface(who.interfaceName());
-                mForwardedDownstreams.remove(who);
-            }
-
-            // If this is a Wi-Fi interface, notify WifiManager of the active serving state.
-            if (who.interfaceType() == TETHERING_WIFI) {
-                final WifiManager mgr = getWifiManager();
-                final String iface = who.interfaceName();
-                switch (mode) {
-                    case IpServer.STATE_TETHERED:
-                        mgr.updateInterfaceIpState(iface, IFACE_IP_MODE_TETHERED);
-                        break;
-                    case IpServer.STATE_LOCAL_ONLY:
-                        mgr.updateInterfaceIpState(iface, IFACE_IP_MODE_LOCAL_ONLY);
-                        break;
-                    default:
-                        Log.wtf(TAG, "Unknown active serving mode: " + mode);
-                        break;
-                }
-            }
-        }
-
-        private void handleInterfaceServingStateInactive(IpServer who) {
-            mNotifyList.remove(who);
-            mIPv6TetheringCoordinator.removeActiveDownstream(who);
-            mOffload.excludeDownstreamInterface(who.interfaceName());
-            mForwardedDownstreams.remove(who);
-
-            // If this is a Wi-Fi interface, tell WifiManager of any errors
-            // or the inactive serving state.
-            if (who.interfaceType() == TETHERING_WIFI) {
-                if (who.lastError() != TETHER_ERROR_NO_ERROR) {
-                    getWifiManager().updateInterfaceIpState(
-                            who.interfaceName(), IFACE_IP_MODE_CONFIGURATION_ERROR);
-                } else {
-                    getWifiManager().updateInterfaceIpState(
-                            who.interfaceName(), IFACE_IP_MODE_UNSPECIFIED);
-                }
-            }
-        }
-
-        private void handleUpstreamNetworkMonitorCallback(int arg1, Object o) {
-            if (arg1 == UpstreamNetworkMonitor.NOTIFY_LOCAL_PREFIXES) {
-                mOffload.sendOffloadExemptPrefixes((Set<IpPrefix>) o);
-                return;
-            }
-
-            final NetworkState ns = (NetworkState) o;
-
-            if (ns == null || !pertainsToCurrentUpstream(ns)) {
-                // TODO: In future, this is where upstream evaluation and selection
-                // could be handled for notifications which include sufficient data.
-                // For example, after CONNECTIVITY_ACTION listening is removed, here
-                // is where we could observe a Wi-Fi network becoming available and
-                // passing validation.
-                if (mCurrentUpstreamIfaceSet == null) {
-                    // If we have no upstream interface, try to run through upstream
-                    // selection again.  If, for example, IPv4 connectivity has shown up
-                    // after IPv6 (e.g., 464xlat became available) we want the chance to
-                    // notice and act accordingly.
-                    chooseUpstreamType(false);
-                }
-                return;
-            }
-
-            switch (arg1) {
-                case UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES:
-                    handleNewUpstreamNetworkState(ns);
-                    break;
-                case UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES:
-                    chooseUpstreamType(false);
-                    break;
-                case UpstreamNetworkMonitor.EVENT_ON_LOST:
-                    // TODO: Re-evaluate possible upstreams. Currently upstream
-                    // reevaluation is triggered via received CONNECTIVITY_ACTION
-                    // broadcasts that result in being passed a
-                    // TetherMasterSM.CMD_UPSTREAM_CHANGED.
-                    handleNewUpstreamNetworkState(null);
-                    break;
-                default:
-                    mLog.e("Unknown arg1 value: " + arg1);
-                    break;
-            }
-        }
-
-        class TetherModeAliveState extends State {
-            boolean mUpstreamWanted = false;
-            boolean mTryCell = true;
-
-            @Override
-            public void enter() {
-                // If turning on master tether settings fails, we have already
-                // transitioned to an error state; exit early.
-                if (!turnOnMasterTetherSettings()) {
-                    return;
-                }
-
-                mUpstreamNetworkMonitor.startObserveAllNetworks();
-
-                // TODO: De-duplicate with updateUpstreamWanted() below.
-                if (upstreamWanted()) {
-                    mUpstreamWanted = true;
-                    mOffload.start();
-                    chooseUpstreamType(true);
-                    mTryCell = false;
-                }
-            }
-
-            @Override
-            public void exit() {
-                mOffload.stop();
-                mUpstreamNetworkMonitor.stop();
-                notifyDownstreamsOfNewUpstreamIface(null);
-                handleNewUpstreamNetworkState(null);
-                if (mTetherUpstream != null) {
-                    mTetherUpstream = null;
-                    reportUpstreamChanged(null);
-                }
-            }
-
-            private boolean updateUpstreamWanted() {
-                final boolean previousUpstreamWanted = mUpstreamWanted;
-                mUpstreamWanted = upstreamWanted();
-                if (mUpstreamWanted != previousUpstreamWanted) {
-                    if (mUpstreamWanted) {
-                        mOffload.start();
-                    } else {
-                        mOffload.stop();
-                    }
-                }
-                return previousUpstreamWanted;
-            }
-
-            @Override
-            public boolean processMessage(Message message) {
-                logMessage(this, message.what);
-                boolean retValue = true;
-                switch (message.what) {
-                    case EVENT_IFACE_SERVING_STATE_ACTIVE: {
-                        IpServer who = (IpServer) message.obj;
-                        if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
-                        handleInterfaceServingStateActive(message.arg1, who);
-                        who.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED,
-                                mCurrentUpstreamIfaceSet);
-                        // If there has been a change and an upstream is now
-                        // desired, kick off the selection process.
-                        final boolean previousUpstreamWanted = updateUpstreamWanted();
-                        if (!previousUpstreamWanted && mUpstreamWanted) {
-                            chooseUpstreamType(true);
-                        }
-                        break;
-                    }
-                    case EVENT_IFACE_SERVING_STATE_INACTIVE: {
-                        IpServer who = (IpServer) message.obj;
-                        if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
-                        handleInterfaceServingStateInactive(who);
-
-                        if (mNotifyList.isEmpty()) {
-                            // This transitions us out of TetherModeAliveState,
-                            // either to InitialState or an error state.
-                            turnOffMasterTetherSettings();
-                            break;
-                        }
-
-                        if (DBG) {
-                            Log.d(TAG, "TetherModeAlive still has " + mNotifyList.size() +
-                                    " live requests:");
-                            for (IpServer o : mNotifyList) {
-                                Log.d(TAG, "  " + o);
-                            }
-                        }
-                        // If there has been a change and an upstream is no
-                        // longer desired, release any mobile requests.
-                        final boolean previousUpstreamWanted = updateUpstreamWanted();
-                        if (previousUpstreamWanted && !mUpstreamWanted) {
-                            mUpstreamNetworkMonitor.releaseMobileNetworkRequest();
-                        }
-                        break;
-                    }
-                    case EVENT_IFACE_UPDATE_LINKPROPERTIES: {
-                        final LinkProperties newLp = (LinkProperties) message.obj;
-                        if (message.arg1 == IpServer.STATE_TETHERED) {
-                            mOffload.updateDownstreamLinkProperties(newLp);
-                        } else {
-                            mOffload.excludeDownstreamInterface(newLp.getInterfaceName());
-                        }
-                        break;
-                    }
-                    case EVENT_UPSTREAM_PERMISSION_CHANGED:
-                    case CMD_UPSTREAM_CHANGED:
-                        updateUpstreamWanted();
-                        if (!mUpstreamWanted) break;
-
-                        // Need to try DUN immediately if Wi-Fi goes down.
-                        chooseUpstreamType(true);
-                        mTryCell = false;
-                        break;
-                    case CMD_RETRY_UPSTREAM:
-                        updateUpstreamWanted();
-                        if (!mUpstreamWanted) break;
-
-                        chooseUpstreamType(mTryCell);
-                        mTryCell = !mTryCell;
-                        break;
-                    case EVENT_UPSTREAM_CALLBACK: {
-                        updateUpstreamWanted();
-                        if (mUpstreamWanted) {
-                            handleUpstreamNetworkMonitorCallback(message.arg1, message.obj);
-                        }
-                        break;
-                    }
-                    default:
-                        retValue = false;
-                        break;
-                }
-                return retValue;
-            }
-        }
-
-        class ErrorState extends State {
-            private int mErrorNotification;
-
-            @Override
-            public boolean processMessage(Message message) {
-                boolean retValue = true;
-                switch (message.what) {
-                    case EVENT_IFACE_SERVING_STATE_ACTIVE:
-                        IpServer who = (IpServer) message.obj;
-                        who.sendMessage(mErrorNotification);
-                        break;
-                    case CMD_CLEAR_ERROR:
-                        mErrorNotification = TETHER_ERROR_NO_ERROR;
-                        transitionTo(mInitialState);
-                        break;
-                    default:
-                       retValue = false;
-                }
-                return retValue;
-            }
-
-            void notify(int msgType) {
-                mErrorNotification = msgType;
-                for (IpServer ipServer : mNotifyList) {
-                    ipServer.sendMessage(msgType);
-                }
-            }
-
-        }
-
-        class SetIpForwardingEnabledErrorState extends ErrorState {
-            @Override
-            public void enter() {
-                Log.e(TAG, "Error in setIpForwardingEnabled");
-                notify(IpServer.CMD_IP_FORWARDING_ENABLE_ERROR);
-            }
-        }
-
-        class SetIpForwardingDisabledErrorState extends ErrorState {
-            @Override
-            public void enter() {
-                Log.e(TAG, "Error in setIpForwardingDisabled");
-                notify(IpServer.CMD_IP_FORWARDING_DISABLE_ERROR);
-            }
-        }
-
-        class StartTetheringErrorState extends ErrorState {
-            @Override
-            public void enter() {
-                Log.e(TAG, "Error in startTethering");
-                notify(IpServer.CMD_START_TETHERING_ERROR);
-                try {
-                    mNMService.setIpForwardingEnabled(false);
-                } catch (Exception e) {}
-            }
-        }
-
-        class StopTetheringErrorState extends ErrorState {
-            @Override
-            public void enter() {
-                Log.e(TAG, "Error in stopTethering");
-                notify(IpServer.CMD_STOP_TETHERING_ERROR);
-                try {
-                    mNMService.setIpForwardingEnabled(false);
-                } catch (Exception e) {}
-            }
-        }
-
-        class SetDnsForwardersErrorState extends ErrorState {
-            @Override
-            public void enter() {
-                Log.e(TAG, "Error in setDnsForwarders");
-                notify(IpServer.CMD_SET_DNS_FORWARDERS_ERROR);
-                try {
-                    mNMService.stopTethering();
-                } catch (Exception e) {}
-                try {
-                    mNMService.setIpForwardingEnabled(false);
-                } catch (Exception e) {}
-            }
-        }
-
-        // A wrapper class to handle multiple situations where several calls to
-        // the OffloadController need to happen together.
-        //
-        // TODO: This suggests that the interface between OffloadController and
-        // Tethering is in need of improvement. Refactor these calls into the
-        // OffloadController implementation.
-        class OffloadWrapper {
-            public void start() {
-                mOffloadController.start();
-                sendOffloadExemptPrefixes();
-            }
-
-            public void stop() {
-                mOffloadController.stop();
-            }
-
-            public void updateUpstreamNetworkState(NetworkState ns) {
-                mOffloadController.setUpstreamLinkProperties(
-                        (ns != null) ? ns.linkProperties : null);
-            }
-
-            public void updateDownstreamLinkProperties(LinkProperties newLp) {
-                // Update the list of offload-exempt prefixes before adding
-                // new prefixes on downstream interfaces to the offload HAL.
-                sendOffloadExemptPrefixes();
-                mOffloadController.notifyDownstreamLinkProperties(newLp);
-            }
-
-            public void excludeDownstreamInterface(String ifname) {
-                // This and other interfaces may be in local-only hotspot mode;
-                // resend all local prefixes to the OffloadController.
-                sendOffloadExemptPrefixes();
-                mOffloadController.removeDownstreamInterface(ifname);
-            }
-
-            public void sendOffloadExemptPrefixes() {
-                sendOffloadExemptPrefixes(mUpstreamNetworkMonitor.getLocalPrefixes());
-            }
-
-            public void sendOffloadExemptPrefixes(final Set<IpPrefix> localPrefixes) {
-                // Add in well-known minimum set.
-                PrefixUtils.addNonForwardablePrefixes(localPrefixes);
-                // Add tragically hardcoded prefixes.
-                localPrefixes.add(PrefixUtils.DEFAULT_WIFI_P2P_PREFIX);
-
-                // Maybe add prefixes or addresses for downstreams, depending on
-                // the IP serving mode of each.
-                for (IpServer ipServer : mNotifyList) {
-                    final LinkProperties lp = ipServer.linkProperties();
-
-                    switch (ipServer.servingMode()) {
-                        case IpServer.STATE_UNAVAILABLE:
-                        case IpServer.STATE_AVAILABLE:
-                            // No usable LinkProperties in these states.
-                            continue;
-                        case IpServer.STATE_TETHERED:
-                            // Only add IPv4 /32 and IPv6 /128 prefixes. The
-                            // directly-connected prefixes will be sent as
-                            // downstream "offload-able" prefixes.
-                            for (LinkAddress addr : lp.getAllLinkAddresses()) {
-                                final InetAddress ip = addr.getAddress();
-                                if (ip.isLinkLocalAddress()) continue;
-                                localPrefixes.add(PrefixUtils.ipAddressAsPrefix(ip));
-                            }
-                            break;
-                        case IpServer.STATE_LOCAL_ONLY:
-                            // Add prefixes covering all local IPs.
-                            localPrefixes.addAll(PrefixUtils.localPrefixesFrom(lp));
-                            break;
-                    }
-                }
-
-                mOffloadController.setLocalPrefixes(localPrefixes);
-            }
-        }
-    }
-
-    public void systemReady() {
-        mUpstreamNetworkMonitor.startTrackDefaultNetwork(mDeps.getDefaultNetworkRequest(),
-                mEntitlementMgr);
-    }
-
-    /** Get the latest value of the tethering entitlement check. */
-    public void getLatestTetheringEntitlementResult(int type, ResultReceiver receiver,
-            boolean showEntitlementUi) {
-        if (receiver != null) {
-            mEntitlementMgr.getLatestTetheringEntitlementResult(type, receiver, showEntitlementUi);
-        }
-    }
-
-    /** Register tethering event callback */
-    public void registerTetheringEventCallback(ITetheringEventCallback callback) {
-        mHandler.post(() -> {
-            try {
-                callback.onUpstreamChanged(mTetherUpstream);
-            } catch (RemoteException e) {
-                // Not really very much to do here.
-            }
-            mTetheringEventCallbacks.register(callback);
-        });
-    }
-
-    /** Unregister tethering event callback */
-    public void unregisterTetheringEventCallback(ITetheringEventCallback callback) {
-        mHandler.post(() -> {
-            mTetheringEventCallbacks.unregister(callback);
-        });
-    }
-
-    private void reportUpstreamChanged(Network network) {
-        final int length = mTetheringEventCallbacks.beginBroadcast();
-        try {
-            for (int i = 0; i < length; i++) {
-                try {
-                    mTetheringEventCallbacks.getBroadcastItem(i).onUpstreamChanged(network);
-                } catch (RemoteException e) {
-                    // Not really very much to do here.
-                }
-            }
-        } finally {
-            mTetheringEventCallbacks.finishBroadcast();
-        }
-    }
-
-    @Override
-    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
-        // Binder.java closes the resource for us.
-        @SuppressWarnings("resource")
-        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
-        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
-
-        pw.println("Tethering:");
-        pw.increaseIndent();
-
-        pw.println("Configuration:");
-        pw.increaseIndent();
-        final TetheringConfiguration cfg = mConfig;
-        cfg.dump(pw);
-        pw.decreaseIndent();
-
-        pw.println("Entitlement:");
-        pw.increaseIndent();
-        mEntitlementMgr.dump(pw);
-        pw.decreaseIndent();
-
-        synchronized (mPublicSync) {
-            pw.println("Tether state:");
-            pw.increaseIndent();
-            for (int i = 0; i < mTetherStates.size(); i++) {
-                final String iface = mTetherStates.keyAt(i);
-                final TetherState tetherState = mTetherStates.valueAt(i);
-                pw.print(iface + " - ");
-
-                switch (tetherState.lastState) {
-                    case IpServer.STATE_UNAVAILABLE:
-                        pw.print("UnavailableState");
-                        break;
-                    case IpServer.STATE_AVAILABLE:
-                        pw.print("AvailableState");
-                        break;
-                    case IpServer.STATE_TETHERED:
-                        pw.print("TetheredState");
-                        break;
-                    case IpServer.STATE_LOCAL_ONLY:
-                        pw.print("LocalHotspotState");
-                        break;
-                    default:
-                        pw.print("UnknownState");
-                        break;
-                }
-                pw.println(" - lastError = " + tetherState.lastError);
-            }
-            pw.println("Upstream wanted: " + upstreamWanted());
-            pw.println("Current upstream interface(s): " + mCurrentUpstreamIfaceSet);
-            pw.decreaseIndent();
-        }
-
-        pw.println("Hardware offload:");
-        pw.increaseIndent();
-        mOffloadController.dump(pw);
-        pw.decreaseIndent();
-
-        pw.println("Log:");
-        pw.increaseIndent();
-        if (argsContain(args, SHORT_ARG)) {
-            pw.println("<log removed for brevity>");
-        } else {
-            mLog.dump(fd, pw, args);
-        }
-        pw.decreaseIndent();
-
-        pw.decreaseIndent();
-    }
-
-    private static boolean argsContain(String[] args, String target) {
-        for (String arg : args) {
-            if (target.equals(arg)) return true;
-        }
-        return false;
-    }
-
-    private IpServer.Callback makeControlCallback() {
-        return new IpServer.Callback() {
-            @Override
-            public void updateInterfaceState(IpServer who, int state, int lastError) {
-                notifyInterfaceStateChange(who, state, lastError);
-            }
-
-            @Override
-            public void updateLinkProperties(IpServer who, LinkProperties newLp) {
-                notifyLinkPropertiesChanged(who, newLp);
-            }
-        };
-    }
-
-    // TODO: Move into TetherMasterSM.
-    private void notifyInterfaceStateChange(IpServer who, int state, int error) {
-        final String iface = who.interfaceName();
-        synchronized (mPublicSync) {
-            final TetherState tetherState = mTetherStates.get(iface);
-            if (tetherState != null && tetherState.ipServer.equals(who)) {
-                tetherState.lastState = state;
-                tetherState.lastError = error;
-            } else {
-                if (DBG) Log.d(TAG, "got notification from stale iface " + iface);
-            }
-        }
-
-        mLog.log(String.format("OBSERVED iface=%s state=%s error=%s", iface, state, error));
-
-        try {
-            // Notify that we're tethering (or not) this interface.
-            // This is how data saver for instance knows if the user explicitly
-            // turned on tethering (thus keeping us from being in data saver mode).
-            mPolicyManager.onTetheringChanged(iface, state == IpServer.STATE_TETHERED);
-        } catch (RemoteException e) {
-            // Not really very much we can do here.
-        }
-
-        // If TetherMasterSM is in ErrorState, TetherMasterSM stays there.
-        // Thus we give a chance for TetherMasterSM to recover to InitialState
-        // by sending CMD_CLEAR_ERROR
-        if (error == TETHER_ERROR_MASTER_ERROR) {
-            mTetherMasterSM.sendMessage(TetherMasterSM.CMD_CLEAR_ERROR, who);
-        }
-        int which;
-        switch (state) {
-            case IpServer.STATE_UNAVAILABLE:
-            case IpServer.STATE_AVAILABLE:
-                which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_INACTIVE;
-                break;
-            case IpServer.STATE_TETHERED:
-            case IpServer.STATE_LOCAL_ONLY:
-                which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_ACTIVE;
-                break;
-            default:
-                Log.wtf(TAG, "Unknown interface state: " + state);
-                return;
-        }
-        mTetherMasterSM.sendMessage(which, state, 0, who);
-        sendTetherStateChangedBroadcast();
-    }
-
-    private void notifyLinkPropertiesChanged(IpServer who, LinkProperties newLp) {
-        final String iface = who.interfaceName();
-        final int state;
-        synchronized (mPublicSync) {
-            final TetherState tetherState = mTetherStates.get(iface);
-            if (tetherState != null && tetherState.ipServer.equals(who)) {
-                state = tetherState.lastState;
-            } else {
-                mLog.log("got notification from stale iface " + iface);
-                return;
-            }
-        }
-
-        mLog.log(String.format(
-                "OBSERVED LinkProperties update iface=%s state=%s lp=%s",
-                iface, IpServer.getStateString(state), newLp));
-        final int which = TetherMasterSM.EVENT_IFACE_UPDATE_LINKPROPERTIES;
-        mTetherMasterSM.sendMessage(which, state, 0, newLp);
-    }
-
-    private void maybeTrackNewInterfaceLocked(final String iface) {
-        // If we don't care about this type of interface, ignore.
-        final int interfaceType = ifaceNameToType(iface);
-        if (interfaceType == TETHERING_INVALID) {
-            mLog.log(iface + " is not a tetherable iface, ignoring");
-            return;
-        }
-        maybeTrackNewInterfaceLocked(iface, interfaceType);
-    }
-
-    private void maybeTrackNewInterfaceLocked(final String iface, int interfaceType) {
-        // If we have already started a TISM for this interface, skip.
-        if (mTetherStates.containsKey(iface)) {
-            mLog.log("active iface (" + iface + ") reported as added, ignoring");
-            return;
-        }
-
-        mLog.log("adding TetheringInterfaceStateMachine for: " + iface);
-        final TetherState tetherState = new TetherState(
-                new IpServer(iface, mLooper, interfaceType, mLog, mNMService, mStatsService,
-                             makeControlCallback(), mConfig.enableLegacyDhcpServer,
-                             mDeps.getIpServerDependencies()));
-        mTetherStates.put(iface, tetherState);
-        tetherState.ipServer.start();
-    }
-
-    private void stopTrackingInterfaceLocked(final String iface) {
-        final TetherState tetherState = mTetherStates.get(iface);
-        if (tetherState == null) {
-            mLog.log("attempting to remove unknown iface (" + iface + "), ignoring");
-            return;
-        }
-        tetherState.ipServer.stop();
-        mLog.log("removing TetheringInterfaceStateMachine for: " + iface);
-        mTetherStates.remove(iface);
-    }
-
-    private static String[] copy(String[] strarray) {
-        return Arrays.copyOf(strarray, strarray.length);
-    }
-}
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
deleted file mode 100644
index 8186343..0000000
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity.tethering;
-
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkState;
-import android.net.RouteInfo;
-import android.net.ip.IpServer;
-import android.net.util.NetworkConstants;
-import android.net.util.SharedLog;
-import android.util.Log;
-
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.Random;
-
-
-/**
- * IPv6 tethering is rather different from IPv4 owing to the absence of NAT.
- * This coordinator is responsible for evaluating the dedicated prefixes
- * assigned to the device and deciding how to divvy them up among downstream
- * interfaces.
- *
- * @hide
- */
-public class IPv6TetheringCoordinator {
-    private static final String TAG = IPv6TetheringCoordinator.class.getSimpleName();
-    private static final boolean DBG = false;
-    private static final boolean VDBG = false;
-
-    private static class Downstream {
-        public final IpServer ipServer;
-        public final int mode;  // IpServer.STATE_*
-        // Used to append to a ULA /48, constructing a ULA /64 for local use.
-        public final short subnetId;
-
-        Downstream(IpServer ipServer, int mode, short subnetId) {
-            this.ipServer = ipServer;
-            this.mode = mode;
-            this.subnetId = subnetId;
-        }
-    }
-
-    private final ArrayList<IpServer> mNotifyList;
-    private final SharedLog mLog;
-    // NOTE: mActiveDownstreams is a list and not a hash data structure because
-    // we keep active downstreams in arrival order.  This is done so /64s can
-    // be parceled out on a "first come, first served" basis and a /64 used by
-    // a downstream that is no longer active can be redistributed to any next
-    // waiting active downstream (again, in arrival order).
-    private final LinkedList<Downstream> mActiveDownstreams;
-    private final byte[] mUniqueLocalPrefix;
-    private short mNextSubnetId;
-    private NetworkState mUpstreamNetworkState;
-
-    public IPv6TetheringCoordinator(ArrayList<IpServer> notifyList, SharedLog log) {
-        mNotifyList = notifyList;
-        mLog = log.forSubComponent(TAG);
-        mActiveDownstreams = new LinkedList<>();
-        mUniqueLocalPrefix = generateUniqueLocalPrefix();
-        mNextSubnetId = 0;
-    }
-
-    public void addActiveDownstream(IpServer downstream, int mode) {
-        if (findDownstream(downstream) == null) {
-            // Adding a new downstream appends it to the list. Adding a
-            // downstream a second time without first removing it has no effect.
-            // We never change the mode of a downstream except by first removing
-            // it and then re-adding it (with its new mode specified);
-            if (mActiveDownstreams.offer(new Downstream(downstream, mode, mNextSubnetId))) {
-                // Make sure subnet IDs are always positive. They are appended
-                // to a ULA /48 to make a ULA /64 for local use.
-                mNextSubnetId = (short) Math.max(0, mNextSubnetId + 1);
-            }
-            updateIPv6TetheringInterfaces();
-        }
-    }
-
-    public void removeActiveDownstream(IpServer downstream) {
-        stopIPv6TetheringOn(downstream);
-        if (mActiveDownstreams.remove(findDownstream(downstream))) {
-            updateIPv6TetheringInterfaces();
-        }
-
-        // When tethering is stopping we can reset the subnet counter.
-        if (mNotifyList.isEmpty()) {
-            if (!mActiveDownstreams.isEmpty()) {
-                Log.wtf(TAG, "Tethering notify list empty, IPv6 downstreams non-empty.");
-            }
-            mNextSubnetId = 0;
-        }
-    }
-
-    public void updateUpstreamNetworkState(NetworkState ns) {
-        if (VDBG) {
-            Log.d(TAG, "updateUpstreamNetworkState: " + toDebugString(ns));
-        }
-        if (TetheringInterfaceUtils.getIPv6Interface(ns) == null) {
-            stopIPv6TetheringOnAllInterfaces();
-            setUpstreamNetworkState(null);
-            return;
-        }
-
-        if (mUpstreamNetworkState != null &&
-            !ns.network.equals(mUpstreamNetworkState.network)) {
-            stopIPv6TetheringOnAllInterfaces();
-        }
-
-        setUpstreamNetworkState(ns);
-        updateIPv6TetheringInterfaces();
-    }
-
-    private void stopIPv6TetheringOnAllInterfaces() {
-        for (IpServer ipServer : mNotifyList) {
-            stopIPv6TetheringOn(ipServer);
-        }
-    }
-
-    private void setUpstreamNetworkState(NetworkState ns) {
-        if (ns == null) {
-            mUpstreamNetworkState = null;
-        } else {
-            // Make a deep copy of the parts we need.
-            mUpstreamNetworkState = new NetworkState(
-                    null,
-                    new LinkProperties(ns.linkProperties),
-                    new NetworkCapabilities(ns.networkCapabilities),
-                    new Network(ns.network),
-                    null,
-                    null);
-        }
-
-        mLog.log("setUpstreamNetworkState: " + toDebugString(mUpstreamNetworkState));
-    }
-
-    private void updateIPv6TetheringInterfaces() {
-        for (IpServer ipServer : mNotifyList) {
-            final LinkProperties lp = getInterfaceIPv6LinkProperties(ipServer);
-            ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, lp);
-            break;
-        }
-    }
-
-    private LinkProperties getInterfaceIPv6LinkProperties(IpServer ipServer) {
-        final Downstream ds = findDownstream(ipServer);
-        if (ds == null) return null;
-
-        if (ds.mode == IpServer.STATE_LOCAL_ONLY) {
-            // Build a Unique Locally-assigned Prefix configuration.
-            return getUniqueLocalConfig(mUniqueLocalPrefix, ds.subnetId);
-        }
-
-        // This downstream is in IpServer.STATE_TETHERED mode.
-        if (mUpstreamNetworkState == null || mUpstreamNetworkState.linkProperties == null) {
-            return null;
-        }
-
-        // NOTE: Here, in future, we would have policies to decide how to divvy
-        // up the available dedicated prefixes among downstream interfaces.
-        // At this time we have no such mechanism--we only support tethering
-        // IPv6 toward the oldest (first requested) active downstream.
-
-        final Downstream currentActive = mActiveDownstreams.peek();
-        if (currentActive != null && currentActive.ipServer == ipServer) {
-            final LinkProperties lp = getIPv6OnlyLinkProperties(
-                    mUpstreamNetworkState.linkProperties);
-            if (lp.hasIpv6DefaultRoute() && lp.hasGlobalIpv6Address()) {
-                return lp;
-            }
-        }
-
-        return null;
-    }
-
-    Downstream findDownstream(IpServer ipServer) {
-        for (Downstream ds : mActiveDownstreams) {
-            if (ds.ipServer == ipServer) return ds;
-        }
-        return null;
-    }
-
-    private static LinkProperties getIPv6OnlyLinkProperties(LinkProperties lp) {
-        final LinkProperties v6only = new LinkProperties();
-        if (lp == null) {
-            return v6only;
-        }
-
-        // NOTE: At this time we don't copy over any information about any
-        // stacked links. No current stacked link configuration has IPv6.
-
-        v6only.setInterfaceName(lp.getInterfaceName());
-
-        v6only.setMtu(lp.getMtu());
-
-        for (LinkAddress linkAddr : lp.getLinkAddresses()) {
-            if (linkAddr.isGlobalPreferred() && linkAddr.getPrefixLength() == 64) {
-                v6only.addLinkAddress(linkAddr);
-            }
-        }
-
-        for (RouteInfo routeInfo : lp.getRoutes()) {
-            final IpPrefix destination = routeInfo.getDestination();
-            if ((destination.getAddress() instanceof Inet6Address) &&
-                (destination.getPrefixLength() <= 64)) {
-                v6only.addRoute(routeInfo);
-            }
-        }
-
-        for (InetAddress dnsServer : lp.getDnsServers()) {
-            if (isIPv6GlobalAddress(dnsServer)) {
-                // For now we include ULAs.
-                v6only.addDnsServer(dnsServer);
-            }
-        }
-
-        v6only.setDomains(lp.getDomains());
-
-        return v6only;
-    }
-
-    // TODO: Delete this and switch to LinkAddress#isGlobalPreferred once we
-    // announce our own IPv6 address as DNS server.
-    private static boolean isIPv6GlobalAddress(InetAddress ip) {
-        return (ip instanceof Inet6Address) &&
-               !ip.isAnyLocalAddress() &&
-               !ip.isLoopbackAddress() &&
-               !ip.isLinkLocalAddress() &&
-               !ip.isSiteLocalAddress() &&
-               !ip.isMulticastAddress();
-    }
-
-    private static LinkProperties getUniqueLocalConfig(byte[] ulp, short subnetId) {
-        final LinkProperties lp = new LinkProperties();
-
-        final IpPrefix local48 = makeUniqueLocalPrefix(ulp, (short) 0, 48);
-        lp.addRoute(new RouteInfo(local48, null, null));
-
-        final IpPrefix local64 = makeUniqueLocalPrefix(ulp, subnetId, 64);
-        // Because this is a locally-generated ULA, we don't have an upstream
-        // address. But because the downstream IP address management code gets
-        // its prefix from the upstream's IP address, we create a fake one here.
-        lp.addLinkAddress(new LinkAddress(local64.getAddress(), 64));
-
-        lp.setMtu(NetworkConstants.ETHER_MTU);
-        return lp;
-    }
-
-    private static IpPrefix makeUniqueLocalPrefix(byte[] in6addr, short subnetId, int prefixlen) {
-        final byte[] bytes = Arrays.copyOf(in6addr, in6addr.length);
-        bytes[7] = (byte) (subnetId >> 8);
-        bytes[8] = (byte) subnetId;
-        return new IpPrefix(bytes, prefixlen);
-    }
-
-    // Generates a Unique Locally-assigned Prefix:
-    //
-    //     https://tools.ietf.org/html/rfc4193#section-3.1
-    //
-    // The result is a /48 that can be used for local-only communications.
-    private static byte[] generateUniqueLocalPrefix() {
-        final byte[] ulp = new byte[6];  // 6 = 48bits / 8bits/byte
-        (new Random()).nextBytes(ulp);
-
-        final byte[] in6addr = Arrays.copyOf(ulp, NetworkConstants.IPV6_ADDR_LEN);
-        in6addr[0] = (byte) 0xfd;  // fc00::/7 and L=1
-
-        return in6addr;
-    }
-
-    private static String toDebugString(NetworkState ns) {
-        if (ns == null) {
-            return "NetworkState{null}";
-        }
-        return String.format("NetworkState{%s, %s, %s}",
-                ns.network,
-                ns.networkCapabilities,
-                ns.linkProperties);
-    }
-
-    private static void stopIPv6TetheringOn(IpServer ipServer) {
-        ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null);
-    }
-}
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
deleted file mode 100644
index 4ad7ac4..0000000
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity.tethering;
-
-import android.content.Context;
-import android.net.NetworkRequest;
-import android.net.ip.IpServer;
-import android.net.util.SharedLog;
-import android.os.Handler;
-
-import com.android.internal.util.StateMachine;
-import com.android.server.connectivity.MockableSystemProperties;
-
-import java.util.ArrayList;
-
-
-/**
- * Capture tethering dependencies, for injection.
- *
- * @hide
- */
-public class TetheringDependencies {
-    /**
-     * Get a reference to the offload hardware interface to be used by tethering.
-     */
-    public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) {
-        return new OffloadHardwareInterface(h, log);
-    }
-
-    /**
-     * Get a reference to the UpstreamNetworkMonitor to be used by tethering.
-     */
-    public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx, StateMachine target,
-            SharedLog log, int what) {
-        return new UpstreamNetworkMonitor(ctx, target, log, what);
-    }
-
-    /**
-     * Get a reference to the IPv6TetheringCoordinator to be used by tethering.
-     */
-    public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
-            ArrayList<IpServer> notifyList, SharedLog log) {
-        return new IPv6TetheringCoordinator(notifyList, log);
-    }
-
-    /**
-     * Get dependencies to be used by IpServer.
-     */
-    public IpServer.Dependencies getIpServerDependencies() {
-        return new IpServer.Dependencies();
-    }
-
-    /**
-     * Indicates whether tethering is supported on the device.
-     */
-    public boolean isTetheringSupported() {
-        return true;
-    }
-
-    /**
-     * Get the NetworkRequest that should be fulfilled by the default network.
-     */
-    public NetworkRequest getDefaultNetworkRequest() {
-        return null;
-    }
-
-    /**
-     * Get a reference to the EntitlementManager to be used by tethering.
-     */
-    public EntitlementManager getEntitlementManager(Context ctx, StateMachine target,
-            SharedLog log, int what, MockableSystemProperties systemProperties) {
-        return new EntitlementManager(ctx, target, log, what, systemProperties);
-    }
-
-    /**
-     * Generate a new TetheringConfiguration according to input sub Id.
-     */
-    public TetheringConfiguration generateTetheringConfiguration(Context ctx, SharedLog log,
-            int subId) {
-        return new TetheringConfiguration(ctx, log, subId);
-    }
-}
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 9882f6c..7ce63c5 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -138,13 +138,17 @@
     }
 
     /**
-     * Sets the display modes the system is allowed to switch between, roughly ordered by
-     * preference.
+     * Sets the refresh ranges, and display modes that the system is allowed to switch between.
+     * Display modes are roughly ordered by preference.
      *
      * Not all display devices will automatically switch between modes, so it's important that the
      * most-desired modes are at the beginning of the allowed array.
+     *
+     * @param defaultModeId is used, if the device does not support multiple refresh
+     * rates, and to navigate other parameters.
      */
-    public void setAllowedDisplayModesLocked(int[] modes) {
+    public void setDesiredDisplayConfigSpecs(int defaultModeId, float minRefreshRate,
+            float maxRefreshRate, int[] modes) {
     }
 
     /**
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index c466640..d20191d 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -431,7 +431,7 @@
             recordTopInsetLocked(mLogicalDisplays.get(Display.DEFAULT_DISPLAY));
         }
 
-        mDisplayModeDirector.setListener(new AllowedDisplayModeObserver());
+        mDisplayModeDirector.setDisplayModeListener(new AllowedDisplayModeObserver());
         mDisplayModeDirector.start(mSensorManager);
 
         mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
@@ -2488,7 +2488,7 @@
 
     }
 
-    class AllowedDisplayModeObserver implements DisplayModeDirector.Listener {
+    class AllowedDisplayModeObserver implements DisplayModeDirector.DisplayModeListener {
         public void onAllowedDisplayModesChanged() {
             onAllowedDisplayModesChangedInternal();
         }
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index d24bd1a..2df682f 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -18,26 +18,22 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.res.Resources;
 import android.database.ContentObserver;
-import android.hardware.display.DisplayManager;
 import android.hardware.Sensor;
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
-
+import android.hardware.display.DisplayManager;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.os.UserHandle;
 import android.os.PowerManager;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.text.TextUtils;
@@ -47,11 +43,11 @@
 import android.view.Display;
 import android.view.DisplayInfo;
 
-import com.android.internal.os.BackgroundThread;
 import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
 import com.android.server.display.utils.AmbientFilter;
 import com.android.server.display.utils.AmbientFilterFactory;
-import com.android.server.display.whitebalance.DisplayWhiteBalanceFactory;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -87,11 +83,11 @@
     // A map from the display ID to the collection of votes and their priority. The latter takes
     // the form of another map from the priority to the vote itself so that each priority is
     // guaranteed to have exactly one vote, which is also easily and efficiently replaceable.
-    private final SparseArray<SparseArray<Vote>> mVotesByDisplay;
+    private SparseArray<SparseArray<Vote>> mVotesByDisplay;
     // A map from the display ID to the supported modes on that display.
-    private final SparseArray<Display.Mode[]> mSupportedModesByDisplay;
+    private SparseArray<Display.Mode[]> mSupportedModesByDisplay;
     // A map from the display ID to the default mode of that display.
-    private final SparseArray<Display.Mode> mDefaultModeByDisplay;
+    private SparseArray<Display.Mode> mDefaultModeByDisplay;
 
     private final AppRequestObserver mAppRequestObserver;
     private final SettingsObserver mSettingsObserver;
@@ -99,7 +95,7 @@
     private final BrightnessObserver mBrightnessObserver;
 
     private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
-    private Listener mListener;
+    private DisplayModeListener mDisplayModeListener;
 
     public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler) {
         mContext = context;
@@ -143,17 +139,7 @@
      */
     @NonNull
     public int[] getAllowedModes(int displayId) {
-        synchronized (mLock) {
-            SparseArray<Vote> votes = getVotesLocked(displayId);
-            Display.Mode[] modes = mSupportedModesByDisplay.get(displayId);
-            Display.Mode defaultMode = mDefaultModeByDisplay.get(displayId);
-            if (modes == null || defaultMode == null) {
-                Slog.e(TAG, "Asked about unknown display, returning empty allowed set! (id="
-                        + displayId + ")");
-                return new int[0];
-            }
-            return getAllowedModesLocked(votes, modes, defaultMode);
-        }
+        return getDesiredDisplayConfigSpecs(displayId).allowedConfigs;
     }
 
     @NonNull
@@ -178,76 +164,101 @@
         return votes;
     }
 
+    /**
+     * Calculates the refresh rate ranges and display modes that the system is allowed to freely
+     * switch between based on global and display-specific constraints.
+     *
+     * @param displayId The display to query for.
+     * @return The ID of the default mode the system should use, and the refresh rate range the
+     * system is allowed to switch between.
+     */
     @NonNull
-    private int[] getAllowedModesLocked(@NonNull SparseArray<Vote> votes,
-            @NonNull Display.Mode[] modes, @NonNull Display.Mode defaultMode) {
-        int lowestConsideredPriority = Vote.MIN_PRIORITY;
-        while (lowestConsideredPriority <= Vote.MAX_PRIORITY) {
+    public DesiredDisplayConfigSpecs getDesiredDisplayConfigSpecs(int displayId) {
+        synchronized (mLock) {
+            SparseArray<Vote> votes = getVotesLocked(displayId);
+            Display.Mode[] modes = mSupportedModesByDisplay.get(displayId);
+            Display.Mode defaultMode = mDefaultModeByDisplay.get(displayId);
+            if (modes == null || defaultMode == null) {
+                Slog.e(TAG, "Asked about unknown display, returning empty desired configs!"
+                        + "(id=" + displayId + ")");
+                return new DesiredDisplayConfigSpecs(displayId, new RefreshRateRange(60, 60),
+                        new int[0]);
+            }
+
+            int[] availableModes = new int[]{defaultMode.getModeId()};
             float minRefreshRate = 0f;
             float maxRefreshRate = Float.POSITIVE_INFINITY;
-            int height = Vote.INVALID_SIZE;
-            int width = Vote.INVALID_SIZE;
+            int lowestConsideredPriority = Vote.MIN_PRIORITY;
+            while (lowestConsideredPriority <= Vote.MAX_PRIORITY) {
+                int height = Vote.INVALID_SIZE;
+                int width = Vote.INVALID_SIZE;
 
-            for (int priority = Vote.MAX_PRIORITY;
-                    priority >= lowestConsideredPriority;
-                    priority--) {
-                Vote vote = votes.get(priority);
-                if (vote == null) {
-                    continue;
+                for (int priority = Vote.MAX_PRIORITY;
+                        priority >= lowestConsideredPriority; priority--) {
+                    Vote vote = votes.get(priority);
+                    if (vote == null) {
+                        continue;
+                    }
+                    // For refresh rates, just use the tightest bounds of all the votes
+                    minRefreshRate = Math.max(minRefreshRate, vote.refreshRateRange.min);
+                    maxRefreshRate = Math.min(maxRefreshRate, vote.refreshRateRange.max);
+                    // For display size, use only the first vote we come across (i.e. the highest
+                    // priority vote that includes the width / height).
+                    if (height == Vote.INVALID_SIZE && width == Vote.INVALID_SIZE
+                            && vote.height > 0 && vote.width > 0) {
+                        width = vote.width;
+                        height = vote.height;
+                    }
                 }
-                // For refresh rates, just use the tightest bounds of all the votes
-                minRefreshRate = Math.max(minRefreshRate, vote.minRefreshRate);
-                maxRefreshRate = Math.min(maxRefreshRate, vote.maxRefreshRate);
-                // For display size, use only the first vote we come across (i.e. the highest
-                // priority vote that includes the width / height).
-                if (height == Vote.INVALID_SIZE && width == Vote.INVALID_SIZE
-                        && vote.height > 0 && vote.width > 0) {
-                    width = vote.width;
-                    height = vote.height;
+
+                // If we don't have anything specifying the width / height of the display, just use
+                // the default width and height. We don't want these switching out from underneath
+                // us since it's a pretty disruptive behavior.
+                if (height == Vote.INVALID_SIZE || width == Vote.INVALID_SIZE) {
+                    width = defaultMode.getPhysicalWidth();
+                    height = defaultMode.getPhysicalHeight();
                 }
-            }
 
-            // If we don't have anything specifying the width / height of the display, just use the
-            // default width and height. We don't want these switching out from underneath us since
-            // it's a pretty disruptive behavior.
-            if (height == Vote.INVALID_SIZE || width == Vote.INVALID_SIZE) {
-                width = defaultMode.getPhysicalWidth();
-                height = defaultMode.getPhysicalHeight();
-            }
+                availableModes = filterModes(modes, width, height, minRefreshRate, maxRefreshRate);
+                if (availableModes.length > 0) {
+                    if (DEBUG) {
+                        Slog.w(TAG, "Found available modes=" + Arrays.toString(availableModes)
+                                + " with lowest priority considered "
+                                + Vote.priorityToString(lowestConsideredPriority)
+                                + " and constraints: "
+                                + "width=" + width
+                                + ", height=" + height
+                                + ", minRefreshRate=" + minRefreshRate
+                                + ", maxRefreshRate=" + maxRefreshRate);
+                    }
+                    break;
+                }
 
-            int[] availableModes =
-                    filterModes(modes, width, height, minRefreshRate, maxRefreshRate);
-            if (availableModes.length > 0) {
                 if (DEBUG) {
-                    Slog.w(TAG, "Found available modes=" + Arrays.toString(availableModes)
-                            + " with lowest priority considered "
+                    Slog.w(TAG, "Couldn't find available modes with lowest priority set to "
                             + Vote.priorityToString(lowestConsideredPriority)
-                            + " and constraints: "
+                            + " and with the following constraints: "
                             + "width=" + width
                             + ", height=" + height
                             + ", minRefreshRate=" + minRefreshRate
                             + ", maxRefreshRate=" + maxRefreshRate);
                 }
-                return availableModes;
+
+                // If we haven't found anything with the current set of votes, drop the
+                // current lowest priority vote.
+                lowestConsideredPriority++;
             }
 
-            if (DEBUG) {
-                Slog.w(TAG, "Couldn't find available modes with lowest priority set to "
-                        + Vote.priorityToString(lowestConsideredPriority)
-                        + " and with the following constraints: "
-                        + "width=" + width
-                        + ", height=" + height
-                        + ", minRefreshRate=" + minRefreshRate
-                        + ", maxRefreshRate=" + maxRefreshRate);
+            int defaultModeId = defaultMode.getModeId();
+            if (availableModes.length > 0) {
+                defaultModeId = availableModes[0];
             }
-            // If we haven't found anything with the current set of votes, drop the current lowest
-            // priority vote.
-            lowestConsideredPriority++;
+            // filterModes function is going to filter the modes based on the voting system. If
+            // the application requests a given mode with preferredModeId function, it will be
+            // stored as the first and only element in available modes array.
+            return new DesiredDisplayConfigSpecs(defaultModeId,
+                    new RefreshRateRange(minRefreshRate, maxRefreshRate), availableModes);
         }
-
-        // If we still haven't found anything that matches our current set of votes, just fall back
-        // to the default mode.
-        return new int[] { defaultMode.getModeId() };
     }
 
     private int[] filterModes(Display.Mode[] supportedModes,
@@ -300,11 +311,11 @@
     }
 
     /**
-     * Sets the listener for changes to allowed display modes.
+     * Sets the modeListener for changes to allowed display modes.
      */
-    public void setListener(@Nullable Listener listener) {
+    public void setDisplayModeListener(@Nullable DisplayModeListener displayModeListener) {
         synchronized (mLock) {
-            mListener = listener;
+            mDisplayModeListener = displayModeListener;
         }
     }
 
@@ -382,12 +393,12 @@
     }
 
     private void notifyAllowedModesChangedLocked() {
-        if (mListener != null && !mHandler.hasMessages(MSG_ALLOWED_MODES_CHANGED)) {
+        if (mDisplayModeListener != null && !mHandler.hasMessages(MSG_ALLOWED_MODES_CHANGED)) {
             // We need to post this to a handler to avoid calling out while holding the lock
             // since we know there are things that both listen for changes as well as provide
             // information. If we did call out while holding the lock, then there's no guaranteed
             // lock order and we run the real of risk deadlock.
-            Message msg = mHandler.obtainMessage(MSG_ALLOWED_MODES_CHANGED, mListener);
+            Message msg = mHandler.obtainMessage(MSG_ALLOWED_MODES_CHANGED, mDisplayModeListener);
             msg.sendToTarget();
         }
     }
@@ -403,10 +414,25 @@
         }
     }
 
+    @VisibleForTesting
+    void injectSupportedModesByDisplay(SparseArray<Display.Mode[]> supportedModesByDisplay) {
+        mSupportedModesByDisplay = supportedModesByDisplay;
+    }
+
+    @VisibleForTesting
+    void injectDefaultModeByDisplay(SparseArray<Display.Mode> defaultModeByDisplay) {
+        mDefaultModeByDisplay = defaultModeByDisplay;
+    }
+
+    @VisibleForTesting
+    void injectVotesByDisplay(SparseArray<SparseArray<Vote>> votesByDisplay) {
+        mVotesByDisplay = votesByDisplay;
+    }
+
     /**
      * Listens for changes to display mode coordination.
      */
-    public interface Listener {
+    public interface DisplayModeListener {
         /**
          * Called when the allowed display modes may have changed.
          */
@@ -422,8 +448,8 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_ALLOWED_MODES_CHANGED:
-                    Listener listener = (Listener) msg.obj;
-                    listener.onAllowedDisplayModesChanged();
+                    DisplayModeListener displayModeListener = (DisplayModeListener) msg.obj;
+                    displayModeListener.onAllowedDisplayModesChanged();
                     break;
 
                 case MSG_BRIGHTNESS_THRESHOLDS_CHANGED:
@@ -452,7 +478,129 @@
         }
     }
 
-    private static final class Vote {
+    /**
+     * Information about the min and max refresh rate DM would like to set the display to.
+     */
+    public static final class RefreshRateRange {
+        /**
+         * The lowest desired refresh rate.
+         */
+        public final float min;
+        /**
+         * The highest desired refresh rate.
+         */
+        public final float max;
+
+        public RefreshRateRange(float min, float max) {
+            if (min < 0 || max < 0 || min > max) {
+                Slog.e(TAG, "Wrong values for min and max when initializing RefreshRateRange : "
+                        + min + " " + max);
+                this.min = this.max = 0;
+                return;
+            }
+            this.min = min;
+            this.max = max;
+        }
+
+        /**
+         * Checks whether the two objects have the same values.
+         */
+        @Override
+        public boolean equals(Object other) {
+            if (other == this) {
+                return true;
+            }
+
+            if (!(other instanceof RefreshRateRange)) {
+                return false;
+            }
+
+            RefreshRateRange refreshRateRange = (RefreshRateRange) other;
+            return (min == refreshRateRange.min && max == refreshRateRange.max);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(min, max);
+        }
+
+        @Override
+        public String toString() {
+            return "(" + min + " " + max + ")";
+        }
+    }
+
+    /**
+     * Information about the desired configuration to be set by the system. Includes the default
+     * configuration ID, refresh rate range, and the list of policy decisions that influenced the
+     * choice.
+     */
+    public static final class DesiredDisplayConfigSpecs {
+        /**
+         * Default configuration ID. This is what system defaults to for all other settings, or
+         * if the refresh rate range is not available.
+         */
+        public final int defaultModeId;
+        /**
+         * The refresh rate range.
+         */
+        public final RefreshRateRange refreshRateRange;
+        /**
+         * For legacy reasons, keep a list of allowed configs.
+         * TODO(b/142507213): Re-assess whether the list of allowed configs is still necessary.
+         */
+        public final int[] allowedConfigs;
+
+        public DesiredDisplayConfigSpecs(int defaultModeId,
+                @NonNull RefreshRateRange refreshRateRange,
+                @NonNull int[] allowedConfigs) {
+            this.defaultModeId = defaultModeId;
+            this.refreshRateRange = refreshRateRange;
+            this.allowedConfigs = allowedConfigs;
+        }
+
+        /**
+         * Returns a string representation of the object.
+         */
+        @Override
+        public String toString() {
+            return "DesiredDisplayConfigSpecs(defaultModeId=" + defaultModeId
+                    + ", refreshRateRange=" + refreshRateRange.toString()
+                    + ", allowedConfigs=" + Arrays.toString(allowedConfigs) + ")";
+        }
+        /**
+         * Checks whether the two objects have the same values.
+         */
+        @Override
+        public boolean equals(Object other) {
+            if (other == this) {
+                return true;
+            }
+
+            if (!(other instanceof DesiredDisplayConfigSpecs)) {
+                return false;
+            }
+
+            DesiredDisplayConfigSpecs desiredDisplayConfigSpecs =
+                    (DesiredDisplayConfigSpecs) other;
+
+            if (defaultModeId != desiredDisplayConfigSpecs.defaultModeId) {
+                return false;
+            }
+            if (!refreshRateRange.equals(desiredDisplayConfigSpecs.refreshRateRange)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(defaultModeId, refreshRateRange);
+        }
+    }
+
+    @VisibleForTesting
+    static final class Vote {
         // LOW_BRIGHTNESS votes for a single refresh rate like [60,60], [90,90] or null.
         // If the higher voters result is a range, it will fix the rate to a single choice.
         // It's used to avoid rate switch in certain conditions.
@@ -499,15 +647,10 @@
          * The requested height of the display in pixels, or INVALID_SIZE;
          */
         public final int height;
-
         /**
-         * The lowest desired refresh rate.
+         * Information about the min and max refresh rate DM would like to set the display to.
          */
-        public final float minRefreshRate;
-        /**
-         * The highest desired refresh rate.
-         */
-        public final float maxRefreshRate;
+        public final RefreshRateRange refreshRateRange;
 
         public static Vote forRefreshRates(float minRefreshRate, float maxRefreshRate) {
             return new Vote(INVALID_SIZE, INVALID_SIZE, minRefreshRate, maxRefreshRate);
@@ -521,8 +664,8 @@
                 float minRefreshRate, float maxRefreshRate) {
             this.width = width;
             this.height = height;
-            this.minRefreshRate = minRefreshRate;
-            this.maxRefreshRate = maxRefreshRate;
+            this.refreshRateRange =
+                    new RefreshRateRange(minRefreshRate, maxRefreshRate);
         }
 
         public static String priorityToString(int priority) {
@@ -547,11 +690,9 @@
         @Override
         public String toString() {
             return "Vote{"
-                + "width=" + width
-                + ", height=" + height
-                + ", minRefreshRate=" + minRefreshRate
-                + ", maxRefreshRate=" + maxRefreshRate
-                + "}";
+                + "width=" + width + ", height=" + height
+                + ", minRefreshRate=" + refreshRateRange.min
+                + ", maxRefreshRate=" + refreshRateRange.max + "}";
         }
     }
 
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index b03dc3b..1d7c942 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -173,6 +173,8 @@
         private int mActiveModeId;
         private boolean mActiveModeInvalid;
         private int[] mAllowedModeIds;
+        private float mMinRefreshRate;
+        private float mMaxRefreshRate;
         private boolean mAllowedModeIdsInvalid;
         private int mActivePhysIndex;
         private int[] mAllowedPhysIndexes;
@@ -623,7 +625,9 @@
         }
 
         @Override
-        public void setAllowedDisplayModesLocked(int[] modes) {
+        public void setDesiredDisplayConfigSpecs(int defaultModeId, float minRefreshRate,
+                float maxRefreshRate, int[] modes) {
+            updateDesiredDisplayConfigSpecs(defaultModeId, minRefreshRate, maxRefreshRate);
             updateAllowedModesLocked(modes);
         }
 
@@ -653,6 +657,7 @@
             return true;
         }
 
+        // TODO(b/142507213): Remove once refresh rates are plummed through to kernel.
         public void updateAllowedModesLocked(int[] allowedModes) {
             if (Arrays.equals(allowedModes, mAllowedModeIds) && !mAllowedModeIdsInvalid) {
                 return;
@@ -662,6 +667,39 @@
             }
         }
 
+        public void updateDesiredDisplayConfigSpecs(int defaultModeId, float minRefreshRate,
+                float maxRefreshRate) {
+            if (minRefreshRate == mMinRefreshRate
+                        && maxRefreshRate == mMaxRefreshRate
+                        && defaultModeId == mDefaultModeId) {
+                return;
+            }
+            if (updateDesiredDisplayConfigSpecsInternalLocked(defaultModeId, minRefreshRate,
+                    maxRefreshRate)) {
+                updateDeviceInfoLocked();
+            }
+        }
+
+        public boolean updateDesiredDisplayConfigSpecsInternalLocked(int defaultModeId,
+                float minRefreshRate, float maxRefreshRate) {
+            if (DEBUG) {
+                Slog.w(TAG, "updateDesiredDisplayConfigSpecsInternalLocked("
+                        + "defaultModeId="
+                        + Integer.toString(defaultModeId)
+                        + ", minRefreshRate="
+                        + Float.toString(minRefreshRate)
+                        + ", maxRefreshRate="
+                        + Float.toString(minRefreshRate));
+            }
+
+            final IBinder token = getDisplayTokenLocked();
+            SurfaceControl.setDesiredDisplayConfigSpecs(token,
+                    new SurfaceControl.DesiredDisplayConfigSpecs(
+                            defaultModeId, minRefreshRate, maxRefreshRate));
+            int activePhysIndex = SurfaceControl.getActiveConfig(token);
+            return updateActiveModeLocked(activePhysIndex);
+        }
+
         public boolean updateAllowedModesInternalLocked(int[] allowedModes) {
             if (DEBUG) {
                 Slog.w(TAG, "updateAllowedModesInternalLocked(allowedModes="
@@ -735,6 +773,8 @@
             pw.println("mPhysicalDisplayId=" + mPhysicalDisplayId);
             pw.println("mAllowedPhysIndexes=" + Arrays.toString(mAllowedPhysIndexes));
             pw.println("mAllowedModeIds=" + Arrays.toString(mAllowedModeIds));
+            pw.println("mMinRefreshRate=" + mMinRefreshRate);
+            pw.println("mMaxRefreshRate=" + mMaxRefreshRate);
             pw.println("mAllowedModeIdsInvalid=" + mAllowedModeIdsInvalid);
             pw.println("mActivePhysIndex=" + mActivePhysIndex);
             pw.println("mActiveModeId=" + mActiveModeId);
@@ -808,7 +848,7 @@
             int[] ports = res.getIntArray(
                     com.android.internal.R.array.config_localPrivateDisplayPorts);
             if (ports != null) {
-                int port = physicalAddress.getPort();
+                int port = Byte.toUnsignedInt(physicalAddress.getPort());
                 for (int p : ports) {
                     if (p == port) {
                         return true;
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index dcef998..f4b2dc8 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -352,11 +352,12 @@
 
         // Set the color mode and allowed display mode.
         if (device == mPrimaryDisplayDevice) {
-            device.setAllowedDisplayModesLocked(mAllowedDisplayModes);
+            // See ag/9588196 for correct values.
+            device.setDesiredDisplayConfigSpecs(0, 60, 60, mAllowedDisplayModes);
             device.setRequestedColorModeLocked(mRequestedColorMode);
         } else {
             // Reset to default for non primary displays
-            device.setAllowedDisplayModesLocked(new int[] {0});
+            device.setDesiredDisplayConfigSpecs(0, 60, 60, new int[] {0});
             device.setRequestedColorModeLocked(0);
         }
 
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 60cfbd0..739dd64 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -315,16 +315,9 @@
         }
 
         @Override
-        public void setAllowedDisplayModesLocked(int[] modes) {
-            final int id;
-            if (modes.length > 0) {
-                // The allowed modes should be ordered by preference, so just use the first mode
-                // here.
-                id = modes[0];
-            } else {
-                // If we don't have any allowed modes, just use the default mode.
-                id = 0;
-            }
+        public void setDesiredDisplayConfigSpecs(int defaultModeId, float minRefreshRate,
+                float maxRefreshRate, int[] modes) {
+            final int id = defaultModeId;
             int index = -1;
             if (id == 0) {
                 // Use the default.
diff --git a/services/core/java/com/android/server/display/WifiDisplayController.java b/services/core/java/com/android/server/display/WifiDisplayController.java
index 283a78b..2992f1e 100644
--- a/services/core/java/com/android/server/display/WifiDisplayController.java
+++ b/services/core/java/com/android/server/display/WifiDisplayController.java
@@ -508,8 +508,7 @@
                 Slog.d(TAG, "updateDesiredDevice: new information "
                         + describeWifiP2pDevice(device));
             }
-            mDesiredDevice.updateSupplicantDetails(device);
-            mDesiredDevice.status = device.status;
+            mDesiredDevice.update(device);
             if (mAdvertisedDisplay != null
                     && mAdvertisedDisplay.getDeviceAddress().equals(address)) {
                 readvertiseDisplay(createWifiDisplay(mDesiredDevice));
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 9a85f952..a702ce5 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -1557,6 +1557,18 @@
         if (!connected) {
             removeCecSwitches(portId);
         }
+
+        // Turning System Audio Mode off when the AVR is unlugged or standby.
+        // When the device is not unplugged but reawaken from standby, we check if the System
+        // Audio Control Feature is enabled or not then decide if turning SAM on/off accordingly.
+        if (getAvrDeviceInfo() != null && portId == getAvrDeviceInfo().getPortId()) {
+            if (!connected) {
+                setSystemAudioMode(false);
+            } else if (mSystemAudioControlFeatureEnabled != mService.isSystemAudioActivated()){
+                setSystemAudioMode(mSystemAudioControlFeatureEnabled);
+            }
+        }
+
         // Tv device will have permanent HotplugDetectionAction.
         List<HotplugDetectionAction> hotplugActions = getActions(HotplugDetectionAction.class);
         if (!hotplugActions.isEmpty()) {
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 67a23dd..16b7d99 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -171,7 +171,6 @@
     private final ArrayList<InputDevice>
             mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only
     private boolean mKeyboardLayoutNotificationShown;
-    private PendingIntent mKeyboardLayoutIntent;
     private Toast mSwitchedKeyboardLayoutToast;
 
     // State for vibrator tokens.
@@ -205,6 +204,7 @@
     private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel);
     private static native void nativePilferPointers(long ptr, IBinder token);
     private static native void nativeSetInputFilterEnabled(long ptr, boolean enable);
+    private static native void nativeSetInTouchMode(long ptr, boolean inTouchMode);
     private static native int nativeInjectInputEvent(long ptr, InputEvent event,
             int injectorPid, int injectorUid, int syncMode, int timeoutMillis,
             int policyFlags);
@@ -603,6 +603,25 @@
         }
     }
 
+    /**
+     * Set the state of the touch mode.
+     *
+     * WindowManager remains the source of truth of the touch mode state.
+     * However, we need to keep a copy of this state in input.
+     *
+     * The apps determine the touch mode state. Therefore, a single app will
+     * affect the global state. That state change needs to be propagated to
+     * other apps, when they become focused.
+     *
+     * When input dispatches focus to the apps, the touch mode state
+     * will be sent together with the focus change.
+     *
+     * @param inTouchMode true if the device is in touch mode.
+     */
+    public void setInTouchMode(boolean inTouchMode) {
+        nativeSetInTouchMode(mPtr, inTouchMode);
+    }
+
     @Override // Binder call
     public boolean injectInputEvent(InputEvent event, int mode) {
         return injectInputEventInternal(event, mode);
diff --git a/services/core/java/com/android/server/integrity/model/BitInputStream.java b/services/core/java/com/android/server/integrity/model/BitInputStream.java
new file mode 100644
index 0000000..e768fe6
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/model/BitInputStream.java
@@ -0,0 +1,89 @@
+/*
+ * 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.integrity.model;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/** A wrapper class for reading a stream of bits. */
+public class BitInputStream {
+
+    private long mBitPointer;
+    private boolean mReadFromStream;
+
+    private byte[] mRuleBytes;
+    private InputStream mRuleInputStream;
+
+    private byte mCurrentRuleByte;
+
+    public BitInputStream(byte[] ruleBytes) {
+        this.mRuleBytes = ruleBytes;
+        this.mBitPointer = 0;
+        this.mReadFromStream = false;
+    }
+
+    public BitInputStream(InputStream ruleInputStream) {
+        this.mRuleInputStream = ruleInputStream;
+        this.mReadFromStream = true;
+    }
+
+    /**
+     * Read the next number of bits from the stream.
+     *
+     * @param numOfBits The number of bits to read.
+     * @return The value read from the stream.
+     */
+    public int getNext(int numOfBits) throws IOException {
+        int component = 0;
+        int count = 0;
+
+        while (count++ < numOfBits) {
+            if (mBitPointer % 8 == 0) {
+                mCurrentRuleByte = getNextByte();
+            }
+            int offset = 7 - (int) (mBitPointer % 8);
+
+            component <<= 1;
+            component |= (mCurrentRuleByte >>> offset) & 1;
+
+            mBitPointer++;
+        }
+
+        return component;
+    }
+
+    /** Check if there are bits left in the stream. */
+    public boolean hasNext() throws IOException {
+        if (mReadFromStream) {
+            return mRuleInputStream.available() > 0;
+        } else {
+            return mBitPointer / 8 < mRuleBytes.length;
+        }
+    }
+
+    private byte getNextByte() throws IOException {
+        if (mReadFromStream) {
+            return (byte) mRuleInputStream.read();
+        } else {
+            int idx = (int) (mBitPointer / 8);
+            if (idx >= mRuleBytes.length) {
+                throw new IllegalArgumentException(String.format("Invalid byte index: %d", idx));
+            }
+            return mRuleBytes[idx];
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/integrity/model/BitOutputStream.java b/services/core/java/com/android/server/integrity/model/BitOutputStream.java
new file mode 100644
index 0000000..ecb9189
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/model/BitOutputStream.java
@@ -0,0 +1,86 @@
+/*
+ * 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.integrity.model;
+
+import java.util.BitSet;
+
+/** A wrapper class for writing a stream of bits. */
+public class BitOutputStream {
+
+    private BitSet mBitSet;
+    private int mIndex;
+
+    public BitOutputStream() {
+        mBitSet = new BitSet();
+        mIndex = 0;
+    }
+
+    /**
+     * Set the next number of bits in the stream to value.
+     *
+     * @param numOfBits The number of bits used to represent the value.
+     * @param value The value to convert to bits.
+     */
+    public void setNext(int numOfBits, int value) {
+        if (numOfBits <= 0) {
+            return;
+        }
+        int offset = 1 << (numOfBits - 1);
+        while (numOfBits-- > 0) {
+            mBitSet.set(mIndex, (value & offset) != 0);
+            offset >>= 1;
+            mIndex++;
+        }
+    }
+
+    /**
+     * Set the next bit in the stream to value.
+     *
+     * @param value The value to set the bit to.
+     */
+    public void setNext(boolean value) {
+        mBitSet.set(mIndex, value);
+        mIndex++;
+    }
+
+    /** Set the next bit in the stream to true. */
+    public void setNext() {
+        setNext(/* value= */ true);
+    }
+
+    /** Convert BitSet in big-endian to ByteArray in big-endian. */
+    public byte[] toByteArray() {
+        int bitSetSize = mBitSet.length();
+        int numOfBytes = bitSetSize / 8;
+        if (bitSetSize % 8 != 0) {
+            numOfBytes++;
+        }
+        byte[] bytes = new byte[numOfBytes];
+        for (int i = 0; i < mBitSet.length(); i++) {
+            if (mBitSet.get(i)) {
+                bytes[i / 8] |= 1 << (7 - (i % 8));
+            }
+        }
+        return bytes;
+    }
+
+    /** Clear the stream. */
+    public void clear() {
+        mBitSet.clear();
+        mIndex = 0;
+    }
+}
diff --git a/services/core/java/com/android/server/integrity/model/ComponentBitSize.java b/services/core/java/com/android/server/integrity/model/ComponentBitSize.java
new file mode 100644
index 0000000..d47ce2d
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/model/ComponentBitSize.java
@@ -0,0 +1,41 @@
+/*
+ * 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.integrity.model;
+
+import android.content.integrity.Rule;
+
+/**
+ * A helper class containing information about the binary representation of different {@link Rule}
+ * components.
+ */
+public final class ComponentBitSize {
+    public static final int FORMAT_VERSION_BITS = 5;
+    public static final int EFFECT_BITS = 3;
+    public static final int KEY_BITS = 4;
+    public static final int OPERATOR_BITS = 3;
+    public static final int CONNECTOR_BITS = 2;
+    public static final int SEPARATOR_BITS = 2;
+    public static final int VALUE_SIZE_BITS = 5;
+    public static final int IS_HASHED_BITS = 1;
+
+    public static final int ATOMIC_FORMULA_START = 0;
+    public static final int COMPOUND_FORMULA_START = 1;
+    public static final int COMPOUND_FORMULA_END = 2;
+
+    public static final int DEFAULT_FORMAT_VERSION = 1;
+    public static final int SIGNAL_BIT = 1;
+}
diff --git a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
index 111b95a..3ef45a6 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
@@ -16,23 +16,132 @@
 
 package com.android.server.integrity.parser;
 
+import static com.android.server.integrity.model.ComponentBitSize.ATOMIC_FORMULA_START;
+import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_END;
+import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_START;
+import static com.android.server.integrity.model.ComponentBitSize.CONNECTOR_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.EFFECT_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.FORMAT_VERSION_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.IS_HASHED_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.KEY_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.OPERATOR_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.SEPARATOR_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.SIGNAL_BIT;
+import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BITS;
+
+import android.content.integrity.AtomicFormula;
+import android.content.integrity.CompoundFormula;
+import android.content.integrity.Formula;
 import android.content.integrity.Rule;
 
+import com.android.server.integrity.model.BitInputStream;
+
+import java.io.IOException;
 import java.io.InputStream;
+import java.util.ArrayList;
 import java.util.List;
 
 /** A helper class to parse rules into the {@link Rule} model from Binary representation. */
 public class RuleBinaryParser implements RuleParser {
 
     @Override
-    public List<Rule> parse(String ruleText) {
-        // TODO: Implement binary text parser.
-        return null;
+    public List<Rule> parse(byte[] ruleBytes) throws RuleParseException {
+        try {
+            BitInputStream bitInputStream = new BitInputStream(ruleBytes);
+            return parseRules(bitInputStream);
+        } catch (Exception e) {
+            throw new RuleParseException(e.getMessage(), e);
+        }
     }
 
     @Override
-    public List<Rule> parse(InputStream inputStream) {
-        // TODO: Implement stream parser.
-        return null;
+    public List<Rule> parse(InputStream inputStream) throws RuleParseException {
+        try {
+            BitInputStream bitInputStream = new BitInputStream(inputStream);
+            return parseRules(bitInputStream);
+        } catch (Exception e) {
+            throw new RuleParseException(e.getMessage(), e);
+        }
+    }
+
+    private List<Rule> parseRules(BitInputStream bitInputStream) throws IOException {
+        List<Rule> parsedRules = new ArrayList<>();
+
+        // Read the rule binary file format version.
+        bitInputStream.getNext(FORMAT_VERSION_BITS);
+
+        while (bitInputStream.hasNext()) {
+            if (bitInputStream.getNext(SIGNAL_BIT) == 1) {
+                parsedRules.add(parseRule(bitInputStream));
+            }
+        }
+
+        return parsedRules;
+    }
+
+    private Rule parseRule(BitInputStream bitInputStream) throws IOException {
+        Formula formula = parseFormula(bitInputStream);
+        int effect = bitInputStream.getNext(EFFECT_BITS);
+
+        if (bitInputStream.getNext(SIGNAL_BIT) != 1) {
+            throw new IllegalArgumentException("A rule must end with a '1' bit.");
+        }
+
+        return new Rule(formula, effect);
+    }
+
+    private Formula parseFormula(BitInputStream bitInputStream) throws IOException {
+        int separator = bitInputStream.getNext(SEPARATOR_BITS);
+        switch (separator) {
+            case ATOMIC_FORMULA_START:
+                return parseAtomicFormula(bitInputStream);
+            case COMPOUND_FORMULA_START:
+                return parseCompoundFormula(bitInputStream);
+            case COMPOUND_FORMULA_END:
+                return null;
+            default:
+                throw new IllegalArgumentException(
+                        String.format("Unknown formula separator: %s", separator));
+        }
+    }
+
+    private CompoundFormula parseCompoundFormula(BitInputStream bitInputStream) throws IOException {
+        int connector = bitInputStream.getNext(CONNECTOR_BITS);
+        List<Formula> formulas = new ArrayList<>();
+
+        Formula parsedFormula = parseFormula(bitInputStream);
+        while (parsedFormula != null) {
+            formulas.add(parsedFormula);
+            parsedFormula = parseFormula(bitInputStream);
+        }
+
+        return new CompoundFormula(connector, formulas);
+    }
+
+    private AtomicFormula parseAtomicFormula(BitInputStream bitInputStream) throws IOException {
+        int key = bitInputStream.getNext(KEY_BITS);
+        int operator = bitInputStream.getNext(OPERATOR_BITS);
+
+        boolean isHashedValue = bitInputStream.getNext(IS_HASHED_BITS) == 1;
+        int valueSize = bitInputStream.getNext(VALUE_SIZE_BITS);
+        StringBuilder value = new StringBuilder();
+        while (valueSize-- > 0) {
+            value.append((char) bitInputStream.getNext(/* numOfBits= */ 8));
+        }
+
+        switch (key) {
+            case AtomicFormula.PACKAGE_NAME:
+            case AtomicFormula.APP_CERTIFICATE:
+            case AtomicFormula.INSTALLER_NAME:
+            case AtomicFormula.INSTALLER_CERTIFICATE:
+                return new AtomicFormula.StringAtomicFormula(key, value.toString(), isHashedValue);
+            case AtomicFormula.VERSION_CODE:
+                return new AtomicFormula.IntAtomicFormula(
+                        key, operator, Integer.parseInt(value.toString()));
+            case AtomicFormula.PRE_INSTALLED:
+                return new AtomicFormula.BooleanAtomicFormula(key, value.toString().equals("1"));
+            default:
+                throw new IllegalArgumentException(String.format("Unknown key: %d", key));
+        }
     }
 }
diff --git a/services/core/java/com/android/server/integrity/parser/RuleParser.java b/services/core/java/com/android/server/integrity/parser/RuleParser.java
index 4e1f914..81783d5 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleParser.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleParser.java
@@ -24,8 +24,8 @@
 /** A helper class to parse rules into the {@link Rule} model. */
 public interface RuleParser {
 
-    /** Parse rules from a string. */
-    List<Rule> parse(String ruleText) throws RuleParseException;
+    /** Parse rules from bytes. */
+    List<Rule> parse(byte[] ruleBytes) throws RuleParseException;
 
     /** Parse rules from an input stream. */
     List<Rule> parse(InputStream inputStream) throws RuleParseException;
diff --git a/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java b/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java
index 1212a08..d405583 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java
@@ -41,7 +41,7 @@
     private static final String NAMESPACE = "";
     private static final String RULE_LIST_TAG = "RL";
     private static final String RULE_TAG = "R";
-    private static final String OPEN_FORMULA_TAG = "OF";
+    private static final String COMPOUND_FORMULA_TAG = "OF";
     private static final String ATOMIC_FORMULA_TAG = "AF";
     private static final String EFFECT_ATTRIBUTE = "E";
     private static final String KEY_ATTRIBUTE = "K";
@@ -51,10 +51,10 @@
     private static final String IS_HASHED_VALUE_ATTRIBUTE = "H";
 
     @Override
-    public List<Rule> parse(String ruleText) throws RuleParseException {
+    public List<Rule> parse(byte[] ruleBytes) throws RuleParseException {
         try {
             XmlPullParser xmlPullParser = Xml.newPullParser();
-            xmlPullParser.setInput(new StringReader(ruleText));
+            xmlPullParser.setInput(new StringReader(new String(ruleBytes, StandardCharsets.UTF_8)));
             return parseRules(xmlPullParser);
         } catch (Exception e) {
             throw new RuleParseException(e.getMessage(), e);
@@ -118,8 +118,8 @@
 
             if (eventType == XmlPullParser.START_TAG) {
                 switch (nodeName) {
-                    case OPEN_FORMULA_TAG:
-                        formula = parseOpenFormula(parser);
+                    case COMPOUND_FORMULA_TAG:
+                        formula = parseCompoundFormula(parser);
                         break;
                     case ATOMIC_FORMULA_TAG:
                         formula = parseAtomicFormula(parser);
@@ -137,7 +137,7 @@
         return new Rule(formula, effect);
     }
 
-    private static Formula parseOpenFormula(XmlPullParser parser)
+    private static Formula parseCompoundFormula(XmlPullParser parser)
             throws IOException, XmlPullParserException {
         int connector =
                 Integer.parseInt(extractAttributeValue(parser, CONNECTOR_ATTRIBUTE).orElse("-1"));
@@ -147,7 +147,8 @@
         while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
             String nodeName = parser.getName();
 
-            if (eventType == XmlPullParser.END_TAG && parser.getName().equals(OPEN_FORMULA_TAG)) {
+            if (eventType == XmlPullParser.END_TAG
+                    && parser.getName().equals(COMPOUND_FORMULA_TAG)) {
                 break;
             }
 
@@ -156,8 +157,8 @@
                     case ATOMIC_FORMULA_TAG:
                         formulas.add(parseAtomicFormula(parser));
                         break;
-                    case OPEN_FORMULA_TAG:
-                        formulas.add(parseOpenFormula(parser));
+                    case COMPOUND_FORMULA_TAG:
+                        formulas.add(parseCompoundFormula(parser));
                         break;
                     default:
                         throw new RuntimeException(
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
index ace15bd..fdbb7d9 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
@@ -16,22 +16,155 @@
 
 package com.android.server.integrity.serializer;
 
+import static com.android.server.integrity.model.ComponentBitSize.ATOMIC_FORMULA_START;
+import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_END;
+import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_START;
+import static com.android.server.integrity.model.ComponentBitSize.CONNECTOR_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.DEFAULT_FORMAT_VERSION;
+import static com.android.server.integrity.model.ComponentBitSize.EFFECT_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.FORMAT_VERSION_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.KEY_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.OPERATOR_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.SEPARATOR_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BITS;
+
+import android.content.integrity.AtomicFormula;
+import android.content.integrity.CompoundFormula;
+import android.content.integrity.Formula;
 import android.content.integrity.Rule;
 
-import java.io.OutputStream;
-import java.util.List;
+import com.android.server.integrity.model.BitOutputStream;
 
-/** A helper class to serialize rules from the {@link Rule} model to Xml representation. */
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Optional;
+
+/** A helper class to serialize rules from the {@link Rule} model to Binary representation. */
 public class RuleBinarySerializer implements RuleSerializer {
 
+    // Get the byte representation for a list of rules, and write them to an output stream.
     @Override
-    public void serialize(List<Rule> rules, OutputStream outputStream) {
-        // TODO: Implement stream serializer.
+    public void serialize(
+            List<Rule> rules, Optional<Integer> formatVersion, OutputStream outputStream)
+            throws RuleSerializeException {
+        try {
+            BitOutputStream bitOutputStream = new BitOutputStream();
+
+            int formatVersionValue = formatVersion.orElse(DEFAULT_FORMAT_VERSION);
+            bitOutputStream.setNext(FORMAT_VERSION_BITS, formatVersionValue);
+            outputStream.write(bitOutputStream.toByteArray());
+
+            for (Rule rule : rules) {
+                bitOutputStream.clear();
+                serializeRule(rule, bitOutputStream);
+                outputStream.write(bitOutputStream.toByteArray());
+            }
+        } catch (Exception e) {
+            throw new RuleSerializeException(e.getMessage(), e);
+        }
     }
 
+    // Get the byte representation for a list of rules.
     @Override
-    public String serialize(List<Rule> rules) {
-        // TODO: Implement text serializer.
-        return null;
+    public byte[] serialize(List<Rule> rules, Optional<Integer> formatVersion)
+            throws RuleSerializeException {
+        try {
+            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+            serialize(rules, formatVersion, byteArrayOutputStream);
+            return byteArrayOutputStream.toByteArray();
+        } catch (Exception e) {
+            throw new RuleSerializeException(e.getMessage(), e);
+        }
+    }
+
+    private void serializeRule(Rule rule, BitOutputStream bitOutputStream) {
+        if (rule == null) {
+            throw new IllegalArgumentException("Null rule can not be serialized");
+        }
+
+        // Start with a '1' bit to mark the start of a rule.
+        bitOutputStream.setNext();
+
+        serializeFormula(rule.getFormula(), bitOutputStream);
+        bitOutputStream.setNext(EFFECT_BITS, rule.getEffect());
+
+        // End with a '1' bit to mark the end of a rule.
+        bitOutputStream.setNext();
+    }
+
+    private void serializeFormula(Formula formula, BitOutputStream bitOutputStream) {
+        if (formula instanceof AtomicFormula) {
+            serializeAtomicFormula((AtomicFormula) formula, bitOutputStream);
+        } else if (formula instanceof CompoundFormula) {
+            serializeCompoundFormula((CompoundFormula) formula, bitOutputStream);
+        } else {
+            throw new IllegalArgumentException(
+                    String.format("Invalid formula type: %s", formula.getClass()));
+        }
+    }
+
+    private void serializeCompoundFormula(
+            CompoundFormula compoundFormula, BitOutputStream bitOutputStream) {
+        if (compoundFormula == null) {
+            throw new IllegalArgumentException("Null compound formula can not be serialized");
+        }
+
+        bitOutputStream.setNext(SEPARATOR_BITS, COMPOUND_FORMULA_START);
+        bitOutputStream.setNext(CONNECTOR_BITS, compoundFormula.getConnector());
+        for (Formula formula : compoundFormula.getFormulas()) {
+            serializeFormula(formula, bitOutputStream);
+        }
+        bitOutputStream.setNext(SEPARATOR_BITS, COMPOUND_FORMULA_END);
+    }
+
+    private void serializeAtomicFormula(
+            AtomicFormula atomicFormula, BitOutputStream bitOutputStream) {
+        if (atomicFormula == null) {
+            throw new IllegalArgumentException("Null atomic formula can not be serialized");
+        }
+
+        bitOutputStream.setNext(SEPARATOR_BITS, ATOMIC_FORMULA_START);
+        bitOutputStream.setNext(KEY_BITS, atomicFormula.getKey());
+        if (atomicFormula.getTag() == AtomicFormula.STRING_ATOMIC_FORMULA_TAG) {
+            AtomicFormula.StringAtomicFormula stringAtomicFormula =
+                    (AtomicFormula.StringAtomicFormula) atomicFormula;
+            bitOutputStream.setNext(OPERATOR_BITS, AtomicFormula.EQ);
+            serializeValue(
+                    stringAtomicFormula.getValue(),
+                    stringAtomicFormula.getIsHashedValue(),
+                    bitOutputStream);
+        } else if (atomicFormula.getTag() == AtomicFormula.INT_ATOMIC_FORMULA_TAG) {
+            AtomicFormula.IntAtomicFormula intAtomicFormula =
+                    (AtomicFormula.IntAtomicFormula) atomicFormula;
+            bitOutputStream.setNext(OPERATOR_BITS, intAtomicFormula.getOperator());
+            serializeValue(
+                    String.valueOf(intAtomicFormula.getValue()),
+                    /* isHashedValue= */ false,
+                    bitOutputStream);
+        } else if (atomicFormula.getTag() == AtomicFormula.BOOLEAN_ATOMIC_FORMULA_TAG) {
+            AtomicFormula.BooleanAtomicFormula booleanAtomicFormula =
+                    (AtomicFormula.BooleanAtomicFormula) atomicFormula;
+            bitOutputStream.setNext(OPERATOR_BITS, AtomicFormula.EQ);
+            serializeValue(
+                    booleanAtomicFormula.getValue() ? "1" : "0",
+                    /* isHashedValue= */ false,
+                    bitOutputStream);
+        } else {
+            throw new IllegalArgumentException(
+                    String.format("Invalid atomic formula type: %s", atomicFormula.getClass()));
+        }
+    }
+
+    private void serializeValue(
+            String value, boolean isHashedValue, BitOutputStream bitOutputStream) {
+        byte[] valueBytes = value.getBytes(StandardCharsets.UTF_8);
+
+        bitOutputStream.setNext(isHashedValue);
+        bitOutputStream.setNext(VALUE_SIZE_BITS, valueBytes.length);
+        for (byte valueByte : valueBytes) {
+            bitOutputStream.setNext(/* numOfBits= */ 8, valueByte);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleIndexTypeIdentifier.java b/services/core/java/com/android/server/integrity/serializer/RuleIndexTypeIdentifier.java
new file mode 100644
index 0000000..4d3961d
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/serializer/RuleIndexTypeIdentifier.java
@@ -0,0 +1,117 @@
+/*
+ * 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.integrity.serializer;
+
+import android.annotation.IntDef;
+import android.content.integrity.AtomicFormula;
+import android.content.integrity.CompoundFormula;
+import android.content.integrity.Formula;
+import android.content.integrity.Rule;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/** A helper class for identifying the indexing type of a given rule. */
+public class RuleIndexTypeIdentifier {
+
+    static final int NOT_INDEXED = 0;
+    static final int PACKAGE_NAME_INDEXED = 1;
+    static final int APP_CERTIFICATE_INDEXED = 2;
+
+    /** Represents which indexed file the rule should be located. */
+    @IntDef(
+            value = {
+                    NOT_INDEXED,
+                    PACKAGE_NAME_INDEXED,
+                    APP_CERTIFICATE_INDEXED
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface IndexType {
+    }
+
+    /** Determines the indexing file type that a given rule should be located at. */
+    public static int getIndexType(Rule rule) {
+        if (rule == null) {
+            throw new IllegalArgumentException("Indexing type cannot be determined for null rule.");
+        }
+        return getIndexType(rule.getFormula());
+    }
+
+    private static int getIndexType(Formula formula) {
+        if (formula == null) {
+            throw new IllegalArgumentException(
+                    "Indexing type cannot be determined for null formula.");
+        }
+
+        switch (formula.getTag()) {
+            case Formula.COMPOUND_FORMULA_TAG:
+                return getIndexTypeForCompoundFormula((CompoundFormula) formula);
+            case Formula.STRING_ATOMIC_FORMULA_TAG:
+                return getIndexTypeForAtomicStringFormula((AtomicFormula) formula);
+            case Formula.INT_ATOMIC_FORMULA_TAG:
+            case Formula.BOOLEAN_ATOMIC_FORMULA_TAG:
+                // Package name and app certificate related formulas are string atomic formulas.
+                return NOT_INDEXED;
+            default:
+                throw new IllegalArgumentException(
+                        String.format("Invalid formula tag type: %s", formula.getTag()));
+        }
+    }
+
+    private static int getIndexTypeForCompoundFormula(CompoundFormula compoundFormula) {
+        int connector = compoundFormula.getConnector();
+        List<Formula> formulas = compoundFormula.getFormulas();
+
+        switch (connector) {
+            case CompoundFormula.NOT:
+                // Having a NOT operator in the indexing messes up the indexing; e.g., deny
+                // installation if app certificate is NOT X (should not be indexed with app cert
+                // X). We will not keep these rules indexed.
+                return NOT_INDEXED;
+            case CompoundFormula.AND:
+            case CompoundFormula.OR:
+                Set<Integer> indexingTypesForAllFormulas =
+                        formulas.stream()
+                                .map(formula -> getIndexType(formula))
+                                .collect(Collectors.toSet());
+                if (indexingTypesForAllFormulas.contains(PACKAGE_NAME_INDEXED)) {
+                    return PACKAGE_NAME_INDEXED;
+                } else if (indexingTypesForAllFormulas.contains(APP_CERTIFICATE_INDEXED)) {
+                    return APP_CERTIFICATE_INDEXED;
+                } else {
+                    return NOT_INDEXED;
+                }
+            default:
+                return NOT_INDEXED;
+        }
+    }
+
+    private static int getIndexTypeForAtomicStringFormula(AtomicFormula atomicFormula) {
+        switch (atomicFormula.getKey()) {
+            case AtomicFormula.PACKAGE_NAME:
+                return PACKAGE_NAME_INDEXED;
+            case AtomicFormula.APP_CERTIFICATE:
+                return APP_CERTIFICATE_INDEXED;
+            default:
+                return NOT_INDEXED;
+        }
+    }
+}
+
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java
index c45f6be..4fcff65 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java
@@ -20,13 +20,16 @@
 
 import java.io.OutputStream;
 import java.util.List;
+import java.util.Optional;
 
 /** A helper class to serialize rules from the {@link Rule} model. */
 public interface RuleSerializer {
 
     /** Serialize rules to an output stream */
-    void serialize(List<Rule> rules, OutputStream outputStream) throws RuleSerializeException;
+    void serialize(List<Rule> rules, Optional<Integer> formatVersion, OutputStream outputStream)
+            throws RuleSerializeException;
 
-    /** Serialize rules to a string. */
-    String serialize(List<Rule> rule) throws RuleSerializeException;
+    /** Serialize rules to a ByteArray. */
+    byte[] serialize(List<Rule> rule, Optional<Integer> formatVersion)
+            throws RuleSerializeException;
 }
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java
index 5dd7891..cfe50c6 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java
@@ -29,6 +29,7 @@
 import java.io.StringWriter;
 import java.nio.charset.StandardCharsets;
 import java.util.List;
+import java.util.Optional;
 
 /** A helper class to serialize rules from the {@link Rule} model to Xml representation. */
 public class RuleXmlSerializer implements RuleSerializer {
@@ -38,7 +39,7 @@
 
     private static final String RULE_LIST_TAG = "RL";
     private static final String RULE_TAG = "R";
-    private static final String OPEN_FORMULA_TAG = "OF";
+    private static final String COMPOUND_FORMULA_TAG = "OF";
     private static final String ATOMIC_FORMULA_TAG = "AF";
     private static final String EFFECT_ATTRIBUTE = "E";
     private static final String KEY_ATTRIBUTE = "K";
@@ -48,7 +49,8 @@
     private static final String IS_HASHED_VALUE_ATTRIBUTE = "H";
 
     @Override
-    public void serialize(List<Rule> rules, OutputStream outputStream)
+    public void serialize(
+            List<Rule> rules, Optional<Integer> formatVersion, OutputStream outputStream)
             throws RuleSerializeException {
         try {
             XmlSerializer xmlSerializer = Xml.newSerializer();
@@ -60,13 +62,14 @@
     }
 
     @Override
-    public String serialize(List<Rule> rules) throws RuleSerializeException {
+    public byte[] serialize(List<Rule> rules, Optional<Integer> formatVersion)
+            throws RuleSerializeException {
         try {
             XmlSerializer xmlSerializer = Xml.newSerializer();
             StringWriter writer = new StringWriter();
             xmlSerializer.setOutput(writer);
             serializeRules(rules, xmlSerializer);
-            return writer.toString();
+            return writer.toString().getBytes(StandardCharsets.UTF_8);
         } catch (Exception e) {
             throw new RuleSerializeException(e.getMessage(), e);
         }
@@ -75,13 +78,13 @@
     private void serializeRules(List<Rule> rules, XmlSerializer xmlSerializer) throws IOException {
         xmlSerializer.startTag(NAMESPACE, RULE_LIST_TAG);
         for (Rule rule : rules) {
-            serialize(rule, xmlSerializer);
+            serializeRule(rule, xmlSerializer);
         }
         xmlSerializer.endTag(NAMESPACE, RULE_LIST_TAG);
         xmlSerializer.endDocument();
     }
 
-    private void serialize(Rule rule, XmlSerializer xmlSerializer) throws IOException {
+    private void serializeRule(Rule rule, XmlSerializer xmlSerializer) throws IOException {
         if (rule == null) {
             return;
         }
@@ -95,25 +98,25 @@
         if (formula instanceof AtomicFormula) {
             serializeAtomicFormula((AtomicFormula) formula, xmlSerializer);
         } else if (formula instanceof CompoundFormula) {
-            serializeOpenFormula((CompoundFormula) formula, xmlSerializer);
+            serializeCompoundFormula((CompoundFormula) formula, xmlSerializer);
         } else {
             throw new IllegalArgumentException(
                     String.format("Invalid formula type: %s", formula.getClass()));
         }
     }
 
-    private void serializeOpenFormula(CompoundFormula compoundFormula, XmlSerializer xmlSerializer)
-            throws IOException {
+    private void serializeCompoundFormula(
+            CompoundFormula compoundFormula, XmlSerializer xmlSerializer) throws IOException {
         if (compoundFormula == null) {
             return;
         }
-        xmlSerializer.startTag(NAMESPACE, OPEN_FORMULA_TAG);
-        serializeAttributeValue(CONNECTOR_ATTRIBUTE, String.valueOf(compoundFormula.getConnector()),
-                xmlSerializer);
+        xmlSerializer.startTag(NAMESPACE, COMPOUND_FORMULA_TAG);
+        serializeAttributeValue(
+                CONNECTOR_ATTRIBUTE, String.valueOf(compoundFormula.getConnector()), xmlSerializer);
         for (Formula formula : compoundFormula.getFormulas()) {
             serializeFormula(formula, xmlSerializer);
         }
-        xmlSerializer.endTag(NAMESPACE, OPEN_FORMULA_TAG);
+        xmlSerializer.endTag(NAMESPACE, COMPOUND_FORMULA_TAG);
     }
 
     private void serializeAtomicFormula(AtomicFormula atomicFormula, XmlSerializer xmlSerializer)
@@ -122,24 +125,30 @@
             return;
         }
         xmlSerializer.startTag(NAMESPACE, ATOMIC_FORMULA_TAG);
-        serializeAttributeValue(KEY_ATTRIBUTE, String.valueOf(atomicFormula.getKey()),
-                xmlSerializer);
-        if (atomicFormula instanceof AtomicFormula.StringAtomicFormula) {
-            serializeAttributeValue(VALUE_ATTRIBUTE,
-                    ((AtomicFormula.StringAtomicFormula) atomicFormula).getValue(), xmlSerializer);
-            serializeAttributeValue(IS_HASHED_VALUE_ATTRIBUTE,
+        serializeAttributeValue(
+                KEY_ATTRIBUTE, String.valueOf(atomicFormula.getKey()), xmlSerializer);
+        if (atomicFormula.getTag() == AtomicFormula.STRING_ATOMIC_FORMULA_TAG) {
+            serializeAttributeValue(
+                    VALUE_ATTRIBUTE,
+                    ((AtomicFormula.StringAtomicFormula) atomicFormula).getValue(),
+                    xmlSerializer);
+            serializeAttributeValue(
+                    IS_HASHED_VALUE_ATTRIBUTE,
                     String.valueOf(
                             ((AtomicFormula.StringAtomicFormula) atomicFormula).getIsHashedValue()),
                     xmlSerializer);
-        } else if (atomicFormula instanceof AtomicFormula.IntAtomicFormula) {
-            serializeAttributeValue(OPERATOR_ATTRIBUTE,
+        } else if (atomicFormula.getTag() == AtomicFormula.INT_ATOMIC_FORMULA_TAG) {
+            serializeAttributeValue(
+                    OPERATOR_ATTRIBUTE,
                     String.valueOf(((AtomicFormula.IntAtomicFormula) atomicFormula).getOperator()),
                     xmlSerializer);
-            serializeAttributeValue(VALUE_ATTRIBUTE,
+            serializeAttributeValue(
+                    VALUE_ATTRIBUTE,
                     String.valueOf(((AtomicFormula.IntAtomicFormula) atomicFormula).getValue()),
                     xmlSerializer);
-        } else if (atomicFormula instanceof AtomicFormula.BooleanAtomicFormula) {
-            serializeAttributeValue(VALUE_ATTRIBUTE,
+        } else if (atomicFormula.getTag() == AtomicFormula.BOOLEAN_ATOMIC_FORMULA_TAG) {
+            serializeAttributeValue(
+                    VALUE_ATTRIBUTE,
                     String.valueOf(((AtomicFormula.BooleanAtomicFormula) atomicFormula).getValue()),
                     xmlSerializer);
         } else {
@@ -149,9 +158,8 @@
         xmlSerializer.endTag(NAMESPACE, ATOMIC_FORMULA_TAG);
     }
 
-    private void serializeAttributeValue(String attribute, String value,
-            XmlSerializer xmlSerializer)
-            throws IOException {
+    private void serializeAttributeValue(
+            String attribute, String value, XmlSerializer xmlSerializer) throws IOException {
         if (value == null) {
             return;
         }
diff --git a/services/core/java/com/android/server/location/ContextHubClientBroker.java b/services/core/java/com/android/server/location/ContextHubClientBroker.java
index 675e59e..45d9bae 100644
--- a/services/core/java/com/android/server/location/ContextHubClientBroker.java
+++ b/services/core/java/com/android/server/location/ContextHubClientBroker.java
@@ -29,10 +29,12 @@
 import android.hardware.location.IContextHubClient;
 import android.hardware.location.IContextHubClientCallback;
 import android.hardware.location.NanoAppMessage;
+import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
 
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Supplier;
 
 /**
@@ -97,6 +99,16 @@
     private final PendingIntentRequest mPendingIntentRequest;
 
     /*
+     * The host package associated with this client.
+     */
+    private final String mPackage;
+
+    /*
+     * True if a PendingIntent has been cancelled.
+     */
+    private AtomicBoolean mIsPendingIntentCancelled = new AtomicBoolean(false);
+
+    /*
      * Helper class to manage registered PendingIntent requests from the client.
      */
     private class PendingIntentRequest {
@@ -110,11 +122,14 @@
          */
         private long mNanoAppId;
 
+        private boolean mValid = false;
+
         PendingIntentRequest() {}
 
         PendingIntentRequest(PendingIntent pendingIntent, long nanoAppId) {
             mPendingIntent = pendingIntent;
             mNanoAppId = nanoAppId;
+            mValid = true;
         }
 
         public long getNanoAppId() {
@@ -132,6 +147,10 @@
         public void clear() {
             mPendingIntent = null;
         }
+
+        public boolean isValid() {
+            return mValid;
+        }
     }
 
     /* package */ ContextHubClientBroker(
@@ -145,6 +164,7 @@
         mHostEndPointId = hostEndPointId;
         mCallbackInterface = callback;
         mPendingIntentRequest = new PendingIntentRequest();
+        mPackage = mContext.getPackageManager().getNameForUid(Binder.getCallingUid());
     }
 
     /* package */ ContextHubClientBroker(
@@ -157,6 +177,7 @@
         mAttachedContextHubInfo = contextHubInfo;
         mHostEndPointId = hostEndPointId;
         mPendingIntentRequest = new PendingIntentRequest(pendingIntent, nanoAppId);
+        mPackage = pendingIntent.getCreatorPackage();
     }
 
     /**
@@ -313,6 +334,13 @@
     }
 
     /**
+     * @return true if the client is a PendingIntent client that has been cancelled.
+     */
+    /* package */ boolean isPendingIntentCancelled() {
+        return mIsPendingIntentCancelled.get();
+    }
+
+    /**
      * Helper function to invoke a specified client callback, if the connection is open.
      *
      * @param consumer the consumer specifying the callback to invoke
@@ -392,6 +420,7 @@
                     Manifest.permission.LOCATION_HARDWARE /* requiredPermission */,
                     null /* options */);
         } catch (PendingIntent.CanceledException e) {
+            mIsPendingIntentCancelled.set(true);
             // The PendingIntent is no longer valid
             Log.w(TAG, "PendingIntent has been canceled, unregistering from client"
                     + " (host endpoint ID " + mHostEndPointId + ")");
@@ -419,4 +448,20 @@
             mRegistered = false;
         }
     }
+
+    @Override
+    public String toString() {
+        String out = "[ContextHubClient ";
+        out += "endpointID: " + getHostEndPointId() + ", ";
+        out += "contextHub: " + getAttachedContextHubId() + ", ";
+        if (mPendingIntentRequest.isValid()) {
+            out += "intentCreatorPackage: " + mPackage + ", ";
+            out += "nanoAppId: 0x" + Long.toHexString(mPendingIntentRequest.getNanoAppId());
+        } else {
+            out += "package: " + mPackage;
+        }
+        out += "]";
+
+        return out;
+    }
 }
diff --git a/services/core/java/com/android/server/location/ContextHubClientManager.java b/services/core/java/com/android/server/location/ContextHubClientManager.java
index 00b7d62..46db8dc 100644
--- a/services/core/java/com/android/server/location/ContextHubClientManager.java
+++ b/services/core/java/com/android/server/location/ContextHubClientManager.java
@@ -16,6 +16,7 @@
 
 package com.android.server.location;
 
+import android.annotation.IntDef;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.hardware.contexthub.V1_0.ContextHubMsg;
@@ -27,7 +28,12 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Calendar;
+import java.util.Iterator;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedDeque;
 import java.util.function.Consumer;
 
 /**
@@ -71,6 +77,79 @@
      */
     private int mNextHostEndPointId = 0;
 
+    /*
+     * The list of previous registration records.
+     */
+    private static final int NUM_CLIENT_RECORDS = 20;
+    private final ConcurrentLinkedEvictingDeque<RegistrationRecord> mRegistrationRecordDeque =
+            new ConcurrentLinkedEvictingDeque<>(NUM_CLIENT_RECORDS);
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "ACTION_" }, value = {
+            ACTION_REGISTERED,
+            ACTION_UNREGISTERED,
+            ACTION_CANCELLED,
+    })
+    public @interface Action {}
+    public static final int ACTION_REGISTERED = 0;
+    public static final int ACTION_UNREGISTERED = 1;
+    public static final int ACTION_CANCELLED = 2;
+
+    /**
+     * Helper class to make a ConcurrentLinkedDeque fixed-size, evicting old entries when full.
+     */
+    private class ConcurrentLinkedEvictingDeque<E> extends ConcurrentLinkedDeque<E> {
+        private int mSize;
+
+        ConcurrentLinkedEvictingDeque(int size) {
+            mSize = size;
+        }
+
+        @Override
+        public boolean add(E elem) {
+            synchronized (this) {
+                if (size() == mSize) {
+                    poll();
+                }
+
+                return super.add(elem);
+            }
+        }
+    }
+
+    /**
+     * A container class to store a record of ContextHubClient registration.
+     */
+    private class RegistrationRecord {
+        private final String mBroker;
+        private final int mAction;
+        private final String mDate;
+
+        RegistrationRecord(String broker, @Action int action) {
+            mBroker = broker;
+            mAction = action;
+            Calendar instance = Calendar.getInstance();
+            mDate = String.format("%02d", instance.get(Calendar.MONTH) + 1) // Jan == 0
+                + "/" + String.format("%02d", instance.get(Calendar.DAY_OF_MONTH))
+                + " " + String.format("%02d", instance.get(Calendar.HOUR_OF_DAY))
+                + ":" + String.format("%02d", instance.get(Calendar.MINUTE))
+                + ":" + String.format("%02d", instance.get(Calendar.SECOND))
+                + "." + String.format("%03d", instance.get(Calendar.MILLISECOND));
+        }
+
+        @Override
+        public String toString() {
+            String out = "";
+            out += mDate + " ";
+            out += mAction == ACTION_REGISTERED ? "+ " : "- ";
+            out += mBroker;
+            if (mAction == ACTION_CANCELLED) {
+                out += " (cancelled)";
+            }
+            return out;
+        }
+    }
+
     /* package */ ContextHubClientManager(
             Context context, IContexthub contextHubProxy) {
         mContext = context;
@@ -96,6 +175,8 @@
                     mContext, mContextHubProxy, this /* clientManager */, contextHubInfo,
                     hostEndPointId, clientCallback);
             mHostEndPointIdToClientMap.put(hostEndPointId, broker);
+            mRegistrationRecordDeque.add(
+                    new RegistrationRecord(broker.toString(), ACTION_REGISTERED));
         }
 
         try {
@@ -136,6 +217,8 @@
                         hostEndPointId, pendingIntent, nanoAppId);
                 mHostEndPointIdToClientMap.put(hostEndPointId, broker);
                 registerString = "Registered";
+                mRegistrationRecordDeque.add(
+                        new RegistrationRecord(broker.toString(), ACTION_REGISTERED));
             }
         }
 
@@ -178,6 +261,13 @@
      * @param hostEndPointId the host endpoint ID of the client that has died
      */
     /* package */ void unregisterClient(short hostEndPointId) {
+        ContextHubClientBroker broker = mHostEndPointIdToClientMap.get(hostEndPointId);
+        if (broker != null) {
+            @Action int action =
+                    broker.isPendingIntentCancelled() ? ACTION_CANCELLED : ACTION_UNREGISTERED;
+            mRegistrationRecordDeque.add(new RegistrationRecord(broker.toString(), action));
+        }
+
         if (mHostEndPointIdToClientMap.remove(hostEndPointId) != null) {
             Log.d(TAG, "Unregistered client with host endpoint ID " + hostEndPointId);
         } else {
@@ -285,4 +375,20 @@
 
         return null;
     }
+
+    @Override
+    public String toString() {
+        String out = "";
+        for (ContextHubClientBroker broker : mHostEndPointIdToClientMap.values()) {
+            out += broker + "\n";
+        }
+
+        out += "\nRegistration history:\n";
+        Iterator<RegistrationRecord> it = mRegistrationRecordDeque.descendingIterator();
+        while (it.hasNext()) {
+            out += it.next() + "\n";
+        }
+
+        return out;
+    }
 }
diff --git a/services/core/java/com/android/server/location/ContextHubService.java b/services/core/java/com/android/server/location/ContextHubService.java
index 36b0342..787a800 100644
--- a/services/core/java/com/android/server/location/ContextHubService.java
+++ b/services/core/java/com/android/server/location/ContextHubService.java
@@ -795,6 +795,10 @@
         // Dump nanoAppHash
         mNanoAppStateManager.foreachNanoAppInstanceInfo((info) -> pw.println(info));
 
+        pw.println("");
+        pw.println("=================== CLIENTS ====================");
+        pw.println(mClientManager);
+
         // dump eventLog
     }
 
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index c84745e..f913ba3 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -531,8 +531,10 @@
         CarrierConfigManager configManager = (CarrierConfigManager)
                 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
         int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId();
-        String mccMnc = SubscriptionManager.isValidSubscriptionId(ddSubId)
-                ? phone.getSimOperator(ddSubId) : phone.getSimOperator();
+        if (SubscriptionManager.isValidSubscriptionId(ddSubId)) {
+            phone = phone.createForSubscriptionId(ddSubId);
+        }
+        String mccMnc = phone.getSimOperator();
         boolean isKeepLppProfile = false;
         if (!TextUtils.isEmpty(mccMnc)) {
             if (DEBUG) Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc);
@@ -1447,11 +1449,13 @@
         private float[] mSvElevations;
         private float[] mSvAzimuths;
         private float[] mSvCarrierFreqs;
+        private float[] mBasebandCn0s;
     }
 
     @NativeEntryPoint
     private void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0s,
-            float[] svElevations, float[] svAzimuths, float[] svCarrierFreqs) {
+            float[] svElevations, float[] svAzimuths, float[] svCarrierFreqs,
+            float[] basebandCn0s) {
         SvStatusInfo svStatusInfo = new SvStatusInfo();
         svStatusInfo.mSvCount = svCount;
         svStatusInfo.mSvidWithFlags = svidWithFlags;
@@ -1459,6 +1463,7 @@
         svStatusInfo.mSvElevations = svElevations;
         svStatusInfo.mSvAzimuths = svAzimuths;
         svStatusInfo.mSvCarrierFreqs = svCarrierFreqs;
+        svStatusInfo.mBasebandCn0s = basebandCn0s;
 
         sendMessage(REPORT_SV_STATUS, 0, svStatusInfo);
     }
@@ -1470,7 +1475,8 @@
                 info.mCn0s,
                 info.mSvElevations,
                 info.mSvAzimuths,
-                info.mSvCarrierFreqs);
+                info.mSvCarrierFreqs,
+                info.mBasebandCn0s);
 
         // Log CN0 as part of GNSS metrics
         mGnssMetrics.logCn0(info.mCn0s, info.mSvCount, info.mSvCarrierFreqs);
@@ -1485,7 +1491,8 @@
                 info.mCn0s,
                 info.mSvElevations,
                 info.mSvAzimuths,
-                info.mSvCarrierFreqs);
+                info.mSvCarrierFreqs,
+                info.mBasebandCn0s);
         int usedInFixCount = 0;
         int maxCn0 = 0;
         int meanCn0 = 0;
@@ -1501,13 +1508,15 @@
             if (VERBOSE) {
                 Log.v(TAG, "svid: " + gnssStatus.getSvid(i)
                         + " cn0: " + gnssStatus.getCn0DbHz(i)
+                        + " basebandCn0: " + gnssStatus.getBasebandCn0DbHz(i)
                         + " elev: " + gnssStatus.getElevationDegrees(i)
                         + " azimuth: " + gnssStatus.getAzimuthDegrees(i)
                         + " carrier frequency: " + gnssStatus.getCn0DbHz(i)
                         + (gnssStatus.hasEphemerisData(i) ? " E" : "  ")
                         + (gnssStatus.hasAlmanacData(i) ? " A" : "  ")
                         + (gnssStatus.usedInFix(i) ? "U" : "")
-                        + (gnssStatus.hasCarrierFrequencyHz(i) ? "F" : ""));
+                        + (gnssStatus.hasCarrierFrequencyHz(i) ? "F" : "")
+                        + (gnssStatus.hasBasebandCn0DbHz(i) ? "B" : ""));
             }
         }
         if (usedInFixCount > 0) {
@@ -1906,24 +1915,17 @@
         String setId = null;
 
         int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId();
+        if (SubscriptionManager.isValidSubscriptionId(ddSubId)) {
+            phone = phone.createForSubscriptionId(ddSubId);
+        }
         if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
-            if (SubscriptionManager.isValidSubscriptionId(ddSubId)) {
-                setId = phone.getSubscriberId(ddSubId);
-            }
-            if (setId == null) {
-                setId = phone.getSubscriberId();
-            }
+            setId = phone.getSubscriberId();
             if (setId != null) {
                 // This means the framework has the SIM card.
                 type = AGPS_SETID_TYPE_IMSI;
             }
         } else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
-            if (SubscriptionManager.isValidSubscriptionId(ddSubId)) {
-                setId = phone.getLine1Number(ddSubId);
-            }
-            if (setId == null) {
-                setId = phone.getLine1Number();
-            }
+            setId = phone.getLine1Number();
             if (setId != null) {
                 // This means the framework has the SIM card.
                 type = AGPS_SETID_TYPE_MSISDN;
diff --git a/services/core/java/com/android/server/location/GnssStatusListenerHelper.java b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
index d67d0c5..eaf63c8 100644
--- a/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
+++ b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
@@ -71,7 +71,8 @@
             final float[] cn0s,
             final float[] elevations,
             final float[] azimuths,
-            final float[] carrierFreqs) {
+            final float[] carrierFreqs,
+            final float[] basebandCn0s) {
         foreach((IGnssStatusListener listener, CallerIdentity callerIdentity) -> {
             if (!hasPermission(mContext, callerIdentity)) {
                 logPermissionDisabledEventNotReported(TAG, callerIdentity.mPackageName,
@@ -79,7 +80,7 @@
                 return;
             }
             listener.onSvStatusChanged(svCount, prnWithFlags, cn0s, elevations, azimuths,
-                    carrierFreqs);
+                    carrierFreqs, basebandCn0s);
         });
     }
 
diff --git a/services/core/java/com/android/server/location/GnssVisibilityControl.java b/services/core/java/com/android/server/location/GnssVisibilityControl.java
index ea4f9c4..dd522b9 100644
--- a/services/core/java/com/android/server/location/GnssVisibilityControl.java
+++ b/services/core/java/com/android/server/location/GnssVisibilityControl.java
@@ -637,7 +637,7 @@
         return new Notification.Builder(context, SystemNotificationChannels.NETWORK_ALERTS)
                 .setSmallIcon(com.android.internal.R.drawable.stat_sys_gps_on)
                 .setWhen(0)
-                .setOngoing(true)
+                .setOngoing(false)
                 .setAutoCancel(true)
                 .setColor(context.getColor(
                         com.android.internal.R.color.system_notification_accent_color))
diff --git a/services/core/java/com/android/server/location/LocationSettingsStore.java b/services/core/java/com/android/server/location/LocationSettingsStore.java
index dc5628e..eb2a37b 100644
--- a/services/core/java/com/android/server/location/LocationSettingsStore.java
+++ b/services/core/java/com/android/server/location/LocationSettingsStore.java
@@ -33,21 +33,51 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.ArraySet;
 
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
+import com.android.server.SystemConfig;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Supplier;
 
 /**
  * Provides accessors and listeners for all location related settings.
  */
 public class LocationSettingsStore {
 
+    /**
+     * Listener for user-specific settings changes.
+     */
+    public interface UserSettingChangedListener {
+        /**
+         * Called when setting changes.
+         */
+        void onSettingChanged(int userId);
+    }
+
+    /**
+     * Listener for global settings changes.
+     */
+    public interface GlobalSettingChangedListener extends UserSettingChangedListener {
+        /**
+         * Called when setting changes.
+         */
+        void onSettingChanged();
+
+        @Override
+        default void onSettingChanged(int userId) {
+            onSettingChanged();
+        }
+    }
+
     private static final String LOCATION_PACKAGE_BLACKLIST = "locationPackagePrefixBlacklist";
     private static final String LOCATION_PACKAGE_WHITELIST = "locationPackagePrefixWhitelist";
 
@@ -63,9 +93,10 @@
     private final LongGlobalSetting mBackgroundThrottleIntervalMs;
     private final StringListCachedSecureSetting mLocationPackageBlacklist;
     private final StringListCachedSecureSetting mLocationPackageWhitelist;
-    private final StringListCachedGlobalSetting mBackgroundThrottlePackageWhitelist;
-    private final StringListCachedGlobalSetting mIgnoreSettingsPackageWhitelist;
+    private final StringSetCachedGlobalSetting mBackgroundThrottlePackageWhitelist;
+    private final StringSetCachedGlobalSetting mIgnoreSettingsPackageWhitelist;
 
+    // TODO: get rid of handler
     public LocationSettingsStore(Context context, Handler handler) {
         mContext = context;
 
@@ -78,10 +109,12 @@
                 LOCATION_PACKAGE_BLACKLIST, handler);
         mLocationPackageWhitelist = new StringListCachedSecureSetting(context,
                 LOCATION_PACKAGE_WHITELIST, handler);
-        mBackgroundThrottlePackageWhitelist = new StringListCachedGlobalSetting(context,
-                LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST, handler);
-        mIgnoreSettingsPackageWhitelist = new StringListCachedGlobalSetting(context,
-                LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST, handler);
+        mBackgroundThrottlePackageWhitelist = new StringSetCachedGlobalSetting(context,
+                LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST,
+                () -> SystemConfig.getInstance().getAllowUnthrottledLocation(), handler);
+        mIgnoreSettingsPackageWhitelist = new StringSetCachedGlobalSetting(context,
+                LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST,
+                () -> SystemConfig.getInstance().getAllowIgnoreLocationSettings(), handler);
     }
 
     /**
@@ -94,14 +127,14 @@
     /**
      * Add a listener for changes to the location enabled setting.
      */
-    public void addOnLocationEnabledChangedListener(Runnable listener) {
+    public void addOnLocationEnabledChangedListener(UserSettingChangedListener listener) {
         mLocationMode.addListener(listener);
     }
 
     /**
      * Remove a listener for changes to the location enabled setting.
      */
-    public void removeOnLocationEnabledChangedListener(Runnable listener) {
+    public void removeOnLocationEnabledChangedListener(UserSettingChangedListener listener) {
         mLocationMode.addListener(listener);
     }
 
@@ -115,15 +148,16 @@
     /**
      * Add a listener for changes to the currently allowed location providers.
      */
-    public void addOnLocationProvidersAllowedChangedListener(Runnable runnable) {
-        mLocationProvidersAllowed.addListener(runnable);
+    public void addOnLocationProvidersAllowedChangedListener(UserSettingChangedListener listener) {
+        mLocationProvidersAllowed.addListener(listener);
     }
 
     /**
      * Remove a listener for changes to the currently allowed location providers.
      */
-    public void removeOnLocationProvidersAllowedChangedListener(Runnable runnable) {
-        mLocationProvidersAllowed.removeListener(runnable);
+    public void removeOnLocationProvidersAllowedChangedListener(
+            UserSettingChangedListener listener) {
+        mLocationProvidersAllowed.removeListener(listener);
     }
 
     /**
@@ -136,14 +170,16 @@
     /**
      * Add a listener for changes to the background throttle interval.
      */
-    public void addOnBackgroundThrottleIntervalChangedListener(Runnable listener) {
+    public void addOnBackgroundThrottleIntervalChangedListener(
+            GlobalSettingChangedListener listener) {
         mBackgroundThrottleIntervalMs.addListener(listener);
     }
 
     /**
      * Remove a listener for changes to the background throttle interval.
      */
-    public void removeOnBackgroundThrottleIntervalChangedListener(Runnable listener) {
+    public void removeOnBackgroundThrottleIntervalChangedListener(
+            GlobalSettingChangedListener listener) {
         mBackgroundThrottleIntervalMs.removeListener(listener);
     }
 
@@ -175,42 +211,46 @@
     /**
      * Retrieve the background throttle package whitelist.
      */
-    public List<String> getBackgroundThrottlePackageWhitelist() {
+    public Set<String> getBackgroundThrottlePackageWhitelist() {
         return mBackgroundThrottlePackageWhitelist.getValue();
     }
 
     /**
      * Add a listener for changes to the background throttle package whitelist.
      */
-    public void addOnBackgroundThrottlePackageWhitelistChangedListener(Runnable listener) {
+    public void addOnBackgroundThrottlePackageWhitelistChangedListener(
+            GlobalSettingChangedListener listener) {
         mBackgroundThrottlePackageWhitelist.addListener(listener);
     }
 
     /**
      * Remove a listener for changes to the background throttle package whitelist.
      */
-    public void removeOnBackgroundThrottlePackageWhitelistChangedListener(Runnable listener) {
+    public void removeOnBackgroundThrottlePackageWhitelistChangedListener(
+            GlobalSettingChangedListener listener) {
         mBackgroundThrottlePackageWhitelist.removeListener(listener);
     }
 
     /**
      * Retrieve the ignore settings package whitelist.
      */
-    public List<String> getIgnoreSettingsPackageWhitelist() {
+    public Set<String> getIgnoreSettingsPackageWhitelist() {
         return mIgnoreSettingsPackageWhitelist.getValue();
     }
 
     /**
      * Add a listener for changes to the ignore settings package whitelist.
      */
-    public void addOnIgnoreSettingsPackageWhitelistChangedListener(Runnable listener) {
+    public void addOnIgnoreSettingsPackageWhitelistChangedListener(
+            GlobalSettingChangedListener listener) {
         mIgnoreSettingsPackageWhitelist.addListener(listener);
     }
 
     /**
      * Remove a listener for changes to the ignore settings package whitelist.
      */
-    public void removeOnIgnoreSettingsPackageWhitelistChangedListener(Runnable listener) {
+    public void removeOnIgnoreSettingsPackageWhitelistChangedListener(
+            GlobalSettingChangedListener listener) {
         mIgnoreSettingsPackageWhitelist.removeListener(listener);
     }
 
@@ -264,7 +304,7 @@
             }
         }
 
-        List<String> backgroundThrottlePackageWhitelist =
+        Set<String> backgroundThrottlePackageWhitelist =
                 mBackgroundThrottlePackageWhitelist.getValue();
         if (!backgroundThrottlePackageWhitelist.isEmpty()) {
             ipw.println("Throttling Whitelisted Packages:");
@@ -275,7 +315,7 @@
             ipw.decreaseIndent();
         }
 
-        List<String> ignoreSettingsPackageWhitelist = mIgnoreSettingsPackageWhitelist.getValue();
+        Set<String> ignoreSettingsPackageWhitelist = mIgnoreSettingsPackageWhitelist.getValue();
         if (!ignoreSettingsPackageWhitelist.isEmpty()) {
             ipw.println("Bypass Whitelisted Packages:");
             ipw.increaseIndent();
@@ -288,7 +328,7 @@
 
     private abstract static class ObservingSetting extends ContentObserver {
 
-        private final CopyOnWriteArrayList<Runnable> mListeners;
+        private final CopyOnWriteArrayList<UserSettingChangedListener> mListeners;
 
         private ObservingSetting(Context context, String settingName, Handler handler) {
             super(handler);
@@ -298,11 +338,11 @@
                     getUriFor(settingName), false, this, UserHandle.USER_ALL);
         }
 
-        public void addListener(Runnable listener) {
+        public void addListener(UserSettingChangedListener listener) {
             mListeners.add(listener);
         }
 
-        public void removeListener(Runnable listener) {
+        public void removeListener(UserSettingChangedListener listener) {
             mListeners.remove(listener);
         }
 
@@ -310,8 +350,8 @@
 
         @Override
         public void onChange(boolean selfChange, Uri uri, int userId) {
-            for (Runnable listener : mListeners) {
-                listener.run();
+            for (UserSettingChangedListener listener : mListeners) {
+                listener.onSettingChanged(userId);
             }
         }
     }
@@ -354,6 +394,8 @@
         }
 
         public synchronized List<String> getValueForUser(int userId) {
+            Preconditions.checkArgument(userId != UserHandle.USER_NULL);
+
             if (userId != mCachedUserId) {
                 String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(),
                         mSettingName, userId);
@@ -409,29 +451,30 @@
         }
     }
 
-    private static class StringListCachedGlobalSetting extends ObservingSetting {
+    private static class StringSetCachedGlobalSetting extends ObservingSetting {
 
         private final Context mContext;
         private final String mSettingName;
+        private final Supplier<ArraySet<String>> mBaseValuesSupplier;
 
         private boolean mValid;
-        private List<String> mCachedValue;
+        private ArraySet<String> mCachedValue;
 
-        private StringListCachedGlobalSetting(Context context, String settingName,
-                Handler handler) {
+        private StringSetCachedGlobalSetting(Context context, String settingName,
+                Supplier<ArraySet<String>> baseValuesSupplier, Handler handler) {
             super(context, settingName, handler);
             mContext = context;
             mSettingName = settingName;
+            mBaseValuesSupplier = baseValuesSupplier;
         }
 
-        public synchronized List<String> getValue() {
+        public synchronized Set<String> getValue() {
             if (!mValid) {
+                mCachedValue = new ArraySet<>(mBaseValuesSupplier.get());
                 String setting = Settings.Global.getString(mContext.getContentResolver(),
                         mSettingName);
-                if (TextUtils.isEmpty(setting)) {
-                    mCachedValue = Collections.emptyList();
-                } else {
-                    mCachedValue = Arrays.asList(setting.split(","));
+                if (!TextUtils.isEmpty(setting)) {
+                    mCachedValue.addAll(Arrays.asList(setting.split(",")));
                 }
                 mValid = true;
             }
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index a4e7ac4..ec4aedd 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -181,6 +181,7 @@
     private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge";
     private static final String PREV_SYNTHETIC_PASSWORD_HANDLE_KEY = "prev-sp-handle";
     private static final String SYNTHETIC_PASSWORD_UPDATE_TIME_KEY = "sp-handle-ts";
+    private static final String USER_SERIAL_NUMBER_KEY = "serial-number";
 
     // No challenge provided
     private static final int CHALLENGE_NONE = 0;
@@ -378,7 +379,7 @@
         if (DEBUG) Slog.v(TAG, "Tie managed profile to parent now!");
         try (LockscreenCredential unifiedProfilePassword = generateRandomProfilePassword()) {
             setLockCredentialInternal(unifiedProfilePassword, managedUserPassword, managedUserId,
-                    false, /* isLockTiedToParent= */ true);
+                    /* isLockTiedToParent= */ true);
             tieProfileLockToParent(managedUserId, unifiedProfilePassword);
         }
     }
@@ -661,6 +662,34 @@
     }
 
     /**
+     * Clean up states associated with the given user, in case the userId is reused but LSS didn't
+     * get a chance to do cleanup previously during ACTION_USER_REMOVED.
+     *
+     * Internally, LSS stores serial number for each user and check it against the current user's
+     * serial number to determine if the userId is reused and invoke cleanup code.
+     */
+    private void cleanupDataForReusedUserIdIfNecessary(int userId) {
+        if (userId == UserHandle.USER_SYSTEM) {
+            // Short circuit as we never clean up user 0.
+            return;
+        }
+        // Serial number is never reusued, so we can use it as a distinguisher for user Id reuse.
+        int serialNumber = mUserManager.getUserSerialNumber(userId);
+
+        int storedSerialNumber = getIntUnchecked(USER_SERIAL_NUMBER_KEY, -1, userId);
+        if (storedSerialNumber != serialNumber) {
+            // If LockSettingsStorage does not have a copy of the serial number, it could be either
+            // this is a user created before the serial number recording logic is introduced, or
+            // the user does not exist or was removed and cleaned up properly. In either case, don't
+            // invoke removeUser().
+            if (storedSerialNumber != -1) {
+                removeUser(userId, /* unknownUser */ true);
+            }
+            setIntUnchecked(USER_SERIAL_NUMBER_KEY, serialNumber, userId);
+        }
+    }
+
+    /**
      * Check if profile got unlocked but the keystore is still locked. This happens on full disk
      * encryption devices since the profile may not yet be running when we consider unlocking it
      * during the normal flow. In this case unlock the keystore for the profile.
@@ -684,6 +713,7 @@
         mHandler.post(new Runnable() {
             @Override
             public void run() {
+                cleanupDataForReusedUserIdIfNecessary(userId);
                 ensureProfileKeystoreUnlocked(userId);
                 // Hide notification first, as tie managed profile lock takes time
                 hideEncryptionNotification(new UserHandle(userId));
@@ -729,9 +759,6 @@
             if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
                 // Notify keystore that a new user was added.
                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
-                if (userHandle > UserHandle.USER_SYSTEM) {
-                    removeUser(userHandle, /* unknownUser= */ true);
-                }
                 final KeyStore ks = KeyStore.getInstance();
                 final UserInfo parentInfo = mUserManager.getProfileParent(userHandle);
                 final int parentHandle = parentInfo != null ? parentInfo.id : -1;
@@ -1066,6 +1093,10 @@
         setStringUnchecked(key, userId, Long.toString(value));
     }
 
+    private void setIntUnchecked(String key, int value, int userId) {
+        setStringUnchecked(key, userId, Integer.toString(value));
+    }
+
     @Override
     public void setString(String key, String value, int userId) {
         checkWritePermission(userId);
@@ -1104,6 +1135,11 @@
         return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
     }
 
+    private int getIntUnchecked(String key, int defaultValue, int userId) {
+        String value = getStringUnchecked(key, null, userId);
+        return TextUtils.isEmpty(value) ? defaultValue : Integer.parseInt(value);
+    }
+
     @Override
     public String getString(String key, String defaultValue, int userId) {
         checkReadPermission(key, userId);
@@ -1437,17 +1473,12 @@
                         setLockCredentialInternal(LockscreenCredential.createNone(),
                                 profilePasswordMap.get(managedUserId),
                                 managedUserId,
-                                false, /* isLockTiedToParent= */ true);
+                                /* isLockTiedToParent= */ true);
+                        mStorage.removeChildProfileLock(managedUserId);
+                        removeKeystoreProfileKey(managedUserId);
                     } else {
-                        Slog.wtf(TAG, "clear tied profile challenges, but no password supplied.");
-                        // Attempt an untrusted reset by supplying an empty credential.
-                        setLockCredentialInternal(LockscreenCredential.createNone(),
-                                LockscreenCredential.createNone(),
-                                managedUserId,
-                                true, /* isLockTiedToParent= */ true);
+                        Slog.wtf(TAG, "Attempt to clear tied challenge, but no password supplied.");
                     }
-                    mStorage.removeChildProfileLock(managedUserId);
-                    removeKeystoreProfileKey(managedUserId);
                 }
             }
         }
@@ -1531,7 +1562,7 @@
     // should call setLockCredentialInternal.
     @Override
     public boolean setLockCredential(LockscreenCredential credential,
-            LockscreenCredential savedCredential, int userId, boolean allowUntrustedChange) {
+            LockscreenCredential savedCredential, int userId) {
 
         if (!mLockPatternUtils.hasSecureLockScreen()) {
             throw new UnsupportedOperationException(
@@ -1540,7 +1571,7 @@
         checkWritePermission(userId);
         synchronized (mSeparateChallengeLock) {
             if (!setLockCredentialInternal(credential, savedCredential,
-                    userId, allowUntrustedChange, /* isLockTiedToParent= */ false)) {
+                    userId, /* isLockTiedToParent= */ false)) {
                 return false;
             }
             setSeparateProfileChallengeEnabledLocked(userId, true, /* unused */ null);
@@ -1562,14 +1593,13 @@
      *     credentials are being tied to its parent's credentials.
      */
     private boolean setLockCredentialInternal(LockscreenCredential credential,
-            LockscreenCredential savedCredential, int userId,
-            boolean allowUntrustedChange, boolean isLockTiedToParent) {
+            LockscreenCredential savedCredential, int userId, boolean isLockTiedToParent) {
         Preconditions.checkNotNull(credential);
         Preconditions.checkNotNull(savedCredential);
         synchronized (mSpManager) {
             if (isSyntheticPasswordBasedCredentialLocked(userId)) {
                 return spBasedSetLockCredentialInternalLocked(credential, savedCredential, userId,
-                        allowUntrustedChange, isLockTiedToParent);
+                        isLockTiedToParent);
             }
         }
 
@@ -1617,7 +1647,7 @@
             if (shouldMigrateToSyntheticPasswordLocked(userId)) {
                 initializeSyntheticPasswordLocked(currentHandle.hash, savedCredential, userId);
                 return spBasedSetLockCredentialInternalLocked(credential, savedCredential, userId,
-                        allowUntrustedChange, isLockTiedToParent);
+                        isLockTiedToParent);
             }
         }
         if (DEBUG) Slog.d(TAG, "setLockCredentialInternal: user=" + userId);
@@ -2039,7 +2069,7 @@
             }
             if (shouldReEnroll) {
                 setLockCredentialInternal(credential, credential,
-                        userId, false, /* isLockTiedToParent= */ false);
+                        userId, /* isLockTiedToParent= */ false);
             } else {
                 // Now that we've cleared of all required GK migration, let's do the final
                 // migration to synthetic password.
@@ -2171,10 +2201,9 @@
     }
 
     private void removeUser(int userId, boolean unknownUser) {
+        Slog.i(TAG, "RemoveUser: " + userId);
         mSpManager.removeUser(userId);
-        mStorage.removeUser(userId);
         mStrongAuth.removeUser(userId);
-        tryRemoveUserFromSpCacheLater(userId);
 
         final KeyStore ks = KeyStore.getInstance();
         ks.onUserRemoved(userId);
@@ -2183,6 +2212,9 @@
         if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) {
             removeKeystoreProfileKey(userId);
         }
+        // Clean up storage last, this is to ensure that cleanupDataForReusedUserIdIfNecessary()
+        // can make the assumption that no USER_SERIAL_NUMBER_KEY means user is fully removed.
+        mStorage.removeUser(userId);
     }
 
     private void removeKeystoreProfileKey(int targetUserId) {
@@ -2432,25 +2464,7 @@
         }
     }
 
-    /**
-     * A user's synthetic password does not change so it must be cached in certain circumstances to
-     * enable untrusted credential reset.
-     *
-     * Untrusted credential reset will be removed in a future version (b/68036371) at which point
-     * this cache is no longer needed as the SP will always be known when changing the user's
-     * credential.
-     */
-    @GuardedBy("mSpManager")
-    private SparseArray<AuthenticationToken> mSpCache = new SparseArray<>();
-
     private void onAuthTokenKnownForUser(@UserIdInt int userId, AuthenticationToken auth) {
-        // Preemptively cache the SP and then try to remove it in a handler.
-        Slog.i(TAG, "Caching SP for user " + userId);
-        synchronized (mSpManager) {
-            mSpCache.put(userId, auth);
-        }
-        tryRemoveUserFromSpCacheLater(userId);
-
         if (mInjector.isGsiRunning()) {
             Slog.w(TAG, "AuthSecret disabled in GSI");
             return;
@@ -2471,42 +2485,6 @@
         }
     }
 
-    private void tryRemoveUserFromSpCacheLater(@UserIdInt int userId) {
-        mHandler.post(() -> {
-            if (!shouldCacheSpForUser(userId)) {
-                // The transition from 'should not cache' to 'should cache' can only happen if
-                // certain admin apps are installed after provisioning e.g. via adb. This is not
-                // a common case and we do not seamlessly support; it may result in the SP not
-                // being cached when it is needed. The cache can be re-populated by verifying
-                // the credential again.
-                Slog.i(TAG, "Removing SP from cache for user " + userId);
-                synchronized (mSpManager) {
-                    mSpCache.remove(userId);
-                }
-            }
-        });
-    }
-
-    /** Do not hold any of the locks from this service when calling. */
-    private boolean shouldCacheSpForUser(@UserIdInt int userId) {
-        // Before the user setup has completed, an admin could be installed that requires the SP to
-        // be cached (see below).
-        if (Settings.Secure.getIntForUser(mContext.getContentResolver(),
-                    Settings.Secure.USER_SETUP_COMPLETE, 0, userId) == 0) {
-            return true;
-        }
-
-        // If the user has an admin which can perform an untrusted credential reset, the SP needs to
-        // be cached. If there isn't a DevicePolicyManager then there can't be an admin in the first
-        // place so caching is not necessary.
-        final DevicePolicyManagerInternal dpmi = LocalServices.getService(
-                DevicePolicyManagerInternal.class);
-        if (dpmi == null) {
-            return false;
-        }
-        return dpmi.canUserHaveUntrustedCredentialReset(userId);
-    }
-
     /**
      * Precondition: vold and keystore unlocked.
      *
@@ -2540,8 +2518,8 @@
      *     This could also happen during an untrusted reset to clear password.
      *
      * 3. credentialhash == null and credential != null
-     *     This is the untrusted credential reset, OR the user sets a new lockscreen password
-     *     FOR THE FIRST TIME on a SP-enabled device. New credential and new SID will be created
+     *     The user sets a new lockscreen password FOR THE FIRST TIME on a SP-enabled device.
+     *     New credential and new SID will be created
      */
     @GuardedBy("mSpManager")
     @VisibleForTesting
@@ -2866,8 +2844,7 @@
      */
     @GuardedBy("mSpManager")
     private boolean spBasedSetLockCredentialInternalLocked(LockscreenCredential credential,
-            LockscreenCredential savedCredential, int userId,
-            boolean allowUntrustedChange, boolean isLockTiedToParent) {
+            LockscreenCredential savedCredential, int userId, boolean isLockTiedToParent) {
         if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId);
         if (savedCredential.isNone() && isManagedProfileWithUnifiedLock(userId)) {
             // get credential from keystore when managed profile has unified lock
@@ -2888,50 +2865,24 @@
         VerifyCredentialResponse response = authResult.gkResponse;
         AuthenticationToken auth = authResult.authToken;
 
-        // If existing credential is provided, the existing credential must match.
-        if (!savedCredential.isNone() && auth == null) {
-            Slog.w(TAG, "Failed to enroll: incorrect credential");
-            return false;
-        }
-        boolean untrustedReset = false;
-        if (auth != null) {
-            onAuthTokenKnownForUser(userId, auth);
-        } else if (response == null) {
-            throw new IllegalStateException("Password change failed.");
-        } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR) {
-            // We are performing an untrusted credential change, by DevicePolicyManager or other
-            // internal callers that don't provide the existing credential
-            Slog.w(TAG, "Untrusted credential change invoked");
-            // Try to get a cached auth token, so we can keep SP unchanged.
-            auth = mSpCache.get(userId);
-            if (!allowUntrustedChange) {
-                throw new IllegalStateException("Untrusted credential change was invoked but it was"
-                        + " not allowed. This is likely a bug. Auth token is null: "
-                        + Boolean.toString(auth == null));
+
+        if (auth == null) {
+            if (response == null
+                    || response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR) {
+                Slog.w(TAG, "Failed to enroll: incorrect credential.");
+                return false;
             }
-            untrustedReset = true;
-        } else /* responseCode == VerifyCredentialResponse.RESPONSE_RETRY */ {
-            Slog.w(TAG, "Rate limit exceeded, so password was not changed.");
-            return false;
+            if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
+                Slog.w(TAG, "Failed to enroll: rate limit exceeded.");
+                return false;
+            }
+            // Should not be reachable, but just in case.
+            throw new IllegalStateException("password change failed");
         }
 
-        if (auth != null) {
-            if (untrustedReset) {
-                // Force change the current SID to mantain existing behaviour that an untrusted
-                // reset leads to a change of SID. If the untrusted reset is for clearing the
-                // current password, the nuking of the SID will be done in
-                // setLockCredentialWithAuthTokenLocked next
-                mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
-            }
-            setLockCredentialWithAuthTokenLocked(credential, auth, userId);
-            mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId);
-        } else {
-            throw new IllegalStateException(
-                    "Untrusted credential reset not possible without cached SP");
-            // Could call initializeSyntheticPasswordLocked(null, credential, credentialType,
-            // requestedQuality, userId) instead if we still allow untrusted reset that changes
-            // synthetic password. That would invalidate existing escrow tokens though.
-        }
+        onAuthTokenKnownForUser(userId, auth);
+        setLockCredentialWithAuthTokenLocked(credential, auth, userId);
+        mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId);
         sendCredentialsOnChangeIfRequired(credential, userId, isLockTiedToParent);
         return true;
     }
@@ -3086,11 +3037,10 @@
                     + "verification.");
             return false;
         }
+        onAuthTokenKnownForUser(userId, result.authToken);
         long oldHandle = getSyntheticPasswordHandleLocked(userId);
         setLockCredentialWithAuthTokenLocked(credential, result.authToken, userId);
         mSpManager.destroyPasswordBasedSyntheticPassword(oldHandle, userId);
-
-        onAuthTokenKnownForUser(userId, result.authToken);
         return true;
     }
 
@@ -3209,8 +3159,6 @@
     private class DeviceProvisionedObserver extends ContentObserver {
         private final Uri mDeviceProvisionedUri = Settings.Global.getUriFor(
                 Settings.Global.DEVICE_PROVISIONED);
-        private final Uri mUserSetupCompleteUri = Settings.Secure.getUriFor(
-                Settings.Secure.USER_SETUP_COMPLETE);
 
         private boolean mRegistered;
 
@@ -3228,8 +3176,6 @@
                     reportDeviceSetupComplete();
                     clearFrpCredentialIfOwnerNotSecure();
                 }
-            } else if (mUserSetupCompleteUri.equals(uri)) {
-                tryRemoveUserFromSpCacheLater(userId);
             }
         }
 
@@ -3281,8 +3227,6 @@
             if (register) {
                 mContext.getContentResolver().registerContentObserver(mDeviceProvisionedUri,
                         false, this);
-                mContext.getContentResolver().registerContentObserver(mUserSetupCompleteUri,
-                        false, this, UserHandle.USER_ALL);
             } else {
                 mContext.getContentResolver().unregisterContentObserver(this);
             }
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index e9a8085..c53647d 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -136,8 +136,13 @@
         "android-synthetic-password-personalization-context".getBytes();
 
     static class AuthenticationResult {
-        public AuthenticationToken authToken;
-        public VerifyCredentialResponse gkResponse;
+        // Non-null if password/token passes verification, null otherwise
+        @Nullable public AuthenticationToken authToken;
+        // OK:    password / token passes verification, user has a lockscreen
+        // null:  user does not have a lockscreen (but password / token passes verification)
+        // ERROR: password / token fails verification
+        // RETRY: password / token verification is throttled at the moment.
+        @Nullable public VerifyCredentialResponse gkResponse;
     }
 
     /**
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index 91c9253..9a49c16 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.media.MediaRoute2Info;
 import android.media.MediaRoute2ProviderInfo;
+import android.os.Bundle;
 
 import java.util.Objects;
 
@@ -29,7 +30,7 @@
     final ComponentName mComponentName;
     final String mUniqueId;
 
-    private Callback mCallback;
+    Callback mCallback;
     private MediaRoute2ProviderInfo mProviderInfo;
 
     MediaRoute2Provider(@NonNull ComponentName componentName) {
@@ -77,6 +78,9 @@
     }
 
     public interface Callback {
-        void onProviderStateChanged(MediaRoute2Provider provider);
+        void onProviderStateChanged(@Nullable MediaRoute2Provider provider);
+        void onRouteSelected(@NonNull MediaRoute2ProviderProxy provider,
+                @NonNull String clientPackageName, @NonNull MediaRoute2Info route,
+                @Nullable Bundle controlHints, int seq);
     }
 }
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
index 3b6580a..a5abb18 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
@@ -26,6 +26,7 @@
 import android.media.MediaRoute2Info;
 import android.media.MediaRoute2ProviderInfo;
 import android.media.MediaRoute2ProviderService;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IBinder.DeathRecipient;
@@ -253,6 +254,20 @@
         setAndNotifyProviderInfo(info);
     }
 
+    private void onRouteSelected(Connection connection,
+            String packageName, String routeId, Bundle controlHints, int seq) {
+        if (mActiveConnection != connection) {
+            return;
+        }
+        MediaRoute2ProviderInfo providerInfo = getProviderInfo();
+        MediaRoute2Info route = (providerInfo == null) ? null : providerInfo.getRoute(routeId);
+        if (route == null) {
+            Slog.w(TAG, this + ": Unknown route " + routeId + " is selected from remove provider");
+            return;
+        }
+        mCallback.onRouteSelected(this, packageName, route, controlHints, seq);
+    }
+
     private void disconnect() {
         if (mActiveConnection != null) {
             mConnectionReady = false;
@@ -341,6 +356,11 @@
         void postProviderInfoUpdated(MediaRoute2ProviderInfo info) {
             mHandler.post(() -> onProviderInfoUpdated(Connection.this, info));
         }
+
+        void postRouteSelected(String packageName, String routeId, Bundle controlHints, int seq) {
+            mHandler.post(() -> onRouteSelected(Connection.this,
+                    packageName, routeId, controlHints, seq));
+        }
     }
 
     private static final class ProviderClient extends IMediaRoute2ProviderClient.Stub  {
@@ -361,5 +381,15 @@
                 connection.postProviderInfoUpdated(info);
             }
         }
+
+        @Override
+        public void notifyRouteSelected(String packageName, String routeId,
+                Bundle controlHints, int seq) {
+            Connection connection = mConnectionRef.get();
+            if (connection != null) {
+                connection.postRouteSelected(packageName, routeId, controlHints, seq);
+            }
+        }
+
     }
 }
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 2cf920d..9fcee50 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -26,7 +26,6 @@
 import android.content.pm.PackageManager;
 import android.media.IMediaRouter2Client;
 import android.media.IMediaRouter2Manager;
-import android.media.IMediaRouterClient;
 import android.media.MediaRoute2Info;
 import android.media.MediaRoute2ProviderInfo;
 import android.media.MediaRouter2;
@@ -71,13 +70,13 @@
     @GuardedBy("mLock")
     private final SparseArray<UserRecord> mUserRecords = new SparseArray<>();
     @GuardedBy("mLock")
-    private final ArrayMap<IBinder, ClientRecord> mAllClientRecords = new ArrayMap<>();
+    private final ArrayMap<IBinder, Client2Record> mAllClientRecords = new ArrayMap<>();
     @GuardedBy("mLock")
     private final ArrayMap<IBinder, ManagerRecord> mAllManagerRecords = new ArrayMap<>();
     @GuardedBy("mLock")
     private int mCurrentUserId = -1;
     @GuardedBy("mLock")
-    private int mSelectRouteRequestSequenceNumber = 0;
+    private int mSelectRouteRequestSequenceNumber = 1;
 
     MediaRouter2ServiceImpl(Context context) {
         mContext = context;
@@ -183,29 +182,14 @@
         }
     }
 
-    //TODO: What would happen if a media app used MediaRouter and MediaRouter2 simultaneously?
-    public void setControlCategories(@NonNull IMediaRouterClient client,
-            @Nullable List<String> categories) {
-        Objects.requireNonNull(client, "client must not be null");
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                ClientRecord clientRecord = mAllClientRecords.get(client.asBinder());
-                setControlCategoriesLocked(clientRecord, categories);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    public void setControlCategories2(@NonNull IMediaRouter2Client client,
+    public void setControlCategories(@NonNull IMediaRouter2Client client,
             @Nullable List<String> categories) {
         Objects.requireNonNull(client, "client must not be null");
 
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
-                ClientRecord clientRecord = mAllClientRecords.get(client.asBinder());
+                Client2Record clientRecord = mAllClientRecords.get(client.asBinder());
                 setControlCategoriesLocked(clientRecord, categories);
             }
         } finally {
@@ -218,7 +202,7 @@
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
-                requestSelectRoute2Locked(mAllClientRecords.get(client.asBinder()), route);
+                requestSelectRoute2Locked(mAllClientRecords.get(client.asBinder()), false, route);
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -295,37 +279,6 @@
         }
     }
 
-
-    public void registerClient(@NonNull IMediaRouterClient client, @NonNull String packageName) {
-        Objects.requireNonNull(client, "client must not be null");
-
-        final int uid = Binder.getCallingUid();
-        final int pid = Binder.getCallingPid();
-        final int userId = UserHandle.getUserId(uid);
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                registerClient1Locked(client, packageName, userId);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    public void unregisterClient(@NonNull IMediaRouterClient client) {
-        Objects.requireNonNull(client, "client must not be null");
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                unregisterClient1Locked(client);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
     //TODO: Review this is handling multi-user properly.
     void switchUser() {
         synchronized (mLock) {
@@ -389,7 +342,7 @@
     }
 
     private void unregisterClient2Locked(IMediaRouter2Client client, boolean died) {
-        Client2Record clientRecord = (Client2Record) mAllClientRecords.remove(client.asBinder());
+        Client2Record clientRecord = mAllClientRecords.remove(client.asBinder());
         if (clientRecord != null) {
             UserRecord userRecord = clientRecord.mUserRecord;
             userRecord.mClientRecords.remove(clientRecord);
@@ -399,10 +352,12 @@
         }
     }
 
-    private void requestSelectRoute2Locked(ClientRecord clientRecord, MediaRoute2Info route) {
+    private void requestSelectRoute2Locked(Client2Record clientRecord, boolean selectedByManager,
+            MediaRoute2Info route) {
         if (clientRecord != null) {
             MediaRoute2Info oldRoute = clientRecord.mSelectedRoute;
             clientRecord.mSelectingRoute = route;
+            clientRecord.mIsManagerSelecting = selectedByManager;
 
             UserHandler handler = clientRecord.mUserRecord.mHandler;
             //TODO: Handle transfer instead of unselect and select
@@ -417,7 +372,6 @@
                 handler.sendMessage(obtainMessage(
                         UserHandler::requestSelectRoute, handler, clientRecord.mPackageName,
                         route, seq));
-
                 // Remove all previous timeout messages
                 for (int previousSeq : clientRecord.mSelectRouteSequenceNumbers) {
                     clientRecord.mUserRecord.mHandler.removeMessages(previousSeq);
@@ -434,7 +388,7 @@
         }
     }
 
-    private void setControlCategoriesLocked(ClientRecord clientRecord, List<String> categories) {
+    private void setControlCategoriesLocked(Client2Record clientRecord, List<String> categories) {
         if (clientRecord != null) {
             clientRecord.mControlCategories = categories;
 
@@ -447,7 +401,7 @@
     private void sendControlRequestLocked(IMediaRouter2Client client, MediaRoute2Info route,
             Intent request) {
         final IBinder binder = client.asBinder();
-        ClientRecord clientRecord = mAllClientRecords.get(binder);
+        Client2Record clientRecord = mAllClientRecords.get(binder);
 
         if (clientRecord != null) {
             clientRecord.mUserRecord.mHandler.sendMessage(
@@ -459,7 +413,7 @@
     private void requestSetVolumeLocked(IMediaRouter2Client client, MediaRoute2Info route,
             int volume) {
         final IBinder binder = client.asBinder();
-        ClientRecord clientRecord = mAllClientRecords.get(binder);
+        Client2Record clientRecord = mAllClientRecords.get(binder);
 
         if (clientRecord != null) {
             clientRecord.mUserRecord.mHandler.sendMessage(
@@ -471,7 +425,7 @@
     private void requestUpdateVolumeLocked(IMediaRouter2Client client, MediaRoute2Info route,
             int delta) {
         final IBinder binder = client.asBinder();
-        ClientRecord clientRecord = mAllClientRecords.get(binder);
+        Client2Record clientRecord = mAllClientRecords.get(binder);
 
         if (clientRecord != null) {
             clientRecord.mUserRecord.mHandler.sendMessage(
@@ -510,7 +464,7 @@
                     obtainMessage(UserHandler::notifyRoutesToManager,
                             userRecord.mHandler, manager));
 
-            for (ClientRecord clientRecord : userRecord.mClientRecords) {
+            for (Client2Record clientRecord : userRecord.mClientRecords) {
                 // TODO: Do not use updateClientUsage since it updates all managers.
                 // Instead, Notify only to the manager that is currently being registered.
 
@@ -537,13 +491,13 @@
             String packageName, MediaRoute2Info route) {
         ManagerRecord managerRecord = mAllManagerRecords.get(manager.asBinder());
         if (managerRecord != null) {
-            ClientRecord clientRecord =
+            Client2Record clientRecord =
                     managerRecord.mUserRecord.findClientRecordLocked(packageName);
             if (clientRecord == null) {
                 Slog.w(TAG, "Ignoring route selection for unknown client.");
             }
             if (clientRecord != null && managerRecord.mTrusted) {
-                requestSelectRoute2Locked(clientRecord, route);
+                requestSelectRoute2Locked(clientRecord, true, route);
             }
         }
     }
@@ -599,41 +553,10 @@
         }
     }
 
-    private void registerClient1Locked(IMediaRouterClient client, String packageName,
-            int userId) {
-        final IBinder binder = client.asBinder();
-        if (mAllClientRecords.get(binder) == null) {
-            boolean newUser = false;
-            UserRecord userRecord = mUserRecords.get(userId);
-            if (userRecord == null) {
-                userRecord = new UserRecord(userId);
-                newUser = true;
-            }
-            ClientRecord clientRecord = new Client1Record(userRecord, client, packageName);
-
-            if (newUser) {
-                mUserRecords.put(userId, userRecord);
-                initializeUserLocked(userRecord);
-            }
-
-            userRecord.mClientRecords.add(clientRecord);
-            mAllClientRecords.put(binder, clientRecord);
-        }
-    }
-
-    private void unregisterClient1Locked(IMediaRouterClient client) {
-        ClientRecord clientRecord = mAllClientRecords.remove(client.asBinder());
-        if (clientRecord != null) {
-            UserRecord userRecord = clientRecord.mUserRecord;
-            userRecord.mClientRecords.remove(clientRecord);
-            disposeUserIfNeededLocked(userRecord);
-        }
-    }
-
     final class UserRecord {
         public final int mUserId;
         //TODO: make records private for thread-safety
-        final ArrayList<ClientRecord> mClientRecords = new ArrayList<>();
+        final ArrayList<Client2Record> mClientRecords = new ArrayList<>();
         final ArrayList<ManagerRecord> mManagerRecords = new ArrayList<>();
         final UserHandler mHandler;
 
@@ -642,8 +565,8 @@
             mHandler = new UserHandler(MediaRouter2ServiceImpl.this, this);
         }
 
-        ClientRecord findClientRecordLocked(String packageName) {
-            for (ClientRecord clientRecord : mClientRecords) {
+        Client2Record findClientRecordLocked(String packageName) {
+            for (Client2Record clientRecord : mClientRecords) {
                 if (TextUtils.equals(clientRecord.mPackageName, packageName)) {
                     return clientRecord;
                 }
@@ -652,42 +575,26 @@
         }
     }
 
-    class ClientRecord {
+    final class Client2Record implements IBinder.DeathRecipient {
         public final UserRecord mUserRecord;
         public final String mPackageName;
         public final List<Integer> mSelectRouteSequenceNumbers;
-        public List<String> mControlCategories;
-        public MediaRoute2Info mSelectingRoute;
-        public MediaRoute2Info mSelectedRoute;
-
-        ClientRecord(UserRecord userRecord, String packageName) {
-            mUserRecord = userRecord;
-            mPackageName = packageName;
-            mSelectRouteSequenceNumbers = new ArrayList<>();
-            mControlCategories = Collections.emptyList();
-        }
-    }
-
-    final class Client1Record extends ClientRecord {
-        public final IMediaRouterClient mClient;
-
-        Client1Record(UserRecord userRecord, IMediaRouterClient client,
-                String packageName) {
-            super(userRecord, packageName);
-            mClient = client;
-        }
-    }
-
-    final class Client2Record extends ClientRecord
-            implements IBinder.DeathRecipient {
         public final IMediaRouter2Client mClient;
         public final int mUid;
         public final int mPid;
         public final boolean mTrusted;
 
+        public List<String> mControlCategories;
+        public boolean mIsManagerSelecting;
+        public MediaRoute2Info mSelectingRoute;
+        public MediaRoute2Info mSelectedRoute;
+
         Client2Record(UserRecord userRecord, IMediaRouter2Client client,
                 int uid, int pid, String packageName, boolean trusted) {
-            super(userRecord, packageName);
+            mUserRecord = userRecord;
+            mPackageName = packageName;
+            mSelectRouteSequenceNumbers = new ArrayList<>();
+            mControlCategories = Collections.emptyList();
             mClient = client;
             mUid = uid;
             mPid = pid;
@@ -802,9 +709,8 @@
             sendMessage(PooledLambda.obtainMessage(UserHandler::updateProvider, this, provider));
         }
 
-        // TODO: When introducing MediaRoute2ProviderService#sendControlHints(),
-        // Make this method to be called.
-        public void onRouteSelectionRequestHandled(@NonNull MediaRoute2ProviderProxy provider,
+        @Override
+        public void onRouteSelected(@NonNull MediaRoute2ProviderProxy provider,
                 String clientPackageName, MediaRoute2Info route, Bundle controlHints, int seq) {
             sendMessage(PooledLambda.obtainMessage(
                     UserHandler::updateSelectedRoute, this, provider, clientPackageName, route,
@@ -907,15 +813,12 @@
                 return;
             }
 
-            ClientRecord clientRecord;
+            Client2Record clientRecord;
             synchronized (service.mLock) {
                 clientRecord = mUserRecord.findClientRecordLocked(clientPackageName);
             }
-            if (!(clientRecord instanceof Client2Record)) {
-                Log.w(TAG, "Ignoring route selection for unknown client.");
-                unselectRoute(clientPackageName, selectedRoute);
-                return;
-            }
+
+            //TODO: handle a case such that controlHints is null. (How should we notify MR2?)
 
             if (clientRecord.mSelectingRoute == null || !TextUtils.equals(
                     clientRecord.mSelectingRoute.getUniqueId(), selectedRoute.getUniqueId())) {
@@ -927,9 +830,11 @@
             clientRecord.mSelectingRoute = null;
             clientRecord.mSelectedRoute = selectedRoute;
 
-            notifyRouteSelectedToClient(((Client2Record) clientRecord).mClient,
+            notifyRouteSelectedToClient(clientRecord.mClient,
                     selectedRoute,
-                    MediaRouter2.SELECT_REASON_USER_SELECTED,
+                    clientRecord.mIsManagerSelecting
+                            ? MediaRouter2.SELECT_REASON_SYSTEM_SELECTED :
+                            MediaRouter2.SELECT_REASON_USER_SELECTED,
                     controlHints);
             updateClientUsage(clientRecord);
 
@@ -944,14 +849,10 @@
                 return;
             }
 
-            ClientRecord clientRecord;
+            Client2Record clientRecord;
             synchronized (service.mLock) {
                 clientRecord = mUserRecord.findClientRecordLocked(clientPackageName);
             }
-            if (!(clientRecord instanceof Client2Record)) {
-                Log.w(TAG, "Ignoring fallback route selection for unknown client.");
-                return;
-            }
 
             if (clientRecord.mSelectingRoute == null || !TextUtils.equals(
                     clientRecord.mSelectingRoute.getUniqueId(), selectingRoute.getUniqueId())) {
@@ -966,7 +867,7 @@
             MediaRoute2Info fallbackRoute = null;
             clientRecord.mSelectedRoute = fallbackRoute;
 
-            notifyRouteSelectedToClient(((Client2Record) clientRecord).mClient,
+            notifyRouteSelectedToClient(clientRecord.mClient,
                     fallbackRoute,
                     MediaRouter2.SELECT_REASON_FALLBACK,
                     Bundle.EMPTY /* controlHints */);
@@ -1023,10 +924,8 @@
                 return clients;
             }
             synchronized (service.mLock) {
-                for (ClientRecord clientRecord : mUserRecord.mClientRecords) {
-                    if (clientRecord instanceof Client2Record) {
-                        clients.add(((Client2Record) clientRecord).mClient);
-                    }
+                for (Client2Record clientRecord : mUserRecord.mClientRecords) {
+                    clients.add(clientRecord.mClient);
                 }
             }
             return clients;
@@ -1151,7 +1050,7 @@
             }
         }
 
-        private void updateClientUsage(ClientRecord clientRecord) {
+        private void updateClientUsage(Client2Record clientRecord) {
             MediaRouter2ServiceImpl service = mServiceRef.get();
             if (service == null) {
                 return;
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 9336af4..9c99e8f 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -249,7 +249,6 @@
             synchronized (mLock) {
                 registerClientLocked(client, uid, pid, packageName, resolvedUserId, trusted);
             }
-            mService2.registerClient(client, packageName);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -290,7 +289,6 @@
             synchronized (mLock) {
                 unregisterClientLocked(client, false);
             }
-            mService2.unregisterClient(client);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -397,12 +395,6 @@
 
     // Binder call
     @Override
-    public void setControlCategories(IMediaRouterClient client, List<String> controlCategories) {
-        mService2.setControlCategories(client, controlCategories);
-    }
-
-    // Binder call
-    @Override
     public void requestUpdateVolume(IMediaRouterClient client, String routeId, int direction) {
         if (client == null) {
             throw new IllegalArgumentException("client must not be null");
@@ -501,8 +493,8 @@
 
     // Binder call
     @Override
-    public void setControlCategories2(IMediaRouter2Client client, List<String> categories) {
-        mService2.setControlCategories2(client, categories);
+    public void setControlCategories(IMediaRouter2Client client, List<String> categories) {
+        mService2.setControlCategories(client, categories);
     }
 
     // Binder call
@@ -601,7 +593,6 @@
         synchronized (mLock) {
             unregisterClientLocked(clientRecord.mClient, true);
         }
-        mService2.unregisterClient(clientRecord.mClient);
     }
 
     private void registerClientLocked(IMediaRouterClient client,
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 77fbe41..4cb41da 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -16,7 +16,7 @@
 
 package com.android.server.net;
 
-import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
+import static android.Manifest.permission.NETWORK_STACK;
 import static android.provider.Settings.ACTION_VPN_SETTINGS;
 
 import android.annotation.NonNull;
@@ -202,8 +202,7 @@
         mVpn.setLockdown(true);
 
         final IntentFilter resetFilter = new IntentFilter(ACTION_LOCKDOWN_RESET);
-        mContext.registerReceiver(mResetReceiver, resetFilter, CONNECTIVITY_INTERNAL, mHandler);
-
+        mContext.registerReceiver(mResetReceiver, resetFilter, NETWORK_STACK, mHandler);
         handleStateChangedLocked();
     }
 
diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java
index 68cd5e7..2326ad3 100644
--- a/services/core/java/com/android/server/net/NetworkIdentitySet.java
+++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java
@@ -170,11 +170,11 @@
         return ident.compareTo(anotherIdent);
     }
 
-    public void writeToProto(ProtoOutputStream proto, long tag) {
+    public void dumpDebug(ProtoOutputStream proto, long tag) {
         final long start = proto.start(tag);
 
         for (NetworkIdentity ident : this) {
-            ident.writeToProto(proto, NetworkIdentitySetProto.IDENTITIES);
+            ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES);
         }
 
         proto.end(start);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 32d4b72..82d74bc 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -20,6 +20,9 @@
 import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
 import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
 import static android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS;
+import static android.Manifest.permission.NETWORK_SETTINGS;
+import static android.Manifest.permission.NETWORK_STACK;
+import static android.Manifest.permission.OBSERVE_NETWORK_POLICY;
 import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
 import static android.Manifest.permission.READ_PHONE_STATE;
 import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
@@ -33,6 +36,7 @@
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
 import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
 import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
 import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
@@ -153,6 +157,7 @@
 import android.net.NetworkQuotaInfo;
 import android.net.NetworkRequest;
 import android.net.NetworkSpecifier;
+import android.net.NetworkStack;
 import android.net.NetworkState;
 import android.net.NetworkStats;
 import android.net.NetworkTemplate;
@@ -217,7 +222,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
-import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.ConcurrentUtils;
 import com.android.internal.util.DumpUtils;
@@ -825,7 +829,7 @@
 
             // watch for network interfaces to be claimed
             final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
-            mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
+            mContext.registerReceiver(mConnReceiver, connFilter, NETWORK_STACK, mHandler);
 
             // listen for package changes to update policy
             final IntentFilter packageFilter = new IntentFilter();
@@ -1128,7 +1132,7 @@
         @Override
         public void limitReached(String limitName, String iface) {
             // only someone like NMS should be calling us
-            mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+            NetworkStack.checkNetworkStackPermission(mContext);
 
             if (!LIMIT_GLOBAL_ALERT.equals(limitName)) {
                 mHandler.obtainMessage(MSG_LIMIT_REACHED, iface).sendToTarget();
@@ -1483,7 +1487,7 @@
     private BroadcastReceiver mConnReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            // on background handler thread, and verified CONNECTIVITY_INTERNAL
+            // on background handler thread, and verified NETWORK_STACK
             // permission above.
             updateNetworksInternal();
         }
@@ -1651,10 +1655,10 @@
             // No need to do a permission check, because the ACTION_CARRIER_CONFIG_CHANGED
             // broadcast is protected and can't be spoofed. Runs on a background handler thread.
 
-            if (!intent.hasExtra(PhoneConstants.SUBSCRIPTION_KEY)) {
+            if (!intent.hasExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX)) {
                 return;
             }
-            final int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, -1);
+            final int subId = intent.getIntExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, -1);
 
             // Get all of our cross-process communication with telephony out of
             // the way before we acquire internal locks.
@@ -2721,17 +2725,35 @@
         return changed;
     }
 
+    private boolean checkAnyPermissionOf(String... permissions) {
+        for (String permission : permissions) {
+            if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void enforceAnyPermissionOf(String... permissions) {
+        if (!checkAnyPermissionOf(permissions)) {
+            throw new SecurityException("Requires one of the following permissions: "
+                    + String.join(", ", permissions) + ".");
+        }
+    }
+
     @Override
     public void registerListener(INetworkPolicyListener listener) {
-        // TODO: create permission for observing network policy
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        // TODO: Remove CONNECTIVITY_INTERNAL and the *AnyPermissionOf methods above after all apps
+        //  have declared OBSERVE_NETWORK_POLICY.
+        enforceAnyPermissionOf(CONNECTIVITY_INTERNAL, OBSERVE_NETWORK_POLICY);
         mListeners.register(listener);
     }
 
     @Override
     public void unregisterListener(INetworkPolicyListener listener) {
-        // TODO: create permission for observing network policy
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        // TODO: Remove CONNECTIVITY_INTERNAL and the *AnyPermissionOf methods above after all apps
+        //  have declared OBSERVE_NETWORK_POLICY.
+        enforceAnyPermissionOf(CONNECTIVITY_INTERNAL, OBSERVE_NETWORK_POLICY);
         mListeners.unregister(listener);
     }
 
@@ -4965,7 +4987,7 @@
 
     @Override
     public void factoryReset(String subscriber) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        mContext.enforceCallingOrSelfPermission(NETWORK_SETTINGS, TAG);
 
         if (mUserManager.hasUserRestriction(UserManager.DISALLOW_NETWORK_RESET)) {
             return;
@@ -4998,7 +5020,7 @@
     public boolean isUidNetworkingBlocked(int uid, boolean isNetworkMetered) {
         final long startTime = mStatLogger.getTime();
 
-        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+        mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
         final int uidRules;
         final boolean isBackgroundRestricted;
         synchronized (mUidRulesFirstLock) {
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index ab52523..05ab2ae 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -687,7 +687,7 @@
         }
     }
 
-    public void writeToProto(ProtoOutputStream proto, long tag) {
+    public void dumpDebug(ProtoOutputStream proto, long tag) {
         final long start = proto.start(tag);
 
         for (Key key : getSortedKeys()) {
@@ -695,7 +695,7 @@
 
             // Key
             final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY);
-            key.ident.writeToProto(proto, NetworkStatsCollectionKeyProto.IDENTITY);
+            key.ident.dumpDebug(proto, NetworkStatsCollectionKeyProto.IDENTITY);
             proto.write(NetworkStatsCollectionKeyProto.UID, key.uid);
             proto.write(NetworkStatsCollectionKeyProto.SET, key.set);
             proto.write(NetworkStatsCollectionKeyProto.TAG, key.tag);
@@ -703,7 +703,7 @@
 
             // Value
             final NetworkStatsHistory history = mStats.get(key);
-            history.writeToProto(proto, NetworkStatsCollectionStatsProto.HISTORY);
+            history.dumpDebug(proto, NetworkStatsCollectionStatsProto.HISTORY);
             proto.end(startStats);
         }
 
diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
index 06ec341..6af962b 100644
--- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
@@ -470,12 +470,12 @@
         }
     }
 
-    public void writeToProtoLocked(ProtoOutputStream proto, long tag) {
+    public void dumpDebugLocked(ProtoOutputStream proto, long tag) {
         final long start = proto.start(tag);
         if (mPending != null) {
             proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES, mPending.getTotalBytes());
         }
-        getOrLoadCompleteLocked().writeToProto(proto, NetworkStatsRecorderProto.COMPLETE_HISTORY);
+        getOrLoadCompleteLocked().dumpDebug(proto, NetworkStatsRecorderProto.COMPLETE_HISTORY);
         proto.end(start);
     }
 
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 08c9426..673e830 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -17,7 +17,6 @@
 package com.android.server.net;
 
 import static android.Manifest.permission.ACCESS_NETWORK_STATE;
-import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
 import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
 import static android.content.Intent.ACTION_SHUTDOWN;
 import static android.content.Intent.ACTION_UID_REMOVED;
@@ -91,6 +90,7 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkIdentity;
 import android.net.NetworkInfo;
+import android.net.NetworkStack;
 import android.net.NetworkState;
 import android.net.NetworkStats;
 import android.net.NetworkStats.NonMonotonicObserver;
@@ -138,7 +138,6 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
-import com.android.server.connectivity.Tethering;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -1021,8 +1020,6 @@
     private BroadcastReceiver mTetherReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            // on background handler thread, and verified CONNECTIVITY_INTERNAL
-            // permission above.
             performPoll(FLAG_PERSIST_NETWORK);
         }
     };
@@ -1096,7 +1093,7 @@
         @Override
         public void limitReached(String limitName, String iface) {
             // only someone like NMS should be calling us
-            mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+            NetworkStack.checkNetworkStackPermission(mContext);
 
             if (LIMIT_GLOBAL_ALERT.equals(limitName)) {
                 // kick off background poll to collect network stats unless there is already
@@ -1612,10 +1609,10 @@
 
         dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES, mActiveIfaces);
         dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES, mActiveUidIfaces);
-        mDevRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS);
-        mXtRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.XT_STATS);
-        mUidRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.UID_STATS);
-        mUidTagRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.UID_TAG_STATS);
+        mDevRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS);
+        mXtRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.XT_STATS);
+        mUidRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_STATS);
+        mUidTagRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_TAG_STATS);
 
         proto.flush();
     }
@@ -1626,7 +1623,7 @@
             final long start = proto.start(tag);
 
             proto.write(NetworkInterfaceProto.INTERFACE, ifaces.keyAt(i));
-            ifaces.valueAt(i).writeToProto(proto, NetworkInterfaceProto.IDENTITIES);
+            ifaces.valueAt(i).dumpDebug(proto, NetworkInterfaceProto.IDENTITIES);
 
             proto.end(start);
         }
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 8560ae6..45df368 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -379,18 +379,18 @@
 
         for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
             if (filter != null && !filter.matches(cmpt)) continue;
-            cmpt.writeToProto(proto, ManagedServicesProto.ENABLED);
+            cmpt.dumpDebug(proto, ManagedServicesProto.ENABLED);
         }
 
         synchronized (mMutex) {
             for (ManagedServiceInfo info : mServices) {
                 if (filter != null && !filter.matches(info.component)) continue;
-                info.writeToProto(proto, ManagedServicesProto.LIVE_SERVICES, this);
+                info.dumpDebug(proto, ManagedServicesProto.LIVE_SERVICES, this);
             }
         }
 
         for (ComponentName name : mSnoozingForCurrentProfiles) {
-            name.writeToProto(proto, ManagedServicesProto.SNOOZED);
+            name.dumpDebug(proto, ManagedServicesProto.SNOOZED);
         }
     }
 
@@ -1497,9 +1497,9 @@
                     .append(']').toString();
         }
 
-        public void writeToProto(ProtoOutputStream proto, long fieldId, ManagedServices host) {
+        public void dumpDebug(ProtoOutputStream proto, long fieldId, ManagedServices host) {
             final long token = proto.start(fieldId);
-            component.writeToProto(proto, ManagedServiceInfoProto.COMPONENT);
+            component.dumpDebug(proto, ManagedServiceInfoProto.COMPONENT);
             proto.write(ManagedServiceInfoProto.USER_ID, userid);
             proto.write(ManagedServiceInfoProto.SERVICE, service.getClass().getName());
             proto.write(ManagedServiceInfoProto.IS_SYSTEM, isSystem);
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
index 378ca4a..2247e54 100644
--- a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
+++ b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
@@ -183,6 +183,7 @@
     public NotificationHistory readNotificationHistory() {
         synchronized (mLock) {
             NotificationHistory notifications = new NotificationHistory();
+            notifications.addNotificationsToWrite(mBuffer);
 
             for (AtomicFile file : mHistoryFiles) {
                 try {
@@ -223,6 +224,13 @@
         }
     }
 
+    public void disableHistory() {
+        synchronized (mLock) {
+            mHistoryDir.delete();
+            mHistoryFiles.clear();
+        }
+    }
+
     /**
      * Remove any files that are too old and schedule jobs to clean up the rest
      */
@@ -241,6 +249,7 @@
                         Slog.d(TAG, "Removed " + currentOldestFile.getBaseFile().getName());
                     }
                     currentOldestFile.delete();
+                    // TODO: delete all relevant bitmaps, once they exist
                     mHistoryFiles.removeLast();
                 } else {
                     // all remaining files are newer than the cut off; schedule jobs to delete
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryManager.java b/services/core/java/com/android/server/notification/NotificationHistoryManager.java
index a350a6b..1b56c7b 100644
--- a/services/core/java/com/android/server/notification/NotificationHistoryManager.java
+++ b/services/core/java/com/android/server/notification/NotificationHistoryManager.java
@@ -21,9 +21,16 @@
 import android.annotation.UserIdInt;
 import android.app.NotificationHistory;
 import android.app.NotificationHistory.HistoricalNotification;
+import android.content.ContentResolver;
 import android.content.Context;
+import android.content.pm.UserInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
 import android.os.Environment;
+import android.os.Handler;
+import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Settings;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -49,6 +56,8 @@
 
     private final Context mContext;
     private final UserManager mUserManager;
+    @VisibleForTesting
+    final SettingsObserver mSettingsObserver;
     private final Object mLock = new Object();
     @GuardedBy("mLock")
     private final SparseArray<NotificationHistoryDatabase> mUserState = new SparseArray<>();
@@ -57,19 +66,26 @@
     // TODO: does this need to be persisted across reboots?
     @GuardedBy("mLock")
     private final SparseArray<List<String>> mUserPendingPackageRemovals = new SparseArray<>();
+    @GuardedBy("mLock")
+    private final SparseBooleanArray mHistoryEnabled = new SparseBooleanArray();
 
-    public NotificationHistoryManager(Context context) {
+    public NotificationHistoryManager(Context context, Handler handler) {
         mContext = context;
         mUserManager = context.getSystemService(UserManager.class);
+        mSettingsObserver = new SettingsObserver(handler);
     }
 
-    public void onUserUnlocked(@UserIdInt int userId) {
+    void onBootPhaseAppsCanStart() {
+        mSettingsObserver.observe();
+    }
+
+    void onUserUnlocked(@UserIdInt int userId) {
         synchronized (mLock) {
             mUserUnlockedStates.put(userId, true);
             final NotificationHistoryDatabase userHistory =
                     getUserHistoryAndInitializeIfNeededLocked(userId);
             if (userHistory == null) {
-                Slog.i(TAG, "Attempted to unlock stopped or removed user " + userId);
+                Slog.i(TAG, "Attempted to unlock gone/disabled user " + userId);
                 return;
             }
 
@@ -81,6 +97,11 @@
                 }
                 mUserPendingPackageRemovals.put(userId, null);
             }
+
+            // delete history if it was disabled when the user was locked
+            if (!mHistoryEnabled.get(userId)) {
+                userHistory.disableHistory();
+            }
         }
     }
 
@@ -91,22 +112,25 @@
         }
     }
 
-    void onUserRemoved(@UserIdInt int userId) {
+    public void onUserRemoved(@UserIdInt int userId) {
         synchronized (mLock) {
             // Actual data deletion is handled by other parts of the system (the entire directory is
             // removed) - we just need clean up our internal state for GC
             mUserPendingPackageRemovals.put(userId, null);
+            mHistoryEnabled.put(userId, false);
             onUserStopped(userId);
         }
     }
 
-    void onPackageRemoved(int userId, String packageName) {
+    public void onPackageRemoved(int userId, String packageName) {
         synchronized (mLock) {
             if (!mUserUnlockedStates.get(userId, false)) {
-                List<String> userPendingRemovals =
-                        mUserPendingPackageRemovals.get(userId, new ArrayList<>());
-                userPendingRemovals.add(packageName);
-                mUserPendingPackageRemovals.put(userId, userPendingRemovals);
+                if (mHistoryEnabled.get(userId, false)) {
+                    List<String> userPendingRemovals =
+                            mUserPendingPackageRemovals.get(userId, new ArrayList<>());
+                    userPendingRemovals.add(packageName);
+                    mUserPendingPackageRemovals.put(userId, userPendingRemovals);
+                }
                 return;
             }
             final NotificationHistoryDatabase userHistory = mUserState.get(userId);
@@ -118,7 +142,8 @@
         }
     }
 
-    void triggerWriteToDisk() {
+    // TODO: wire this up to AMS when power button is long pressed
+    public void triggerWriteToDisk() {
         synchronized (mLock) {
             final int userCount = mUserState.size();
             for (int i = 0; i < userCount; i++) {
@@ -139,7 +164,7 @@
             final NotificationHistoryDatabase userHistory =
                     getUserHistoryAndInitializeIfNeededLocked(notification.getUserId());
             if (userHistory == null) {
-                Slog.w(TAG, "Attempted to add notif for locked/gone user "
+                Slog.w(TAG, "Attempted to add notif for locked/gone/disabled user "
                         + notification.getUserId());
                 return;
             }
@@ -157,7 +182,7 @@
                 final NotificationHistoryDatabase userHistory =
                         getUserHistoryAndInitializeIfNeededLocked(userId);
                 if (userHistory == null) {
-                    Slog.i(TAG, "Attempted to read history for locked/gone user " +userId);
+                    Slog.i(TAG, "Attempted to read history for locked/gone/disabled user " +userId);
                     continue;
                 }
                 mergedHistory.addNotificationsToWrite(userHistory.readNotificationHistory());
@@ -172,7 +197,7 @@
             final NotificationHistoryDatabase userHistory =
                     getUserHistoryAndInitializeIfNeededLocked(userId);
             if (userHistory == null) {
-                Slog.i(TAG, "Attempted to read history for locked/gone user " +userId);
+                Slog.i(TAG, "Attempted to read history for locked/gone/disabled user " +userId);
                 return new android.app.NotificationHistory();
             }
 
@@ -180,9 +205,38 @@
         }
     }
 
+    boolean isHistoryEnabled(@UserIdInt int userId) {
+        synchronized (mLock) {
+            return mHistoryEnabled.get(userId);
+        }
+    }
+
+    void onHistoryEnabledChanged(@UserIdInt int userId, boolean historyEnabled) {
+        synchronized (mLock) {
+            mHistoryEnabled.put(userId, historyEnabled);
+
+            // These requests might fail if the user is locked; onUserUnlocked will pick up those
+            // cases
+            final NotificationHistoryDatabase userHistory =
+                    getUserHistoryAndInitializeIfNeededLocked(userId);
+            if (userHistory != null) {
+                if (!historyEnabled) {
+                    userHistory.disableHistory();
+                }
+            }
+        }
+    }
+
     @GuardedBy("mLock")
     private @Nullable NotificationHistoryDatabase getUserHistoryAndInitializeIfNeededLocked(
             int userId) {
+        if (!mHistoryEnabled.get(userId)) {
+            if (DEBUG) {
+                Slog.i(TAG, "History disabled for user " + userId);
+            }
+            mUserState.put(userId, null);
+            return null;
+        }
         NotificationHistoryDatabase userHistory = mUserState.get(userId);
         if (userHistory == null) {
             final File historyDir = new File(Environment.getDataSystemCeDirectory(userId),
@@ -242,4 +296,39 @@
             return mUserPendingPackageRemovals.get(userId);
         }
     }
+
+    final class SettingsObserver extends ContentObserver {
+        private final Uri NOTIFICATION_HISTORY_URI
+                = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_HISTORY_ENABLED);
+
+        SettingsObserver(Handler handler) {
+            super(handler);
+        }
+
+        void observe() {
+            ContentResolver resolver = mContext.getContentResolver();
+            resolver.registerContentObserver(NOTIFICATION_HISTORY_URI,
+                    false, this, UserHandle.USER_ALL);
+            synchronized (mLock) {
+                for (UserInfo userInfo : mUserManager.getUsers()) {
+                    update(null, userInfo.id);
+                }
+            }
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri, int userId) {
+            update(uri, userId);
+        }
+
+        public void update(Uri uri, int userId) {
+            ContentResolver resolver = mContext.getContentResolver();
+            if (uri == null || NOTIFICATION_HISTORY_URI.equals(uri)) {
+                boolean historyEnabled = Settings.Secure.getIntForUser(resolver,
+                        Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, userId)
+                        != 0;
+                onHistoryEnabledChanged(userId, historyEnabled);
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d5f2d7e..12afef2 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -103,6 +103,8 @@
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.WorkerThread;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
@@ -116,6 +118,8 @@
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationChannelGroup;
+import android.app.NotificationHistory;
+import android.app.NotificationHistory.HistoricalNotification;
 import android.app.NotificationManager;
 import android.app.NotificationManager.Policy;
 import android.app.PendingIntent;
@@ -160,12 +164,14 @@
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.IDeviceIdleController;
 import android.os.IInterface;
 import android.os.Looper;
 import android.os.Message;
+import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
@@ -287,6 +293,9 @@
     public static final boolean ENABLE_CHILD_NOTIFICATIONS
             = SystemProperties.getBoolean("debug.child_notifs", true);
 
+    // pullStats report request: undecorated remote view stats
+    public static final int REPORT_REMOTE_VIEWS = 0x01;
+
     static final boolean DEBUG_INTERRUPTIVENESS = SystemProperties.getBoolean(
             "debug.notification.interruptiveness", false);
 
@@ -319,6 +328,7 @@
     static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
 
     static final int INVALID_UID = -1;
+    static final String ROOT_PKG = "root";
 
     static final boolean ENABLE_BLOCKED_TOASTS = true;
 
@@ -477,12 +487,14 @@
     private long mLastOverRateLogTime;
     private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
 
+    private NotificationHistoryManager mHistoryManager;
     private SnoozeHelper mSnoozeHelper;
     private GroupHelper mGroupHelper;
     private int mAutoGroupAtCount;
     private boolean mIsTelevision;
     private boolean mIsAutomotive;
     private boolean mNotificationEffectsEnabledForAutomotive;
+    private DeviceConfig.OnPropertiesChangedListener mDeviceConfigChangedListener;
 
     private int mWarnRemoteViewsSizeBytes;
     private int mStripRemoteViewsSizeBytes;
@@ -1547,6 +1559,7 @@
                 mListeners.onUserRemoved(userId);
                 mConditionProviders.onUserRemoved(userId);
                 mAssistants.onUserRemoved(userId);
+                mHistoryManager.onUserRemoved(userId);
                 handleSavePolicyFile();
             } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
@@ -1775,8 +1788,8 @@
 
     // TODO: All tests should use this init instead of the one-off setters above.
     @VisibleForTesting
-    void init(Looper looper, RankingHandler rankingHandler, IPackageManager packageManager,
-            PackageManager packageManagerClient,
+    void init(WorkerHandler handler, RankingHandler rankingHandler,
+            IPackageManager packageManager, PackageManager packageManagerClient,
             LightsManager lightsManager, NotificationListeners notificationListeners,
             NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
             ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
@@ -1784,7 +1797,8 @@
             ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
             UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm,
             IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal, AppOpsManager appOps,
-            UserManager userManager) {
+            UserManager userManager, NotificationHistoryManager historyManager) {
+        mHandler = handler;
         Resources resources = getContext().getResources();
         mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
                 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
@@ -1810,7 +1824,6 @@
         mPlatformCompat = IPlatformCompat.Stub.asInterface(
                 ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
 
-        mHandler = new WorkerHandler(looper);
         mUiHandler = new Handler(UiThread.get().getLooper());
         String[] extractorNames;
         try {
@@ -1869,6 +1882,7 @@
                 extractorNames);
         mSnoozeHelper = snoozeHelper;
         mGroupHelper = groupHelper;
+        mHistoryManager = historyManager;
 
         // This is a ManagedServices object that keeps track of the listeners.
         mListeners = notificationListeners;
@@ -1966,7 +1980,9 @@
         final File systemDir = new File(Environment.getDataDirectory(), "system");
         mRankingThread.start();
 
-        init(Looper.myLooper(), new RankingHandlerWorker(mRankingThread.getLooper()),
+        WorkerHandler handler = new WorkerHandler(Looper.myLooper());
+
+        init(handler, new RankingHandlerWorker(mRankingThread.getLooper()),
                 AppGlobals.getPackageManager(), getContext().getPackageManager(),
                 getLocalService(LightsManager.class),
                 new NotificationListeners(AppGlobals.getPackageManager()),
@@ -1983,7 +1999,8 @@
                 UriGrantsManager.getService(),
                 LocalServices.getService(UriGrantsManagerInternal.class),
                 (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE),
-                getContext().getSystemService(UserManager.class));
+                getContext().getSystemService(UserManager.class),
+                new NotificationHistoryManager(getContext(), handler));
 
         // register for various Intents
         IntentFilter filter = new IntentFilter();
@@ -2036,19 +2053,26 @@
     }
 
     private void registerDeviceConfigChange() {
+        mDeviceConfigChangedListener = properties -> {
+            if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(properties.getNamespace())) {
+                return;
+            }
+            if (properties.getKeyset()
+                    .contains(SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE)) {
+                mAssistants.allowAdjustmentType(Adjustment.KEY_IMPORTANCE);
+                mAssistants.resetDefaultAssistantsIfNecessary();
+            }
+        };
         DeviceConfig.addOnPropertiesChangedListener(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
-                getContext().getMainExecutor(),
-                (properties) -> {
-                    if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(properties.getNamespace())) {
-                        return;
-                    }
-                    if (properties.getKeyset()
-                            .contains(SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE)) {
-                        mAssistants.allowAdjustmentType(Adjustment.KEY_IMPORTANCE);
-                        mAssistants.resetDefaultAssistantsIfNecessary();
-                    }
-                });
+                new HandlerExecutor(mHandler),
+                mDeviceConfigChangedListener);
+    }
+
+    void unregisterDeviceConfigChange() {
+        if (mDeviceConfigChangedListener != null) {
+            DeviceConfig.removeOnPropertiesChangedListener(mDeviceConfigChangedListener);
+        }
     }
 
     private GroupHelper getGroupHelper() {
@@ -2134,10 +2158,21 @@
             mListeners.onBootPhaseAppsCanStart();
             mAssistants.onBootPhaseAppsCanStart();
             mConditionProviders.onBootPhaseAppsCanStart();
+            mHistoryManager.onBootPhaseAppsCanStart();
             registerDeviceConfigChange();
         }
     }
 
+    @Override
+    public void onUnlockUser(@NonNull UserInfo userInfo) {
+        mHandler.post(() -> mHistoryManager.onUserUnlocked(userInfo.id));
+    }
+
+    @Override
+    public void onStopUser(@NonNull UserInfo userInfo) {
+        mHandler.post(() -> mHistoryManager.onUserStopped(userInfo.id));
+    }
+
     @GuardedBy("mNotificationLock")
     private void updateListenerHintsLocked() {
         final int hints = calculateHints();
@@ -2449,10 +2484,56 @@
             mAppUsageStats.reportInterruptiveNotification(r.sbn.getPackageName(),
                     r.getChannel().getId(),
                     getRealUserId(r.sbn.getUserId()));
+            mHistoryManager.addNotification(new HistoricalNotification.Builder()
+                    .setPackage(r.sbn.getPackageName())
+                    .setUid(r.sbn.getUid())
+                    .setChannelId(r.getChannel().getId())
+                    .setChannelName(r.getChannel().getName().toString())
+                    .setPostedTimeMs(r.sbn.getPostTime())
+                    .setTitle(getHistoryTitle(r.getNotification()))
+                    .setText(getHistoryText(
+                            r.sbn.getPackageContext(getContext()), r.getNotification()))
+                    .setIcon(r.getNotification().getSmallIcon())
+                    .build());
             r.setRecordedInterruption(true);
         }
     }
 
+    private String getHistoryTitle(Notification n) {
+        CharSequence title = null;
+        if (n.extras != null) {
+            title = n.extras.getCharSequence(Notification.EXTRA_TITLE);
+        }
+        return title == null? null : String.valueOf(title);
+    }
+
+    /**
+     * Returns the appropriate substring for this notification based on the style of notification.
+     */
+    private String getHistoryText(Context appContext, Notification n) {
+        CharSequence text = null;
+        if (n.extras != null) {
+            text = n.extras.getCharSequence(Notification.EXTRA_TEXT);
+
+            Notification.Builder nb = Notification.Builder.recoverBuilder(appContext, n);
+
+            if (nb.getStyle() instanceof Notification.BigTextStyle) {
+                text = ((Notification.BigTextStyle) nb.getStyle()).getBigText();
+            } else if (nb.getStyle() instanceof Notification.MessagingStyle) {
+                Notification.MessagingStyle ms = (Notification.MessagingStyle) nb.getStyle();
+                final List<Notification.MessagingStyle.Message> messages = ms.getMessages();
+                if (messages != null && messages.size() > 0) {
+                    text = messages.get(messages.size() - 1).getText();
+                }
+            }
+
+            if (TextUtils.isEmpty(text)) {
+                text = n.extras.getCharSequence(Notification.EXTRA_TEXT);
+            }
+        }
+        return text == null ? null : String.valueOf(text);
+    }
+
     /**
      * Report to usage stats that the user interacted with the notification.
      * @param r notification record
@@ -3343,10 +3424,9 @@
 
         /**
          * System-only API for getting a list of recent (cleared, no longer shown) notifications.
-         *
-         * Requires ACCESS_NOTIFICATIONS which is signature|system.
          */
         @Override
+        @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)
         public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
             // enforce() will ensure the calling uid has the correct permission
             getContext().enforceCallingOrSelfPermission(
@@ -3367,6 +3447,29 @@
         }
 
         /**
+         * System-only API for getting a list of historical notifications. May contain multiple days
+         * of notifications.
+         */
+        @Override
+        @WorkerThread
+        @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)
+        public NotificationHistory getNotificationHistory(String callingPkg) {
+            // enforce() will ensure the calling uid has the correct permission
+            getContext().enforceCallingOrSelfPermission(
+                    android.Manifest.permission.ACCESS_NOTIFICATIONS,
+                    "NotificationManagerService.getNotificationHistory");
+            int uid = Binder.getCallingUid();
+
+            // noteOp will check to make sure the callingPkg matches the uid
+            if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
+                    == AppOpsManager.MODE_ALLOWED) {
+                IntArray currentUserIds = mUserProfiles.getCurrentProfileIds();
+                return mHistoryManager.readNotificationHistory(currentUserIds.toArray());
+            }
+            return new NotificationHistory();
+        }
+
+        /**
          * Register a listener binder directly with the notification manager.
          *
          * Only works with system callers. Apps should extend
@@ -3981,6 +4084,8 @@
             try {
                 if (filter.stats) {
                     dumpJson(pw, filter);
+                } else if (filter.rvStats) {
+                    dumpRemoteViewStats(pw, filter);
                 } else if (filter.proto) {
                     dumpProto(fd, filter);
                 } else if (filter.criticalPriority) {
@@ -4457,6 +4562,49 @@
             new NotificationShellCmd(NotificationManagerService.this)
                     .exec(this, in, out, err, args, callback, resultReceiver);
         }
+
+        /**
+         * Get stats committed after startNs
+         *
+         * @param startNs Report stats committed after this time in nanoseconds.
+         * @param report  Indicatess which section to include in the stats.
+         * @param doAgg   Whether to aggregate the stats or keep them separated.
+         * @param out   List of protos of individual commits or one representing the
+         *                aggregate.
+         * @return the report time in nanoseconds, or 0 on error.
+         */
+        @Override
+        public long pullStats(long startNs, int report, boolean doAgg,
+                List<ParcelFileDescriptor> out) {
+            checkCallerIsSystemOrShell();
+            long startMs = TimeUnit.MILLISECONDS.convert(startNs, TimeUnit.NANOSECONDS);
+
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                switch (report) {
+                    case REPORT_REMOTE_VIEWS:
+                        Slog.e(TAG, "pullStats REPORT_REMOTE_VIEWS from: "
+                                + startMs + "  wtih " + doAgg);
+                        PulledStats stats = mUsageStats.remoteViewStats(startMs, doAgg);
+                        if (stats != null) {
+                            out.add(stats.toParcelFileDescriptor(report));
+                            Slog.e(TAG, "exiting pullStats with: " + out.size());
+                            long endNs = TimeUnit.NANOSECONDS
+                                    .convert(stats.endTimeMs(), TimeUnit.MILLISECONDS);
+                            return endNs;
+                        }
+                        Slog.e(TAG, "null stats for: " + report);
+                }
+            } catch (IOException e) {
+
+                Slog.e(TAG, "exiting pullStats: on error", e);
+                return 0;
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+            Slog.e(TAG, "exiting pullStats: bad request");
+            return 0;
+        }
     };
 
     @VisibleForTesting
@@ -4674,6 +4822,15 @@
         pw.println(dump);
     }
 
+    private void dumpRemoteViewStats(PrintWriter pw, @NonNull DumpFilter filter) {
+        PulledStats stats = mUsageStats.remoteViewStats(filter.since, true);
+        if (stats == null) {
+            pw.println("no remote view stats reported.");
+            return;
+        }
+        stats.dump(REPORT_REMOTE_VIEWS, pw, filter);
+    }
+
     private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) {
         final ProtoOutputStream proto = new ProtoOutputStream(fd);
         synchronized (mNotificationLock) {
@@ -4703,7 +4860,7 @@
             long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
             mZenModeHelper.dump(proto);
             for (ComponentName suppressor : mEffectsSuppressors) {
-                suppressor.writeToProto(proto, ZenModeProto.SUPPRESSORS);
+                suppressor.dumpDebug(proto, ZenModeProto.SUPPRESSORS);
             }
             proto.end(zenLog);
 
@@ -4723,7 +4880,7 @@
                     mListenersDisablingEffects.valueAt(i);
                 for (int j = 0; j < listeners.size(); j++) {
                     final ComponentName componentName = listeners.valueAt(j);
-                    componentName.writeToProto(proto,
+                    componentName.dumpDebug(proto,
                             ListenersDisablingEffectsProto.LISTENER_COMPONENTS);
                 }
 
@@ -6831,7 +6988,7 @@
         }
     }
 
-    private void handleOnPackageChanged(boolean removingPackage, int changeUserId,
+    void handleOnPackageChanged(boolean removingPackage, int changeUserId,
             String[] pkgList, int[] uidList) {
         boolean preferencesChanged = removingPackage;
         mListeners.onPackagesChanged(removingPackage, pkgList, uidList);
@@ -6839,6 +6996,14 @@
         mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList);
         preferencesChanged |= mPreferencesHelper.onPackagesChanged(
                 removingPackage, changeUserId, pkgList, uidList);
+        if (removingPackage) {
+            int size = Math.min(pkgList.length, uidList.length);
+            for (int i = 0; i < size; i++) {
+                final String pkg = pkgList[i];
+                final int uid = uidList[i];
+                mHistoryManager.onPackageRemoved(UserHandle.getUserId(uid), pkg);
+            }
+        }
         if (preferencesChanged) {
             handleSavePolicyFile();
         }
@@ -7673,7 +7838,8 @@
 
     protected boolean isUidSystemOrPhone(int uid) {
         final int appid = UserHandle.getAppId(uid);
-        return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
+        return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID
+                || uid == Process.ROOT_UID);
     }
 
     // TODO: Most calls should probably move to isCallerSystem.
@@ -7682,7 +7848,8 @@
     }
 
     private void checkCallerIsSystemOrShell() {
-        if (Binder.getCallingUid() == Process.SHELL_UID) {
+        int callingUid = Binder.getCallingUid();
+        if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
             return;
         }
         checkCallerIsSystem();
@@ -7696,7 +7863,8 @@
     }
 
     private void checkCallerIsSystemOrSystemUiOrShell() {
-        if (Binder.getCallingUid() == Process.SHELL_UID) {
+        int callingUid = Binder.getCallingUid();
+        if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
             return;
         }
         if (isCallerSystemOrPhone()) {
@@ -7771,6 +7939,9 @@
     }
 
     private void checkCallerIsSameApp(String pkg, int uid, int userId) {
+        if (uid == Process.ROOT_UID && ROOT_PKG.equals(pkg)) {
+            return;
+        }
         try {
             ApplicationInfo ai = mPackageManager.getApplicationInfo(
                     pkg, 0, userId);
@@ -8162,7 +8333,7 @@
             try {
                 assistant.onAllowedAdjustmentsChanged();
             } catch (RemoteException ex) {
-                Slog.e(TAG, "unable to notify assistant (capabilities): " + assistant, ex);
+                Slog.e(TAG, "unable to notify assistant (capabilities): " + info, ex);
             }
         }
 
@@ -8172,7 +8343,7 @@
             try {
                 assistant.onNotificationsSeen(keys);
             } catch (RemoteException ex) {
-                Slog.e(TAG, "unable to notify assistant (seen): " + assistant, ex);
+                Slog.e(TAG, "unable to notify assistant (seen): " + info, ex);
             }
         }
 
@@ -8478,7 +8649,7 @@
                         listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons);
                     } catch (RemoteException ex) {
                         Slog.e(TAG, "unable to notify listener "
-                                + "(hideSilentStatusIcons): " + listener, ex);
+                                + "(hideSilentStatusIcons): " + info, ex);
                     }
                 });
             }
@@ -8771,7 +8942,7 @@
             try {
                 listener.onNotificationPosted(sbnHolder, rankingUpdate);
             } catch (RemoteException ex) {
-                Slog.e(TAG, "unable to notify listener (posted): " + listener, ex);
+                Slog.e(TAG, "unable to notify listener (posted): " + info, ex);
             }
         }
 
@@ -8785,7 +8956,7 @@
             try {
                 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
             } catch (RemoteException ex) {
-                Slog.e(TAG, "unable to notify listener (removed): " + listener, ex);
+                Slog.e(TAG, "unable to notify listener (removed): " + info, ex);
             }
         }
 
@@ -8795,7 +8966,7 @@
             try {
                 listener.onNotificationRankingUpdate(rankingUpdate);
             } catch (RemoteException ex) {
-                Slog.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
+                Slog.e(TAG, "unable to notify listener (ranking update): " + info, ex);
             }
         }
 
@@ -8804,7 +8975,7 @@
             try {
                 listener.onListenerHintsChanged(hints);
             } catch (RemoteException ex) {
-                Slog.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
+                Slog.e(TAG, "unable to notify listener (listener hints): " + info, ex);
             }
         }
 
@@ -8814,7 +8985,7 @@
             try {
                 listener.onInterruptionFilterChanged(interruptionFilter);
             } catch (RemoteException ex) {
-                Slog.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
+                Slog.e(TAG, "unable to notify listener (interruption filter): " + info, ex);
             }
         }
 
@@ -8825,7 +8996,7 @@
             try {
                 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
             } catch (RemoteException ex) {
-                Slog.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
+                Slog.e(TAG, "unable to notify listener (channel changed): " + info, ex);
             }
         }
 
@@ -8836,7 +9007,7 @@
             try {
                 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
             } catch (RemoteException ex) {
-                Slog.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
+                Slog.e(TAG, "unable to notify listener (channel group changed): " + info, ex);
             }
         }
 
@@ -8971,6 +9142,7 @@
         public boolean zen;
         public long since;
         public boolean stats;
+        public boolean rvStats;
         public boolean redact = true;
         public boolean proto = false;
         public boolean criticalPriority = false;
@@ -9006,6 +9178,14 @@
                     } else {
                         filter.since = 0;
                     }
+                } else if ("--remote-view-stats".equals(a)) {
+                    filter.rvStats = true;
+                    if (ai < args.length-1) {
+                        ai++;
+                        filter.since = Long.parseLong(args[ai]);
+                    } else {
+                        filter.since = 0;
+                    }
                 } else if (PRIORITY_ARG.equals(a)) {
                     // Bugreport will call the service twice with priority arguments, first to dump
                     // critical sections and then non critical ones. Set approriate filters
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index a126073..b57bfa0 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -434,7 +434,7 @@
             proto.write(NotificationRecordProto.SOUND, getSound().toString());
         }
         if (getAudioAttributes() != null) {
-            getAudioAttributes().writeToProto(proto, NotificationRecordProto.AUDIO_ATTRIBUTES);
+            getAudioAttributes().dumpDebug(proto, NotificationRecordProto.AUDIO_ATTRIBUTES);
         }
         proto.write(NotificationRecordProto.PACKAGE, sbn.getPackageName());
         proto.write(NotificationRecordProto.DELEGATE_PACKAGE, sbn.getOpPkg());
diff --git a/services/core/java/com/android/server/notification/NotificationShellCmd.java b/services/core/java/com/android/server/notification/NotificationShellCmd.java
index 50f16bc..2b5ba25 100644
--- a/services/core/java/com/android/server/notification/NotificationShellCmd.java
+++ b/services/core/java/com/android/server/notification/NotificationShellCmd.java
@@ -125,9 +125,13 @@
         final int callingUid = Binder.getCallingUid();
         long identity = Binder.clearCallingIdentity();
         try {
-            String[] packages = mPm.getPackagesForUid(callingUid);
-            if (packages != null && packages.length > 0) {
-                callingPackage = packages[0];
+            if (callingUid == Process.ROOT_UID) {
+                callingPackage = NotificationManagerService.ROOT_PKG;
+            } else {
+                String[] packages = mPm.getPackagesForUid(callingUid);
+                if (packages != null && packages.length > 0) {
+                    callingPackage = packages[0];
+                }
             }
         } catch (Exception e) {
             Slog.e(TAG, "failed to get caller pkg", e);
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index fe3d0eb..ac8d1a9 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -149,6 +149,7 @@
             stats.numPostedByApp++;
             stats.updateInterarrivalEstimate(now);
             stats.countApiUse(notification);
+            stats.numUndecoratedRemoteViews += (isUndecoratedRemoteView(notification) ? 1 : 0);
         }
         releaseAggregatedStatsLocked(aggregatedStatsArray);
         if (ENABLE_SQLITE_LOG) {
@@ -157,6 +158,13 @@
     }
 
     /**
+     * Does this notification use RemoveViews without a platform decoration?
+     */
+    protected static boolean isUndecoratedRemoteView(NotificationRecord notification) {
+        return (notification.getNotification().getNotificationStyle() == null);
+    }
+
+    /**
      * Called when a notification has been updated.
      */
     public synchronized void registerUpdatedByApp(NotificationRecord notification,
@@ -337,6 +345,15 @@
         return dump;
     }
 
+    public PulledStats remoteViewStats(long startMs, boolean aggregate) {
+        if (ENABLE_SQLITE_LOG) {
+            if (aggregate) {
+                return mSQLiteLog.remoteViewAggStats(startMs);
+            }
+        }
+        return null;
+    }
+
     public synchronized void dump(PrintWriter pw, String indent, DumpFilter filter) {
         if (ENABLE_AGGREGATED_IN_MEMORY_STATS) {
             for (AggregatedStats as : mStats.values()) {
@@ -414,6 +431,7 @@
         public int numRateViolations;
         public int numAlertViolations;
         public int numQuotaViolations;
+        public int numUndecoratedRemoteViews;
         public long mLastAccessTime;
         public int numImagesRemoved;
 
@@ -685,6 +703,8 @@
             output.append(indentPlusTwo).append(noisyImportance.toString()).append("\n");
             output.append(indentPlusTwo).append(quietImportance.toString()).append("\n");
             output.append(indentPlusTwo).append(finalImportance.toString()).append("\n");
+            output.append(indentPlusTwo);
+            output.append("numUndecorateRVs=").append(numUndecoratedRemoteViews).append("\n");
             output.append(indent).append("}");
             return output.toString();
         }
@@ -1044,7 +1064,7 @@
         private static final int MSG_DISMISS = 4;
 
         private static final String DB_NAME = "notification_log.db";
-        private static final int DB_VERSION = 5;
+        private static final int DB_VERSION = 7;
 
         /** Age in ms after which events are pruned from the DB. */
         private static final long HORIZON_MS = 7 * 24 * 60 * 60 * 1000L;  // 1 week
@@ -1077,6 +1097,7 @@
         private static final String COL_FIRST_EXPANSIONTIME_MS = "first_expansion_time_ms";
         private static final String COL_AIRTIME_EXPANDED_MS = "expansion_airtime_ms";
         private static final String COL_EXPAND_COUNT = "expansion_count";
+        private static final String COL_UNDECORATED = "undecorated";
 
 
         private static final int EVENT_TYPE_POST = 1;
@@ -1102,12 +1123,20 @@
                 "COUNT(*) AS cnt, " +
                 "SUM(" + COL_MUTED + ") as muted, " +
                 "SUM(" + COL_NOISY + ") as noisy, " +
-                "SUM(" + COL_DEMOTED + ") as demoted " +
+                "SUM(" + COL_DEMOTED + ") as demoted, " +
+                "SUM(" + COL_UNDECORATED + ") as undecorated " +
                 "FROM " + TAB_LOG + " " +
                 "WHERE " +
                 COL_EVENT_TYPE + "=" + EVENT_TYPE_POST +
                 " AND " + COL_EVENT_TIME + " > %d " +
                 " GROUP BY " + COL_EVENT_USER_ID + ", day, " + COL_PKG;
+        private static final String UNDECORATED_QUERY = "SELECT " +
+                COL_PKG + ", " +
+                "MAX(" + COL_EVENT_TIME + ") as max_time " +
+                "FROM " + TAB_LOG + " " +
+                "WHERE " + COL_UNDECORATED + "> 0 " +
+                " AND " + COL_EVENT_TIME + " > %d " +
+                "GROUP BY " + COL_PKG;
 
         public SQLiteLog(Context context) {
             HandlerThread backgroundThread = new HandlerThread("notification-sqlite-log",
@@ -1163,7 +1192,8 @@
                             COL_AIRTIME_MS + " INT," +
                             COL_FIRST_EXPANSIONTIME_MS + " INT," +
                             COL_AIRTIME_EXPANDED_MS + " INT," +
-                            COL_EXPAND_COUNT + " INT" +
+                            COL_EXPAND_COUNT + " INT," +
+                            COL_UNDECORATED + " INT" +
                             ")");
                 }
 
@@ -1273,6 +1303,7 @@
             } else {
                 putPosttimeVisibility(r, cv);
             }
+            cv.put(COL_UNDECORATED, (isUndecoratedRemoteView(r) ? 1 : 0));
             SQLiteDatabase db = mHelper.getWritableDatabase();
             if (db.insert(TAB_LOG, null, cv) < 0) {
                 Log.wtf(TAG, "Error while trying to insert values: " + cv);
@@ -1353,5 +1384,22 @@
             }
             return dump;
         }
+
+        public PulledStats remoteViewAggStats(long startMs) {
+            PulledStats stats = new PulledStats(startMs);
+            SQLiteDatabase db = mHelper.getReadableDatabase();
+            String q = String.format(UNDECORATED_QUERY, startMs);
+            Cursor cursor = db.rawQuery(q, null);
+            try {
+                for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
+                    String pkg = cursor.getString(0);
+                    long maxTimeMs = cursor.getLong(1);
+                    stats.addUndecoratedPackage(pkg, maxTimeMs);
+                }
+            } finally {
+                cursor.close();
+            }
+            return stats;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index cbbf2a0..b1ffa8c 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -1564,10 +1564,10 @@
                 proto.write(RankingHelperProto.RecordProto.SHOW_BADGE, r.showBadge);
 
                 for (NotificationChannel channel : r.channels.values()) {
-                    channel.writeToProto(proto, RankingHelperProto.RecordProto.CHANNELS);
+                    channel.dumpDebug(proto, RankingHelperProto.RecordProto.CHANNELS);
                 }
                 for (NotificationChannelGroup group : r.groups.values()) {
-                    group.writeToProto(proto, RankingHelperProto.RecordProto.CHANNEL_GROUPS);
+                    group.dumpDebug(proto, RankingHelperProto.RecordProto.CHANNEL_GROUPS);
                 }
 
                 proto.end(fToken);
diff --git a/services/core/java/com/android/server/notification/PulledStats.java b/services/core/java/com/android/server/notification/PulledStats.java
new file mode 100644
index 0000000..ada890a
--- /dev/null
+++ b/services/core/java/com/android/server/notification/PulledStats.java
@@ -0,0 +1,129 @@
+/*
+ * 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.notification;
+
+import static com.android.server.notification.NotificationManagerService.REPORT_REMOTE_VIEWS;
+
+import android.os.ParcelFileDescriptor;
+import android.service.notification.NotificationRemoteViewsProto;
+import android.service.notification.PackageRemoteViewInfoProto;
+import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+public class PulledStats {
+    static final String TAG = "PulledStats";
+
+    private final long mTimePeriodStartMs;
+    private long mTimePeriodEndMs;
+    private List<String> mUndecoratedPackageNames;
+
+    public PulledStats(long startMs) {
+        mTimePeriodEndMs = mTimePeriodStartMs = startMs;
+        mUndecoratedPackageNames = new ArrayList<>();
+    }
+
+    ParcelFileDescriptor toParcelFileDescriptor(int report)
+            throws IOException {
+        final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
+        switch(report) {
+            case REPORT_REMOTE_VIEWS:
+                Thread thr = new Thread("NotificationManager pulled metric output") {
+                    public void run() {
+                        try {
+                            FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(
+                                    fds[1]);
+                            final ProtoOutputStream proto = new ProtoOutputStream(fout);
+                            writeToProto(report, proto);
+                            proto.flush();
+                            fout.close();
+                        } catch (IOException e) {
+                            Slog.w(TAG, "Failure writing pipe", e);
+                        }
+                    }
+                };
+                thr.start();
+                break;
+
+            default:
+                Slog.w(TAG, "Unknown pulled stats request: " + report);
+                break;
+        }
+        return fds[0];
+    }
+
+    /*
+     * @return the most recent timestamp in the report, as nanoseconds.
+     */
+    public long endTimeMs() {
+        return mTimePeriodEndMs;
+    }
+
+    public void dump(int report, PrintWriter pw, NotificationManagerService.DumpFilter filter) {
+        switch(report) {
+            case REPORT_REMOTE_VIEWS:
+                pw.print("  Packages with undecordated notifications (");
+                pw.print(mTimePeriodStartMs);
+                pw.print(" - ");
+                pw.print(mTimePeriodEndMs);
+                pw.println("):");
+                if (mUndecoratedPackageNames.size() == 0) {
+                    pw.println("    none");
+                } else {
+                    for (String pkg : mUndecoratedPackageNames) {
+                        if (!filter.filtered || pkg.equals(filter.pkgFilter)) {
+                            pw.println("    " + pkg);
+                        }
+                    }
+                }
+                break;
+
+            default:
+                pw.println("Unknown pulled stats request: " + report);
+                break;
+        }
+    }
+
+    @VisibleForTesting
+    void writeToProto(int report, ProtoOutputStream proto) {
+        switch(report) {
+            case REPORT_REMOTE_VIEWS:
+                for (String pkg: mUndecoratedPackageNames) {
+                    long token = proto.start(NotificationRemoteViewsProto.PACKAGE_REMOTE_VIEW_INFO);
+                    proto.write(PackageRemoteViewInfoProto.PACKAGE_NAME, pkg);
+                    proto.end(token);
+                }
+                break;
+
+            default:
+                Slog.w(TAG, "Unknown pulled stats request: " + report);
+                break;
+        }
+    }
+
+    public void addUndecoratedPackage(String packageName, long timestampMs) {
+        mUndecoratedPackageNames.add(packageName);
+        mTimePeriodEndMs = Math.max(mTimePeriodEndMs, timestampMs);
+    }
+}
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index 8125d0d..9e32d0e 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -374,9 +374,6 @@
             return;
         }
         NotificationRecord existing = pkgRecords.get(record.getKey());
-        if (existing != null && existing.isCanceled) {
-            return;
-        }
         pkgRecords.put(record.getKey(), record);
     }
 
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 6510923..696d2ea 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -627,15 +627,15 @@
         proto.write(ZenModeProto.ZEN_MODE, mZenMode);
         synchronized (mConfig) {
             if (mConfig.manualRule != null) {
-                mConfig.manualRule.writeToProto(proto, ZenModeProto.ENABLED_ACTIVE_CONDITIONS);
+                mConfig.manualRule.dumpDebug(proto, ZenModeProto.ENABLED_ACTIVE_CONDITIONS);
             }
             for (ZenRule rule : mConfig.automaticRules.values()) {
                 if (rule.enabled && rule.condition.state == Condition.STATE_TRUE
                         && !rule.snoozing) {
-                    rule.writeToProto(proto, ZenModeProto.ENABLED_ACTIVE_CONDITIONS);
+                    rule.dumpDebug(proto, ZenModeProto.ENABLED_ACTIVE_CONDITIONS);
                 }
             }
-            mConfig.toNotificationPolicy().writeToProto(proto, ZenModeProto.POLICY);
+            mConfig.toNotificationPolicy().dumpDebug(proto, ZenModeProto.POLICY);
             proto.write(ZenModeProto.SUPPRESSED_EFFECTS, mSuppressedEffects);
         }
     }
diff --git a/services/core/java/com/android/server/om/OverlayActorEnforcer.java b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
index e055116..ac3bf9a 100644
--- a/services/core/java/com/android/server/om/OverlayActorEnforcer.java
+++ b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
@@ -26,6 +26,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.text.TextUtils;
+import android.util.Pair;
 
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.CollectionUtils;
@@ -44,6 +45,38 @@
 
     private final VerifyCallback mVerifyCallback;
 
+    /**
+     * @return nullable actor result with {@link ActorState} failure status
+     */
+    static Pair<String, ActorState> getPackageNameForActor(String actorUriString,
+            Map<String, Map<String, String>> namedActors) {
+        if (namedActors.isEmpty()) {
+            return Pair.create(null, ActorState.NO_NAMED_ACTORS);
+        }
+
+        Uri actorUri = Uri.parse(actorUriString);
+
+        String actorScheme = actorUri.getScheme();
+        List<String> actorPathSegments = actorUri.getPathSegments();
+        if (!"overlay".equals(actorScheme) || CollectionUtils.size(actorPathSegments) != 1) {
+            return Pair.create(null, ActorState.INVALID_OVERLAYABLE_ACTOR_NAME);
+        }
+
+        String actorNamespace = actorUri.getAuthority();
+        Map<String, String> namespace = namedActors.get(actorNamespace);
+        if (namespace == null) {
+            return Pair.create(null, ActorState.MISSING_NAMESPACE);
+        }
+
+        String actorName = actorPathSegments.get(0);
+        String packageName = namespace.get(actorName);
+        if (TextUtils.isEmpty(packageName)) {
+            return Pair.create(null, ActorState.MISSING_ACTOR_NAME);
+        }
+
+        return Pair.create(packageName, ActorState.ALLOWED);
+    }
+
     public OverlayActorEnforcer(@NonNull VerifyCallback verifyCallback) {
         mVerifyCallback = verifyCallback;
     }
@@ -141,31 +174,14 @@
             }
         }
 
-        Map<String, ? extends Map<String, String>> namedActors = mVerifyCallback.getNamedActors();
-        if (namedActors.isEmpty()) {
-            return ActorState.NO_NAMED_ACTORS;
+        Map<String, Map<String, String>> namedActors = mVerifyCallback.getNamedActors();
+        Pair<String, ActorState> actorUriPair = getPackageNameForActor(actor, namedActors);
+        ActorState actorUriState = actorUriPair.second;
+        if (actorUriState != ActorState.ALLOWED) {
+            return actorUriState;
         }
 
-        Uri actorUri = Uri.parse(actor);
-
-        String actorScheme = actorUri.getScheme();
-        List<String> actorPathSegments = actorUri.getPathSegments();
-        if (!"overlay".equals(actorScheme) || CollectionUtils.size(actorPathSegments) != 1) {
-            return ActorState.INVALID_OVERLAYABLE_ACTOR_NAME;
-        }
-
-        String actorNamespace = actorUri.getAuthority();
-        Map<String, String> namespace = namedActors.get(actorNamespace);
-        if (namespace == null) {
-            return ActorState.MISSING_NAMESPACE;
-        }
-
-        String actorName = actorPathSegments.get(0);
-        String packageName = namespace.get(actorName);
-        if (TextUtils.isEmpty(packageName)) {
-            return ActorState.MISSING_ACTOR_NAME;
-        }
-
+        String packageName = actorUriPair.first;
         PackageInfo packageInfo = mVerifyCallback.getPackageInfo(packageName, userId);
         if (packageInfo == null) {
             return ActorState.MISSING_APP_INFO;
@@ -192,7 +208,7 @@
      * For easier logging/debugging, a set of all possible failure/success states when running
      * enforcement.
      */
-    private enum ActorState {
+    enum ActorState {
         ALLOWED,
         INVALID_ACTOR,
         MISSING_NAMESPACE,
@@ -244,7 +260,7 @@
          * value maps actor name to package name
          */
         @NonNull
-        Map<String, ? extends Map<String, String>> getNamedActors();
+        Map<String, Map<String, String>> getNamedActors();
 
         /**
          * @return true if the target package has declared an overlayable
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 63de61c..f1947ac 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -533,13 +533,13 @@
 
     private final IBinder mService = new IOverlayManager.Stub() {
         @Override
-        public Map<String, List<OverlayInfo>> getAllOverlays(int userId) throws RemoteException {
+        public Map<String, List<OverlayInfo>> getAllOverlays(final int userIdArg) {
             try {
-                traceBegin(TRACE_TAG_RRO, "OMS#getAllOverlays " + userId);
-                userId = handleIncomingUser(userId, "getAllOverlays");
+                traceBegin(TRACE_TAG_RRO, "OMS#getAllOverlays " + userIdArg);
+                final int realUserId = handleIncomingUser(userIdArg, "getAllOverlays");
 
                 synchronized (mLock) {
-                    return mImpl.getOverlaysForUser(userId);
+                    return mImpl.getOverlaysForUser(realUserId);
                 }
             } finally {
                 traceEnd(TRACE_TAG_RRO);
@@ -548,16 +548,17 @@
 
         @Override
         public List<OverlayInfo> getOverlayInfosForTarget(@Nullable final String targetPackageName,
-                int userId) throws RemoteException {
+                final int userIdArg) {
+            if (targetPackageName == null) {
+                return Collections.emptyList();
+            }
+
             try {
                 traceBegin(TRACE_TAG_RRO, "OMS#getOverlayInfosForTarget " + targetPackageName);
-                userId = handleIncomingUser(userId, "getOverlayInfosForTarget");
-                if (targetPackageName == null) {
-                    return Collections.emptyList();
-                }
+                final int realUserId = handleIncomingUser(userIdArg, "getOverlayInfosForTarget");
 
                 synchronized (mLock) {
-                    return mImpl.getOverlayInfosForTarget(targetPackageName, userId);
+                    return mImpl.getOverlayInfosForTarget(targetPackageName, realUserId);
                 }
             } finally {
                 traceEnd(TRACE_TAG_RRO);
@@ -566,16 +567,17 @@
 
         @Override
         public OverlayInfo getOverlayInfo(@Nullable final String packageName,
-                int userId) throws RemoteException {
+                final int userIdArg) {
+            if (packageName == null) {
+                return null;
+            }
+
             try {
                 traceBegin(TRACE_TAG_RRO, "OMS#getOverlayInfo " + packageName);
-                userId = handleIncomingUser(userId, "getOverlayInfo");
-                if (packageName == null) {
-                    return null;
-                }
+                final int realUserId = handleIncomingUser(userIdArg, "getOverlayInfo");
 
                 synchronized (mLock) {
-                    return mImpl.getOverlayInfo(packageName, userId);
+                    return mImpl.getOverlayInfo(packageName, realUserId);
                 }
             } finally {
                 traceEnd(TRACE_TAG_RRO);
@@ -584,19 +586,20 @@
 
         @Override
         public boolean setEnabled(@Nullable final String packageName, final boolean enable,
-                int userId) throws RemoteException {
+                int userIdArg) {
+            if (packageName == null) {
+                return false;
+            }
+
             try {
                 traceBegin(TRACE_TAG_RRO, "OMS#setEnabled " + packageName + " " + enable);
-                enforceActor(packageName, "setEnabled", userId);
-                userId = handleIncomingUser(userId, "setEnabled");
-                if (packageName == null) {
-                    return false;
-                }
+                final int realUserId = handleIncomingUser(userIdArg, "setEnabled");
+                enforceActor(packageName, "setEnabled", realUserId);
 
                 final long ident = Binder.clearCallingIdentity();
                 try {
                     synchronized (mLock) {
-                        return mImpl.setEnabled(packageName, enable, userId);
+                        return mImpl.setEnabled(packageName, enable, realUserId);
                     }
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -608,20 +611,21 @@
 
         @Override
         public boolean setEnabledExclusive(@Nullable final String packageName, final boolean enable,
-                int userId) throws RemoteException {
+                int userIdArg) {
+            if (packageName == null || !enable) {
+                return false;
+            }
+
             try {
                 traceBegin(TRACE_TAG_RRO, "OMS#setEnabledExclusive " + packageName + " " + enable);
-                enforceActor(packageName, "setEnabledExclusive", userId);
-                userId = handleIncomingUser(userId, "setEnabledExclusive");
-                if (packageName == null || !enable) {
-                    return false;
-                }
+                final int realUserId = handleIncomingUser(userIdArg, "setEnabledExclusive");
+                enforceActor(packageName, "setEnabledExclusive", realUserId);
 
                 final long ident = Binder.clearCallingIdentity();
                 try {
                     synchronized (mLock) {
                         return mImpl.setEnabledExclusive(packageName, false /* withinCategory */,
-                                userId);
+                                realUserId);
                     }
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -632,21 +636,23 @@
         }
 
         @Override
-        public boolean setEnabledExclusiveInCategory(@Nullable String packageName, int userId)
-                throws RemoteException {
+        public boolean setEnabledExclusiveInCategory(@Nullable String packageName,
+                final int userIdArg) {
+            if (packageName == null) {
+                return false;
+            }
+
             try {
                 traceBegin(TRACE_TAG_RRO, "OMS#setEnabledExclusiveInCategory " + packageName);
-                enforceActor(packageName, "setEnabledExclusiveInCategory", userId);
-                userId = handleIncomingUser(userId, "setEnabledExclusiveInCategory");
-                if (packageName == null) {
-                    return false;
-                }
+                final int realUserId = handleIncomingUser(userIdArg,
+                        "setEnabledExclusiveInCategory");
+                enforceActor(packageName, "setEnabledExclusiveInCategory", realUserId);
 
                 final long ident = Binder.clearCallingIdentity();
                 try {
                     synchronized (mLock) {
                         return mImpl.setEnabledExclusive(packageName, true /* withinCategory */,
-                                userId);
+                                realUserId);
                     }
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -658,20 +664,21 @@
 
         @Override
         public boolean setPriority(@Nullable final String packageName,
-                @Nullable final String parentPackageName, int userId) throws RemoteException {
+                @Nullable final String parentPackageName, final int userIdArg) {
+            if (packageName == null || parentPackageName == null) {
+                return false;
+            }
+
             try {
                 traceBegin(TRACE_TAG_RRO, "OMS#setPriority " + packageName + " "
                         + parentPackageName);
-                enforceActor(packageName, "setPriority", userId);
-                userId = handleIncomingUser(userId, "setPriority");
-                if (packageName == null || parentPackageName == null) {
-                    return false;
-                }
+                final int realUserId = handleIncomingUser(userIdArg, "setPriority");
+                enforceActor(packageName, "setPriority", realUserId);
 
                 final long ident = Binder.clearCallingIdentity();
                 try {
                     synchronized (mLock) {
-                        return mImpl.setPriority(packageName, parentPackageName, userId);
+                        return mImpl.setPriority(packageName, parentPackageName, realUserId);
                     }
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -682,20 +689,20 @@
         }
 
         @Override
-        public boolean setHighestPriority(@Nullable final String packageName, int userId)
-                throws RemoteException {
+        public boolean setHighestPriority(@Nullable final String packageName, final int userIdArg) {
+            if (packageName == null) {
+                return false;
+            }
+
             try {
                 traceBegin(TRACE_TAG_RRO, "OMS#setHighestPriority " + packageName);
-                enforceActor(packageName, "setHighestPriority", userId);
-                userId = handleIncomingUser(userId, "setHighestPriority");
-                if (packageName == null) {
-                    return false;
-                }
+                final int realUserId = handleIncomingUser(userIdArg, "setHighestPriority");
+                enforceActor(packageName, "setHighestPriority", realUserId);
 
                 final long ident = Binder.clearCallingIdentity();
                 try {
                     synchronized (mLock) {
-                        return mImpl.setHighestPriority(packageName, userId);
+                        return mImpl.setHighestPriority(packageName, realUserId);
                     }
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -706,20 +713,20 @@
         }
 
         @Override
-        public boolean setLowestPriority(@Nullable final String packageName, int userId)
-                throws RemoteException {
+        public boolean setLowestPriority(@Nullable final String packageName, final int userIdArg) {
+            if (packageName == null) {
+                return false;
+            }
+
             try {
                 traceBegin(TRACE_TAG_RRO, "OMS#setLowestPriority " + packageName);
-                enforceActor(packageName, "setLowestPriority", userId);
-                userId = handleIncomingUser(userId, "setLowestPriority");
-                if (packageName == null) {
-                    return false;
-                }
+                final int realUserId = handleIncomingUser(userIdArg, "setLowestPriority");
+                enforceActor(packageName, "setLowestPriority", realUserId);
 
                 final long ident = Binder.clearCallingIdentity();
                 try {
                     synchronized (mLock) {
-                        return mImpl.setLowestPriority(packageName, userId);
+                        return mImpl.setLowestPriority(packageName, realUserId);
                     }
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -730,7 +737,7 @@
         }
 
         @Override
-        public String[] getDefaultOverlayPackages() throws RemoteException {
+        public String[] getDefaultOverlayPackages() {
             try {
                 traceBegin(TRACE_TAG_RRO, "OMS#getDefaultOverlayPackages");
                 getContext().enforceCallingOrSelfPermission(
@@ -750,18 +757,17 @@
         }
 
         @Override
-        public void invalidateCachesForOverlay(@Nullable String packageName, int userId)
-                throws RemoteException {
+        public void invalidateCachesForOverlay(@Nullable String packageName, final int userIdArg) {
             if (packageName == null) {
                 return;
             }
 
-            enforceActor(packageName, "invalidateCachesForOverlay", userId);
-            userId = handleIncomingUser(userId, "invalidateCachesForOverlay");
+            final int realUserId = handleIncomingUser(userIdArg, "invalidateCachesForOverlay");
+            enforceActor(packageName, "invalidateCachesForOverlay", realUserId);
             final long ident = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
-                    mImpl.removeIdmapForOverlay(packageName, userId);
+                    mImpl.removeIdmapForOverlay(packageName, realUserId);
                 }
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -876,11 +882,16 @@
             getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, message);
         }
 
-        private void enforceActor(String packageName, String methodName, int userId)
+        private void enforceActor(String packageName, String methodName, int realUserId)
                 throws SecurityException {
-            OverlayInfo overlayInfo = mImpl.getOverlayInfo(packageName, userId);
+            OverlayInfo overlayInfo = mImpl.getOverlayInfo(packageName, realUserId);
+            if (overlayInfo == null) {
+                throw new IllegalArgumentException("Unable to retrieve overlay information for "
+                        + packageName);
+            }
+
             int callingUid = Binder.getCallingUid();
-            mActorEnforcer.enforceActor(overlayInfo, methodName, callingUid, userId);
+            mActorEnforcer.enforceActor(overlayInfo, methodName, callingUid, realUserId);
         }
     };
 
@@ -1062,8 +1073,6 @@
             mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
         }
 
-        // TODO(b/143096091): Remove PackageInfo cache so that PackageManager is always queried
-        //  to enforce visibility/other permission checks
         public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId,
                 final boolean useCache) {
             if (useCache) {
@@ -1086,18 +1095,12 @@
 
         @Override
         public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId) {
-            // TODO(b/143096091): Remove clearing calling ID
-            long callingIdentity = Binder.clearCallingIdentity();
-            try {
-                return getPackageInfo(packageName, userId, true);
-            } finally {
-                Binder.restoreCallingIdentity(callingIdentity);
-            }
+            return getPackageInfo(packageName, userId, true);
         }
 
         @NonNull
         @Override
-        public Map<String, ? extends Map<String, String>> getNamedActors() {
+        public Map<String, Map<String, String>> getNamedActors() {
             return SystemConfig.getInstance().getNamedActors();
         }
 
@@ -1125,57 +1128,45 @@
         public OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
                 @Nullable String targetOverlayableName, int userId)
                 throws IOException {
-            // TODO(b/143096091): Remove clearing calling ID
-            long callingIdentity = Binder.clearCallingIdentity();
+            PackageInfo packageInfo = getPackageInfo(packageName, userId);
+            if (packageInfo == null) {
+                throw new IOException("Unable to get target package");
+            }
+
+            String baseCodePath = packageInfo.applicationInfo.getBaseCodePath();
+
+            ApkAssets apkAssets = null;
             try {
-                PackageInfo packageInfo = getPackageInfo(packageName, userId);
-                if (packageInfo == null) {
-                    throw new IOException("Unable to get target package");
-                }
-
-                String baseCodePath = packageInfo.applicationInfo.getBaseCodePath();
-
-                ApkAssets apkAssets = null;
-                try {
-                    apkAssets = ApkAssets.loadFromPath(baseCodePath);
-                    return apkAssets.getOverlayableInfo(targetOverlayableName);
-                } finally {
-                    if (apkAssets != null) {
-                        try {
-                            apkAssets.close();
-                        } catch (Throwable ignored) {
-                        }
+                apkAssets = ApkAssets.loadFromPath(baseCodePath);
+                return apkAssets.getOverlayableInfo(targetOverlayableName);
+            } finally {
+                if (apkAssets != null) {
+                    try {
+                        apkAssets.close();
+                    } catch (Throwable ignored) {
                     }
                 }
-            } finally {
-                Binder.restoreCallingIdentity(callingIdentity);
             }
         }
 
         @Override
         public boolean doesTargetDefineOverlayable(String targetPackageName, int userId)
                 throws RemoteException, IOException {
-            // TODO(b/143096091): Remove clearing calling ID
-            long callingIdentity = Binder.clearCallingIdentity();
-            try {
-                PackageInfo packageInfo = mPackageManager.getPackageInfo(targetPackageName, 0,
-                        userId);
-                String baseCodePath = packageInfo.applicationInfo.getBaseCodePath();
+            PackageInfo packageInfo = mPackageManager.getPackageInfo(targetPackageName, 0,
+                    userId);
+            String baseCodePath = packageInfo.applicationInfo.getBaseCodePath();
 
-                ApkAssets apkAssets = null;
-                try {
-                    apkAssets = ApkAssets.loadFromPath(baseCodePath);
-                    return apkAssets.definesOverlayable();
-                } finally {
-                    if (apkAssets != null) {
-                        try {
-                            apkAssets.close();
-                        } catch (Throwable ignored) {
-                        }
+            ApkAssets apkAssets = null;
+            try {
+                apkAssets = ApkAssets.loadFromPath(baseCodePath);
+                return apkAssets.definesOverlayable();
+            } finally {
+                if (apkAssets != null) {
+                    try {
+                        apkAssets.close();
+                    } catch (Throwable ignored) {
                     }
                 }
-            } finally {
-                Binder.restoreCallingIdentity(callingIdentity);
             }
         }
 
@@ -1218,16 +1209,10 @@
         @Nullable
         @Override
         public String[] getPackagesForUid(int uid) {
-            // TODO(b/143096091): Remove clearing calling ID
-            long callingIdentity = Binder.clearCallingIdentity();
             try {
-                try {
-                    return mPackageManager.getPackagesForUid(uid);
-                } catch (RemoteException ignored) {
-                    return null;
-                }
-            } finally {
-                Binder.restoreCallingIdentity(callingIdentity);
+                return mPackageManager.getPackagesForUid(uid);
+            } catch (RemoteException ignored) {
+                return null;
             }
         }
 
diff --git a/services/core/java/com/android/server/om/OverlayReferenceMapper.java b/services/core/java/com/android/server/om/OverlayReferenceMapper.java
new file mode 100644
index 0000000..8bea119
--- /dev/null
+++ b/services/core/java/com/android/server/om/OverlayReferenceMapper.java
@@ -0,0 +1,375 @@
+/*
+ * 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.om;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.parsing.AndroidPackage;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Pair;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.CollectionUtils;
+import com.android.server.SystemConfig;
+import com.android.server.pm.PackageSetting;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Track visibility of a targets and overlays to actors.
+ *
+ * 4 cases to handle:
+ * <ol>
+ *     <li>Target adds/changes an overlayable to add a reference to an actor
+ *         <ul>
+ *             <li>Must expose target to actor</li>
+ *             <li>Must expose any overlays that pointed to that overlayable name to the actor</li>
+ *         </ul>
+ *     </li>
+ *     <li>Target removes/changes an overlayable to remove a reference to an actor
+ *         <ul>
+ *             <li>If this target has no other overlayables referencing the actor, hide the
+ *             target</li>
+ *             <li>For all overlays targeting this overlayable, if the overlay is only visible to
+ *             the actor through this overlayable, hide the overlay</li>
+ *         </ul>
+ *     </li>
+ *     <li>Overlay adds/changes an overlay tag to add a reference to an overlayable name
+ *         <ul>
+ *             <li>Expose this overlay to the actor defined by the target overlayable</li>
+ *         </ul>
+ *     </li>
+ *     <li>Overlay removes/changes an overlay tag to remove a reference to an overlayable name
+ *         <ul>
+ *             <li>If this overlay is only visible to an actor through this overlayable name's
+ *             target's actor</li>
+ *         </ul>
+ *     </li>
+ * </ol>
+ *
+ * In this class, the names "actor", "target", and "overlay" all refer to the ID representations.
+ * All other use cases are named appropriate. "actor" is actor name, "target" is target package
+ * name, and "overlay" is overlay package name.
+ */
+public class OverlayReferenceMapper {
+
+    private final Object mLock = new Object();
+
+    /**
+     * Keys are actors, values are maps which map target to a set of overlays targeting it.
+     * The presence of a target in the value map means the actor and targets are connected, even
+     * if the corresponding target's set is empty.
+     * See class comment for specific types.
+     */
+    @GuardedBy("mLock")
+    private final Map<String, Map<String, Set<String>>> mActorToTargetToOverlays = new HashMap<>();
+
+    /**
+     * Keys are actor package names, values are generic package names the actor should be able
+     * to see.
+     */
+    @GuardedBy("mLock")
+    private final Map<String, Set<String>> mActorPkgToPkgs = new HashMap<>();
+
+    @GuardedBy("mLock")
+    private boolean mDeferRebuild;
+
+    @NonNull
+    private final Provider mProvider;
+
+    /**
+     * @param deferRebuild whether or not to defer rebuild calls on add/remove until first get call;
+     *                     useful during boot when multiple packages are added in rapid succession
+     *                     and queries in-between are not expected
+     */
+    public OverlayReferenceMapper(boolean deferRebuild, @Nullable Provider provider) {
+        this.mDeferRebuild = deferRebuild;
+        this.mProvider = provider != null ? provider : new Provider() {
+            @Nullable
+            @Override
+            public String getActorPkg(String actor) {
+                Map<String, Map<String, String>> namedActors = SystemConfig.getInstance()
+                        .getNamedActors();
+
+                Pair<String, OverlayActorEnforcer.ActorState> actorPair =
+                        OverlayActorEnforcer.getPackageNameForActor(actor, namedActors);
+                return actorPair.first;
+            }
+
+            @NonNull
+            @Override
+            public Map<String, Set<String>> getTargetToOverlayables(@NonNull AndroidPackage pkg) {
+                String target = pkg.getOverlayTarget();
+                if (TextUtils.isEmpty(target)) {
+                    return Collections.emptyMap();
+                }
+
+                String overlayable = pkg.getOverlayTargetName();
+                Map<String, Set<String>> targetToOverlayables = new HashMap<>();
+                Set<String> overlayables = new HashSet<>();
+                overlayables.add(overlayable);
+                targetToOverlayables.put(target, overlayables);
+                return targetToOverlayables;
+            }
+        };
+    }
+
+    /**
+     * @return mapping of actor package to a set of packages it can view
+     */
+    @NonNull
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    public Map<String, Set<String>> getActorPkgToPkgs() {
+        return mActorPkgToPkgs;
+    }
+
+    public boolean isValidActor(@NonNull String targetName, @NonNull String actorPackageName) {
+        synchronized (mLock) {
+            assertMapBuilt();
+            Set<String> validSet = mActorPkgToPkgs.get(actorPackageName);
+            return validSet != null && validSet.contains(targetName);
+        }
+    }
+
+    /**
+     * Add a package to be considered for visibility. Currently supports adding as a target and/or
+     * an overlay. Adding an actor is not supported. Those are configured as part of
+     * {@link SystemConfig#getNamedActors()}.
+     *
+     * @param pkg the package to add
+     * @param otherPkgs map of other packages to consider, excluding {@param pkg}
+     */
+    public void addPkg(AndroidPackage pkg, Map<String, AndroidPackage> otherPkgs) {
+        synchronized (mLock) {
+            if (!pkg.getOverlayables().isEmpty()) {
+                addTarget(pkg, otherPkgs);
+            }
+
+            // TODO(b/135203078): Replace with isOverlay boolean flag check; fix test mocks
+            if (!mProvider.getTargetToOverlayables(pkg).isEmpty()) {
+                addOverlay(pkg, otherPkgs);
+            }
+
+            if (!mDeferRebuild) {
+                rebuild();
+            }
+        }
+    }
+
+    /**
+     * Removes a package to be considered for visibility. Currently supports removing as a target
+     * and/or an overlay. Removing an actor is not supported. Those are staticly configured as part
+     * of {@link SystemConfig#getNamedActors()}.
+     *
+     * @param pkgName name to remove, as was added through {@link #addPkg(AndroidPackage, Map)}
+     */
+    public void removePkg(String pkgName) {
+        synchronized (mLock) {
+            removeTarget(pkgName);
+            removeOverlay(pkgName);
+
+            if (!mDeferRebuild) {
+                rebuild();
+            }
+        }
+    }
+
+    private void removeTarget(String target) {
+        synchronized (mLock) {
+            Iterator<Map<String, Set<String>>> iterator =
+                    mActorToTargetToOverlays.values().iterator();
+            while (iterator.hasNext()) {
+                Map<String, Set<String>> next = iterator.next();
+                next.remove(target);
+                if (next.isEmpty()) {
+                    iterator.remove();
+                }
+            }
+        }
+    }
+
+    /**
+     * Associate an actor with an association of a new target to overlays for that target.
+     *
+     * If a target overlays itself, it will not be associated with itself, as only one half of the
+     * relationship needs to exist for visibility purposes.
+     */
+    private void addTarget(AndroidPackage targetPkg, Map<String, AndroidPackage> otherPkgs) {
+        synchronized (mLock) {
+            String target = targetPkg.getPackageName();
+            removeTarget(target);
+
+            Map<String, String> overlayablesToActors = targetPkg.getOverlayables();
+            for (String overlayable : overlayablesToActors.keySet()) {
+                String actor = overlayablesToActors.get(overlayable);
+                addTargetToMap(actor, target);
+
+                for (AndroidPackage overlayPkg : otherPkgs.values()) {
+                    Map<String, Set<String>> targetToOverlayables =
+                            mProvider.getTargetToOverlayables(overlayPkg);
+                    Set<String> overlayables = targetToOverlayables.get(target);
+                    if (CollectionUtils.isEmpty(overlayables)) {
+                        continue;
+                    }
+
+                    if (overlayables.contains(overlayable)) {
+                        addOverlayToMap(actor, target, overlayPkg.getPackageName());
+                    }
+                }
+            }
+        }
+    }
+
+    private void removeOverlay(String overlay) {
+        synchronized (mLock) {
+            for (Map<String, Set<String>> targetToOverlays : mActorToTargetToOverlays.values()) {
+                for (Set<String> overlays : targetToOverlays.values()) {
+                    overlays.remove(overlay);
+                }
+            }
+        }
+    }
+
+    /**
+     * Associate an actor with an association of targets to overlays for a new overlay.
+     *
+     * If an overlay targets itself, it will not be associated with itself, as only one half of the
+     * relationship needs to exist for visibility purposes.
+     */
+    private void addOverlay(AndroidPackage overlayPkg, Map<String, AndroidPackage> otherPkgs) {
+        synchronized (mLock) {
+            String overlay = overlayPkg.getPackageName();
+            removeOverlay(overlay);
+
+            Map<String, Set<String>> targetToOverlayables =
+                    mProvider.getTargetToOverlayables(overlayPkg);
+            for (Map.Entry<String, Set<String>> entry : targetToOverlayables.entrySet()) {
+                String target = entry.getKey();
+                Set<String> overlayables = entry.getValue();
+                AndroidPackage targetPkg = otherPkgs.get(target);
+                if (targetPkg == null) {
+                    continue;
+                }
+
+                String targetPkgName = targetPkg.getPackageName();
+                Map<String, String> overlayableToActor = targetPkg.getOverlayables();
+                for (String overlayable : overlayables) {
+                    String actor = overlayableToActor.get(overlayable);
+                    if (TextUtils.isEmpty(actor)) {
+                        continue;
+                    }
+                    addOverlayToMap(actor, targetPkgName, overlay);
+                }
+            }
+        }
+    }
+
+    public void rebuildIfDeferred() {
+        synchronized (mLock) {
+            if (mDeferRebuild) {
+                rebuild();
+                mDeferRebuild = false;
+            }
+        }
+    }
+
+    private void assertMapBuilt() {
+        if (mDeferRebuild) {
+            throw new IllegalStateException("The actor map must be built by calling "
+                    + "rebuildIfDeferred before it is queried");
+        }
+    }
+
+    private void rebuild() {
+        synchronized (mLock) {
+            mActorPkgToPkgs.clear();
+            for (String actor : mActorToTargetToOverlays.keySet()) {
+                String actorPkg = mProvider.getActorPkg(actor);
+                if (TextUtils.isEmpty(actorPkg)) {
+                    continue;
+                }
+
+                Map<String, Set<String>> targetToOverlays = mActorToTargetToOverlays.get(actor);
+                Set<String> pkgs = new HashSet<>();
+
+                for (String target : targetToOverlays.keySet()) {
+                    Set<String> overlays = targetToOverlays.get(target);
+                    pkgs.add(target);
+                    pkgs.addAll(overlays);
+                }
+
+                mActorPkgToPkgs.put(actorPkg, pkgs);
+            }
+        }
+    }
+
+    private void addTargetToMap(String actor, String target) {
+        Map<String, Set<String>> targetToOverlays = mActorToTargetToOverlays.get(actor);
+        if (targetToOverlays == null) {
+            targetToOverlays = new HashMap<>();
+            mActorToTargetToOverlays.put(actor, targetToOverlays);
+        }
+
+        Set<String> overlays = targetToOverlays.get(target);
+        if (overlays == null) {
+            overlays = new HashSet<>();
+            targetToOverlays.put(target, overlays);
+        }
+    }
+
+    private void addOverlayToMap(String actor, String target, String overlay) {
+        synchronized (mLock) {
+            Map<String, Set<String>> targetToOverlays = mActorToTargetToOverlays.get(actor);
+            if (targetToOverlays == null) {
+                targetToOverlays = new HashMap<>();
+                mActorToTargetToOverlays.put(actor, targetToOverlays);
+            }
+
+            Set<String> overlays = targetToOverlays.get(target);
+            if (overlays == null) {
+                overlays = new HashSet<>();
+                targetToOverlays.put(target, overlays);
+            }
+
+            overlays.add(overlay);
+        }
+    }
+
+    public interface Provider {
+
+        /**
+         * Given the actor string from an overlayable definition, return the actor's package name.
+         */
+        @Nullable
+        String getActorPkg(String actor);
+
+        /**
+         * Mock response of multiple overlay tags.
+         *
+         * TODO(b/119899133): Replace with actual implementation; fix OverlayReferenceMapperTests
+         */
+        @NonNull
+        Map<String, Set<String>> getTargetToOverlayables(@NonNull AndroidPackage pkg);
+    }
+}
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 1222d9a..2b4b409 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -36,6 +36,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.sysprop.ApexProperties;
+import android.util.Singleton;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
@@ -65,22 +66,31 @@
     static final int MATCH_ACTIVE_PACKAGE = 1 << 0;
     static final int MATCH_FACTORY_PACKAGE = 1 << 1;
 
+    private static final Singleton<ApexManager> sApexManagerSingleton =
+            new Singleton<ApexManager>() {
+                @Override
+                protected ApexManager create() {
+                    if (ApexProperties.updatable().orElse(false)) {
+                        try {
+                            return new ApexManagerImpl(IApexService.Stub.asInterface(
+                                    ServiceManager.getServiceOrThrow("apexservice")));
+                        } catch (ServiceManager.ServiceNotFoundException e) {
+                            throw new IllegalStateException(
+                                    "Required service apexservice not available");
+                        }
+                    } else {
+                        return new ApexManagerFlattenedApex();
+                    }
+                }
+            };
+
     /**
      * Returns an instance of either {@link ApexManagerImpl} or {@link ApexManagerFlattenedApex}
      * depending on whether this device supports APEX, i.e. {@link ApexProperties#updatable()}
      * evaluates to {@code true}.
      */
-    static ApexManager create(Context systemContext) {
-        if (ApexProperties.updatable().orElse(false)) {
-            try {
-                return new ApexManagerImpl(systemContext, IApexService.Stub.asInterface(
-                        ServiceManager.getServiceOrThrow("apexservice")));
-            } catch (ServiceManager.ServiceNotFoundException e) {
-                throw new IllegalStateException("Required service apexservice not available");
-            }
-        } else {
-            return new ApexManagerFlattenedApex();
-        }
+    static ApexManager getInstance() {
+        return sApexManagerSingleton.get();
     }
 
     /**
@@ -101,7 +111,7 @@
      */
     abstract List<ActiveApexInfo> getActiveApexInfos();
 
-    abstract void systemReady();
+    abstract void systemReady(Context context);
 
     /**
      * Retrieves information about an APEX package.
@@ -248,7 +258,6 @@
     @VisibleForTesting
     static class ApexManagerImpl extends ApexManager {
         private final IApexService mApexService;
-        private final Context mContext;
         private final Object mLock = new Object();
         /**
          * A map from {@code APEX packageName} to the {@Link PackageInfo} generated from the {@code
@@ -260,8 +269,7 @@
         @GuardedBy("mLock")
         private List<PackageInfo> mAllPackagesCache;
 
-        ApexManagerImpl(Context context, IApexService apexService) {
-            mContext = context;
+        ApexManagerImpl(IApexService apexService) {
             mApexService = apexService;
         }
 
@@ -302,14 +310,14 @@
         }
 
         @Override
-        void systemReady() {
-            mContext.registerReceiver(new BroadcastReceiver() {
+        void systemReady(Context context) {
+            context.registerReceiver(new BroadcastReceiver() {
                 @Override
                 public void onReceive(Context context, Intent intent) {
                     // Post populateAllPackagesCacheIfNeeded to a background thread, since it's
                     // expensive to run it in broadcast handler thread.
                     BackgroundThread.getHandler().post(() -> populateAllPackagesCacheIfNeeded());
-                    mContext.unregisterReceiver(this);
+                    context.unregisterReceiver(this);
                 }
             }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
         }
@@ -643,7 +651,7 @@
         }
 
         @Override
-        void systemReady() {
+        void systemReady(Context context) {
             // No-op
         }
 
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index ec11a97..c4bcf80 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -16,8 +16,6 @@
 
 package com.android.server.pm;
 
-import static android.content.pm.PackageParser.Component;
-import static android.content.pm.PackageParser.IntentInfo;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE;
 
@@ -26,8 +24,13 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
-import android.content.pm.ProviderInfo;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
+import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
+import android.content.pm.parsing.ComponentParseUtils.ParsedService;
 import android.net.Uri;
 import android.os.Process;
 import android.os.Trace;
@@ -44,9 +47,10 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.FgThread;
+import com.android.server.om.OverlayReferenceMapper;
 
 import java.io.PrintWriter;
-import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 import java.util.Set;
 
@@ -102,11 +106,16 @@
 
     private final FeatureConfig mFeatureConfig;
 
+    private final OverlayReferenceMapper mOverlayReferenceMapper;
+
     AppsFilter(FeatureConfig featureConfig, String[] forceQueryableWhitelist,
-            boolean systemAppsQueryable) {
+            boolean systemAppsQueryable,
+            @Nullable OverlayReferenceMapper.Provider overlayProvider) {
         mFeatureConfig = featureConfig;
         mForceQueryableByDevicePackageNames = forceQueryableWhitelist;
         mSystemAppsQueryable = systemAppsQueryable;
+        mOverlayReferenceMapper = new OverlayReferenceMapper(true /*deferRebuild*/,
+                overlayProvider);
     }
 
     public interface FeatureConfig {
@@ -117,7 +126,7 @@
         boolean isGloballyEnabled();
 
         /** @return true if the feature is enabled for the given package. */
-        boolean packageIsEnabled(PackageParser.Package pkg);
+        boolean packageIsEnabled(AndroidPackage pkg);
     }
 
     private static class FeatureConfigImpl implements FeatureConfig {
@@ -136,8 +145,11 @@
             DeviceConfig.addOnPropertiesChangedListener(
                     NAMESPACE_PACKAGE_MANAGER_SERVICE, FgThread.getExecutor(),
                     properties -> {
-                        synchronized (FeatureConfigImpl.this) {
-                            mFeatureEnabled = properties.getBoolean(FILTERING_ENABLED_NAME, false);
+                        if (properties.getKeyset().contains(FILTERING_ENABLED_NAME)) {
+                            synchronized (FeatureConfigImpl.this) {
+                                mFeatureEnabled = properties.getBoolean(FILTERING_ENABLED_NAME,
+                                        false);
+                            }
                         }
                     });
         }
@@ -153,11 +165,12 @@
         }
 
         @Override
-        public boolean packageIsEnabled(PackageParser.Package pkg) {
+        public boolean packageIsEnabled(AndroidPackage pkg) {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "packageIsEnabled");
             try {
+                // TODO(b/135203078): Do not use toAppInfo
                 return mInjector.getCompatibility().isChangeEnabled(
-                        PackageManager.FILTER_APPLICATION_QUERY, pkg.applicationInfo);
+                        PackageManager.FILTER_APPLICATION_QUERY, pkg.toAppInfoWithoutState());
             } finally {
                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
             }
@@ -182,16 +195,16 @@
             }
         }
         return new AppsFilter(featureConfig, forcedQueryablePackageNames,
-                forceSystemAppsQueryable);
+                forceSystemAppsQueryable, null);
     }
 
     /** Returns true if the querying package may query for the potential target package */
-    private static boolean canQueryViaIntent(PackageParser.Package querying,
-            PackageParser.Package potentialTarget) {
-        if (querying.mQueriesIntents == null) {
+    private static boolean canQueryViaIntent(AndroidPackage querying,
+            AndroidPackage potentialTarget) {
+        if (querying.getQueriesIntents() == null) {
             return false;
         }
-        for (Intent intent : querying.mQueriesIntents) {
+        for (Intent intent : querying.getQueriesIntents()) {
             if (matches(intent, potentialTarget)) {
                 return true;
             }
@@ -199,41 +212,40 @@
         return false;
     }
 
-    private static boolean matches(Intent intent, PackageParser.Package potentialTarget) {
-        for (int p = potentialTarget.providers.size() - 1; p >= 0; p--) {
-            PackageParser.Provider provider = potentialTarget.providers.get(p);
-            if (!provider.info.exported) {
+    private static boolean matches(Intent intent, AndroidPackage potentialTarget) {
+        for (int p = ArrayUtils.size(potentialTarget.getProviders()) - 1; p >= 0; p--) {
+            ParsedProvider provider = potentialTarget.getProviders().get(p);
+            if (!provider.isExported()) {
                 continue;
             }
-            final ProviderInfo providerInfo = provider.info;
             final Uri data = intent.getData();
             if ("content".equalsIgnoreCase(intent.getScheme())
                     && data != null
-                    && Objects.equals(providerInfo.authority, data.getAuthority())) {
+                    && Objects.equals(provider.getAuthority(), data.getAuthority())) {
                 return true;
             }
         }
-        for (int s = potentialTarget.services.size() - 1; s >= 0; s--) {
-            PackageParser.Service service = potentialTarget.services.get(s);
-            if (!service.info.exported) {
+        for (int s = ArrayUtils.size(potentialTarget.getServices()) - 1; s >= 0; s--) {
+            ParsedService service = potentialTarget.getServices().get(s);
+            if (!service.exported) {
                 continue;
             }
             if (matchesAnyFilter(intent, service)) {
                 return true;
             }
         }
-        for (int a = potentialTarget.activities.size() - 1; a >= 0; a--) {
-            PackageParser.Activity activity = potentialTarget.activities.get(a);
-            if (!activity.info.exported) {
+        for (int a = ArrayUtils.size(potentialTarget.getActivities()) - 1; a >= 0; a--) {
+            ParsedActivity activity = potentialTarget.getActivities().get(a);
+            if (!activity.exported) {
                 continue;
             }
             if (matchesAnyFilter(intent, activity)) {
                 return true;
             }
         }
-        for (int r = potentialTarget.receivers.size() - 1; r >= 0; r--) {
-            PackageParser.Activity receiver = potentialTarget.receivers.get(r);
-            if (!receiver.info.exported) {
+        for (int r = ArrayUtils.size(potentialTarget.getReceivers()) - 1; r >= 0; r--) {
+            ParsedActivity receiver = potentialTarget.getReceivers().get(r);
+            if (!receiver.exported) {
                 continue;
             }
             if (matchesAnyFilter(intent, receiver)) {
@@ -244,9 +256,9 @@
     }
 
     private static boolean matchesAnyFilter(
-            Intent intent, Component<? extends IntentInfo> component) {
-        ArrayList<? extends IntentInfo> intents = component.intents;
-        for (int i = intents.size() - 1; i >= 0; i--) {
+            Intent intent, ParsedComponent<? extends ParsedIntentInfo> component) {
+        List<? extends ParsedIntentInfo> intents = component.intents;
+        for (int i = ArrayUtils.size(intents) - 1; i >= 0; i--) {
             IntentFilter intentFilter = intents.get(i);
             if (intentFilter.match(intent.getAction(), intent.getType(), intent.getScheme(),
                     intent.getData(), intent.getCategories(), "AppsFilter") > 0) {
@@ -272,6 +284,7 @@
 
     public void onSystemReady() {
         mFeatureConfig.onSystemReady();
+        mOverlayReferenceMapper.rebuildIfDeferred();
     }
 
     /**
@@ -284,7 +297,7 @@
             ArrayMap<String, PackageSetting> existingSettings) {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage");
         try {
-            final PackageParser.Package newPkg = newPkgSetting.pkg;
+            final AndroidPackage newPkg = newPkgSetting.pkg;
             if (newPkg == null) {
                 // nothing to add
                 return;
@@ -293,10 +306,10 @@
             final boolean newIsForceQueryable =
                     mForceQueryable.contains(newPkgSetting.appId)
                             /* shared user that is already force queryable */
-                            || newPkg.mForceQueryable
+                            || newPkg.isForceQueryable()
                             || (newPkgSetting.isSystem() && (mSystemAppsQueryable
                             || ArrayUtils.contains(mForceQueryableByDevicePackageNames,
-                            newPkg.packageName)));
+                            newPkg.getPackageName())));
             if (newIsForceQueryable) {
                 mForceQueryable.add(newPkgSetting.appId);
             }
@@ -306,14 +319,14 @@
                 if (existingSetting.appId == newPkgSetting.appId || existingSetting.pkg == null) {
                     continue;
                 }
-                final PackageParser.Package existingPkg = existingSetting.pkg;
+                final AndroidPackage existingPkg = existingSetting.pkg;
                 // let's evaluate the ability of already added packages to see this new package
                 if (!newIsForceQueryable) {
                     if (canQueryViaIntent(existingPkg, newPkg)) {
                         mQueriesViaIntent.add(existingSetting.appId, newPkgSetting.appId);
                     }
-                    if (existingPkg.mQueriesPackages != null
-                            && existingPkg.mQueriesPackages.contains(newPkg.packageName)) {
+                    if (existingPkg.getQueriesPackages() != null
+                            && existingPkg.getQueriesPackages().contains(newPkg.getPackageName())) {
                         mQueriesViaPackage.add(existingSetting.appId, newPkgSetting.appId);
                     }
                 }
@@ -322,12 +335,22 @@
                     if (canQueryViaIntent(newPkg, existingPkg)) {
                         mQueriesViaIntent.add(newPkgSetting.appId, existingSetting.appId);
                     }
-                    if (newPkg.mQueriesPackages != null
-                            && newPkg.mQueriesPackages.contains(existingPkg.packageName)) {
+                    if (newPkg.getQueriesPackages() != null
+                            && newPkg.getQueriesPackages().contains(existingPkg.getPackageName())) {
                         mQueriesViaPackage.add(newPkgSetting.appId, existingSetting.appId);
                     }
                 }
             }
+
+            int existingSize = existingSettings.size();
+            ArrayMap<String, AndroidPackage> existingPkgs = new ArrayMap<>(existingSize);
+            for (int index = 0; index < existingSize; index++) {
+                PackageSetting pkgSetting = existingSettings.valueAt(index);
+                if (pkgSetting.pkg != null) {
+                    existingPkgs.put(pkgSetting.name, pkgSetting.pkg);
+                }
+            }
+            mOverlayReferenceMapper.addPkg(newPkgSetting.pkg, existingPkgs);
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
@@ -371,6 +394,8 @@
                 addPackage(setting.sharedUser.packages.valueAt(i), existingSettings);
             }
         }
+
+        mOverlayReferenceMapper.removePkg(setting.name);
     }
 
     /**
@@ -387,8 +412,7 @@
             PackageSetting targetPkgSetting, int userId) {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplication");
         try {
-            if (!shouldFilterApplicationInternal(callingUid, callingSetting,
-                    targetPkgSetting,
+            if (!shouldFilterApplicationInternal(callingUid, callingSetting, targetPkgSetting,
                     userId)) {
                 return false;
             }
@@ -402,8 +426,8 @@
         }
     }
 
-    private boolean shouldFilterApplicationInternal(int callingUid,
-            SettingBase callingSetting, PackageSetting targetPkgSetting, int userId) {
+    private boolean shouldFilterApplicationInternal(int callingUid, SettingBase callingSetting,
+            PackageSetting targetPkgSetting, int userId) {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplicationInternal");
         try {
             final boolean featureEnabled = mFeatureConfig.isGloballyEnabled();
@@ -453,14 +477,14 @@
 
             // This package isn't technically installed and won't be written to settings, so we can
             // treat it as filtered until it's available again.
-            final PackageParser.Package targetPkg = targetPkgSetting.pkg;
+            final AndroidPackage targetPkg = targetPkgSetting.pkg;
             if (targetPkg == null) {
                 if (DEBUG_LOGGING) {
                     Slog.wtf(TAG, "shouldFilterApplication: " + "targetPkg is null");
                 }
                 return true;
             }
-            final String targetName = targetPkg.packageName;
+            final String targetName = targetPkg.getPackageName();
             final int callingAppId;
             if (callingPkgSetting != null) {
                 callingAppId = callingPkgSetting.appId;
@@ -520,6 +544,29 @@
                     }
                 }
             }
+
+            if (callingSharedPkgSettings != null) {
+                int size = callingSharedPkgSettings.size();
+                for (int index = 0; index < size; index++) {
+                    PackageSetting pkgSetting = callingSharedPkgSettings.valueAt(index);
+                    if (mOverlayReferenceMapper.isValidActor(targetName, pkgSetting.name)) {
+                        if (DEBUG_LOGGING) {
+                            log(callingPkgSetting, targetPkgSetting,
+                                    "matches shared user of package that acts on target of "
+                                            + "overlay");
+                        }
+                        return false;
+                    }
+                }
+            } else {
+                if (mOverlayReferenceMapper.isValidActor(targetName, callingPkgSetting.name)) {
+                    if (DEBUG_LOGGING) {
+                        log(callingPkgSetting, targetPkgSetting, "acts on target of overlay");
+                    }
+                    return false;
+                }
+            }
+
             return true;
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -529,9 +576,10 @@
     private static boolean callingPkgInstruments(PackageSetting callingPkgSetting,
             PackageSetting targetPkgSetting,
             String targetName) {
-        final ArrayList<PackageParser.Instrumentation> inst = callingPkgSetting.pkg.instrumentation;
-        for (int i = inst.size() - 1; i >= 0; i--) {
-            if (inst.get(i).info.targetPackage == targetName) {
+        final List<ComponentParseUtils.ParsedInstrumentation> inst =
+                callingPkgSetting.pkg.getInstrumentations();
+        for (int i = ArrayUtils.size(inst) - 1; i >= 0; i--) {
+            if (Objects.equals(inst.get(i).getTargetPackage(), targetName)) {
                 if (DEBUG_LOGGING) {
                     log(callingPkgSetting, targetPkgSetting, "instrumentation");
                 }
diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java
index b1eb7e7..f2a2e65 100644
--- a/services/core/java/com/android/server/pm/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/ComponentResolver.java
@@ -21,7 +21,6 @@
 
 import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
 import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE;
-import static com.android.server.pm.PackageManagerService.fixProcessName;
 
 import android.annotation.Nullable;
 import android.content.ComponentName;
@@ -33,13 +32,18 @@
 import android.content.pm.InstantAppResolveInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.ActivityIntentInfo;
-import android.content.pm.PackageParser.ServiceIntentInfo;
 import android.content.pm.PackageUserState;
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProviderIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedService;
+import android.content.pm.parsing.ComponentParseUtils.ParsedServiceIntentInfo;
+import android.content.pm.parsing.PackageInfoUtils;
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -55,11 +59,14 @@
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
+import java.util.function.Function;
 
 /** Resolves all Android component types [activities, services, providers and receivers]. */
 public class ComponentResolver {
@@ -160,7 +167,7 @@
 
     /** All available receivers, for your resolving pleasure. */
     @GuardedBy("mLock")
-    private final ActivityIntentResolver mReceivers = new ActivityIntentResolver();
+    private final ActivityIntentResolver mReceivers = new ReceiverIntentResolver();
 
     /** All available services, for your resolving pleasure. */
     @GuardedBy("mLock")
@@ -168,7 +175,7 @@
 
     /** Mapping from provider authority [first directory in content URI codePath) to provider. */
     @GuardedBy("mLock")
-    private final ArrayMap<String, PackageParser.Provider> mProvidersByAuthority = new ArrayMap<>();
+    private final ArrayMap<String, ParsedProvider> mProvidersByAuthority = new ArrayMap<>();
 
     /** Whether or not processing protected filters should be deferred. */
     private boolean mDeferProtectedFilters = true;
@@ -183,7 +190,7 @@
      * /system partition in order to know which component is the setup wizard. This can
      * only ever be non-empty if {@link #mDeferProtectedFilters} is {@code true}.
      */
-    private List<PackageParser.ActivityIntentInfo> mProtectedFilters;
+    private List<ParsedActivityIntentInfo> mProtectedFilters;
 
     ComponentResolver(UserManagerService userManager,
             PackageManagerInternal packageManagerInternal,
@@ -194,28 +201,28 @@
     }
 
     /** Returns the given activity */
-    PackageParser.Activity getActivity(ComponentName component) {
+    ParsedActivity getActivity(ComponentName component) {
         synchronized (mLock) {
             return mActivities.mActivities.get(component);
         }
     }
 
     /** Returns the given provider */
-    PackageParser.Provider getProvider(ComponentName component) {
+    ParsedProvider getProvider(ComponentName component) {
         synchronized (mLock) {
             return mProviders.mProviders.get(component);
         }
     }
 
     /** Returns the given receiver */
-    PackageParser.Activity getReceiver(ComponentName component) {
+    ParsedActivity getReceiver(ComponentName component) {
         synchronized (mLock) {
             return mReceivers.mActivities.get(component);
         }
     }
 
     /** Returns the given service */
-    PackageParser.Service getService(ComponentName component) {
+    ParsedService getService(ComponentName component) {
         synchronized (mLock) {
             return mServices.mServices.get(component);
         }
@@ -230,7 +237,7 @@
 
     @Nullable
     List<ResolveInfo> queryActivities(Intent intent, String resolvedType, int flags,
-            List<PackageParser.Activity> activities, int userId) {
+            List<ParsedActivity> activities, int userId) {
         synchronized (mLock) {
             return mActivities.queryIntentForPackage(
                     intent, resolvedType, flags, activities, userId);
@@ -246,7 +253,7 @@
 
     @Nullable
     List<ResolveInfo> queryProviders(Intent intent, String resolvedType, int flags,
-            List<PackageParser.Provider> providers, int userId) {
+            List<ParsedProvider> providers, int userId) {
         synchronized (mLock) {
             return mProviders.queryIntentForPackage(intent, resolvedType, flags, providers, userId);
         }
@@ -261,25 +268,34 @@
         List<ProviderInfo> providerList = null;
         synchronized (mLock) {
             for (int i = mProviders.mProviders.size() - 1; i >= 0; --i) {
-                final PackageParser.Provider p = mProviders.mProviders.valueAt(i);
-                final PackageSetting ps = (PackageSetting) p.owner.mExtras;
+                final ParsedProvider p = mProviders.mProviders.valueAt(i);
+                if (p.getAuthority() == null) {
+                    continue;
+                }
+
+                final PackageSetting ps =
+                        (PackageSetting) sPackageManagerInternal.getPackageSetting(
+                                p.getPackageName());
                 if (ps == null) {
                     continue;
                 }
-                if (p.info.authority == null) {
+
+                AndroidPackage pkg = sPackageManagerInternal.getPackage(p.getPackageName());
+                if (pkg == null) {
                     continue;
                 }
-                if (processName != null && (!p.info.processName.equals(processName)
-                        || !UserHandle.isSameApp(p.info.applicationInfo.uid, uid))) {
+
+                if (processName != null && (!p.getProcessName().equals(processName)
+                        || !UserHandle.isSameApp(pkg.getUid(), uid))) {
                     continue;
                 }
                 // See PM.queryContentProviders()'s javadoc for why we have the metaData parameter.
                 if (metaDataKey != null
-                        && (p.metaData == null || !p.metaData.containsKey(metaDataKey))) {
+                        && (p.getMetaData() == null || !p.getMetaData().containsKey(metaDataKey))) {
                     continue;
                 }
-                final ProviderInfo info = PackageParser.generateProviderInfo(
-                        p, flags, ps.readUserState(userId), userId);
+                final ProviderInfo info = PackageInfoUtils.generateProviderInfo(
+                        pkg, p, flags, ps.readUserState(userId), userId);
                 if (info == null) {
                     continue;
                 }
@@ -295,15 +311,21 @@
     @Nullable
     ProviderInfo queryProvider(String authority, int flags, int userId) {
         synchronized (mLock) {
-            final PackageParser.Provider p = mProvidersByAuthority.get(authority);
+            final ParsedProvider p = mProvidersByAuthority.get(authority);
             if (p == null) {
                 return null;
             }
-            final PackageSetting ps = (PackageSetting) p.owner.mExtras;
+            final PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
+                    p.getPackageName());
             if (ps == null) {
                 return null;
             }
-            return PackageParser.generateProviderInfo(p, flags, ps.readUserState(userId), userId);
+            final AndroidPackage pkg = sPackageManagerInternal.getPackage(p.getPackageName());
+            if (pkg == null) {
+                return null;
+            }
+            return PackageInfoUtils.generateProviderInfo(pkg, p, flags,
+                    ps.readUserState(userId), userId);
         }
     }
 
@@ -311,20 +333,29 @@
             int userId) {
         synchronized (mLock) {
             for (int i = mProvidersByAuthority.size() - 1; i >= 0; --i) {
-                final PackageParser.Provider p = mProvidersByAuthority.valueAt(i);
-                final PackageSetting ps = (PackageSetting) p.owner.mExtras;
+                final ParsedProvider p = mProvidersByAuthority.valueAt(i);
+                if (!p.isSyncable()) {
+                    continue;
+                }
+
+                final PackageSetting ps =
+                        (PackageSetting) sPackageManagerInternal.getPackageSetting(
+                                p.getPackageName());
                 if (ps == null) {
                     continue;
                 }
-                if (!p.syncable) {
+
+                final AndroidPackage pkg = sPackageManagerInternal.getPackage(p.getPackageName());
+                if (pkg == null) {
                     continue;
                 }
-                if (safeMode
-                        && (p.info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+
+                if (safeMode && (pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) == 0) {
                     continue;
                 }
                 final ProviderInfo info =
-                        PackageParser.generateProviderInfo(p, 0, ps.readUserState(userId), userId);
+                        PackageInfoUtils.generateProviderInfo(pkg, p, 0,
+                                ps.readUserState(userId), userId);
                 if (info == null) {
                     continue;
                 }
@@ -343,7 +374,7 @@
 
     @Nullable
     List<ResolveInfo> queryReceivers(Intent intent, String resolvedType, int flags,
-            List<PackageParser.Activity> receivers, int userId) {
+            List<ParsedActivity> receivers, int userId) {
         synchronized (mLock) {
             return mReceivers.queryIntentForPackage(intent, resolvedType, flags, receivers, userId);
         }
@@ -358,7 +389,7 @@
 
     @Nullable
     List<ResolveInfo> queryServices(Intent intent, String resolvedType, int flags,
-            List<PackageParser.Service> services, int userId) {
+            List<ParsedService> services, int userId) {
         synchronized (mLock) {
             return mServices.queryIntentForPackage(intent, resolvedType, flags, services, userId);
         }
@@ -372,15 +403,15 @@
     }
 
     /** Asserts none of the providers defined in the given package haven't already been defined. */
-    void assertProvidersNotDefined(PackageParser.Package pkg) throws PackageManagerException {
+    void assertProvidersNotDefined(AndroidPackage pkg) throws PackageManagerException {
         synchronized (mLock) {
             assertProvidersNotDefinedLocked(pkg);
         }
     }
 
     /** Add all components defined in the given package to the internal structures. */
-    void addAllComponents(PackageParser.Package pkg, boolean chatty) {
-        final ArrayList<PackageParser.ActivityIntentInfo> newIntents = new ArrayList<>();
+    void addAllComponents(AndroidPackage pkg, boolean chatty) {
+        final ArrayList<ParsedActivityIntentInfo> newIntents = new ArrayList<>();
         synchronized (mLock) {
             addActivitiesLocked(pkg, newIntents, chatty);
             addReceiversLocked(pkg, chatty);
@@ -393,17 +424,19 @@
                         PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM));
 
         for (int i = newIntents.size() - 1; i >= 0; --i) {
-            final PackageParser.ActivityIntentInfo intentInfo = newIntents.get(i);
-            final PackageParser.Package disabledPkg = sPackageManagerInternal
-                    .getDisabledSystemPackage(intentInfo.activity.info.packageName);
-            final List<PackageParser.Activity> systemActivities =
-                    disabledPkg != null ? disabledPkg.activities : null;
+            final ParsedActivityIntentInfo intentInfo = newIntents.get(i);
+            final PackageSetting disabledPkgSetting = (PackageSetting) sPackageManagerInternal
+                    .getDisabledSystemPackage(intentInfo.getPackageName());
+            final AndroidPackage disabledPkg =
+                    disabledPkgSetting == null ? null : disabledPkgSetting.pkg;
+            final List<ParsedActivity> systemActivities =
+                    disabledPkg != null ? disabledPkg.getActivities() : null;
             adjustPriority(systemActivities, intentInfo, setupWizardPackage);
         }
     }
 
     /** Removes all components defined in the given package from the internal structures. */
-    void removeAllComponents(PackageParser.Package pkg, boolean chatty) {
+    void removeAllComponents(AndroidPackage pkg, boolean chatty) {
         synchronized (mLock) {
             removeAllComponentsLocked(pkg, chatty);
         }
@@ -422,7 +455,7 @@
         if (mProtectedFilters == null || mProtectedFilters.size() == 0) {
             return;
         }
-        final List<ActivityIntentInfo> protectedFilters = mProtectedFilters;
+        final List<ParsedActivityIntentInfo> protectedFilters = mProtectedFilters;
         mProtectedFilters = null;
 
         // expect single setupwizard package
@@ -435,13 +468,13 @@
                     + " All protected intents capped to priority 0");
         }
         for (int i = protectedFilters.size() - 1; i >= 0; --i) {
-            final ActivityIntentInfo filter = protectedFilters.get(i);
-            if (filter.activity.info.packageName.equals(setupWizardPackage)) {
+            final ParsedActivityIntentInfo filter = protectedFilters.get(i);
+            if (filter.getPackageName().equals(setupWizardPackage)) {
                 if (DEBUG_FILTERS) {
                     Slog.i(TAG, "Found setup wizard;"
                             + " allow priority " + filter.getPriority() + ";"
-                            + " package: " + filter.activity.info.packageName
-                            + " activity: " + filter.activity.className
+                            + " package: " + filter.getPackageName()
+                            + " activity: " + filter.getClassName()
                             + " priority: " + filter.getPriority());
                 }
                 // skip setup wizard; allow it to keep the high priority filter
@@ -449,8 +482,8 @@
             }
             if (DEBUG_FILTERS) {
                 Slog.i(TAG, "Protected action; cap priority to 0;"
-                        + " package: " + filter.activity.info.packageName
-                        + " activity: " + filter.activity.className
+                        + " package: " + filter.getPackageName()
+                        + " activity: " + filter.getClassName()
                         + " origPrio: " + filter.getPriority());
             }
             filter.setPriority(0);
@@ -491,8 +524,8 @@
 
     void dumpContentProviders(PrintWriter pw, DumpState dumpState, String packageName) {
         boolean printedSomething = false;
-        for (PackageParser.Provider p : mProviders.mProviders.values()) {
-            if (packageName != null && !packageName.equals(p.info.packageName)) {
+        for (ParsedProvider p : mProviders.mProviders.values()) {
+            if (packageName != null && !packageName.equals(p.getPackageName())) {
                 continue;
             }
             if (!printedSomething) {
@@ -502,14 +535,17 @@
                 pw.println("Registered ContentProviders:");
                 printedSomething = true;
             }
-            pw.print("  "); p.printComponentShortName(pw); pw.println(":");
-            pw.print("    "); pw.println(p.toString());
+            pw.print("  ");
+            ComponentName.printShortString(pw, p.getPackageName(), p.className);
+            pw.println(":");
+            pw.print("    ");
+            pw.println(p.toString());
         }
         printedSomething = false;
-        for (Map.Entry<String, PackageParser.Provider> entry :
+        for (Map.Entry<String, ParsedProvider> entry :
                 mProvidersByAuthority.entrySet()) {
-            PackageParser.Provider p = entry.getValue();
-            if (packageName != null && !packageName.equals(p.info.packageName)) {
+            ParsedProvider p = entry.getValue();
+            if (packageName != null && !packageName.equals(p.getPackageName())) {
                 continue;
             }
             if (!printedSomething) {
@@ -521,25 +557,43 @@
             }
             pw.print("  ["); pw.print(entry.getKey()); pw.println("]:");
             pw.print("    "); pw.println(p.toString());
-            if (p.info != null && p.info.applicationInfo != null) {
-                final String appInfo = p.info.applicationInfo.toString();
-                pw.print("      applicationInfo="); pw.println(appInfo);
+
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(p.getPackageName());
+
+            if (pkg != null) {
+                // TODO(b/135203078): Print AppInfo?
+                pw.print("      applicationInfo="); pw.println(pkg.toAppInfoWithoutState());
             }
         }
     }
 
-    void dumpServicePermissions(PrintWriter pw, DumpState dumpState, String packageName) {
+    void dumpServicePermissions(PrintWriter pw, DumpState dumpState) {
         if (dumpState.onTitlePrinted()) pw.println();
         pw.println("Service permissions:");
 
-        final Iterator<ServiceIntentInfo> filterIterator = mServices.filterIterator();
+        final Iterator<ParsedServiceIntentInfo> filterIterator = mServices.filterIterator();
         while (filterIterator.hasNext()) {
-            final ServiceIntentInfo info = filterIterator.next();
-            final ServiceInfo serviceInfo = info.service.info;
-            final String permission = serviceInfo.permission;
+            final ParsedServiceIntentInfo info = filterIterator.next();
+
+            ParsedService service = null;
+
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(info.getPackageName());
+            if (pkg != null && pkg.getServices() != null) {
+                for (ParsedService parsedService : pkg.getServices()) {
+                    if (Objects.equals(parsedService.className, info.getClassName())) {
+                        service = parsedService;
+                    }
+                }
+            }
+
+            if (service == null) {
+                continue;
+            }
+
+            final String permission = service.getPermission();
             if (permission != null) {
                 pw.print("    ");
-                pw.print(serviceInfo.getComponentName().flattenToShortString());
+                pw.print(service.getComponentName().flattenToShortString());
                 pw.print(": ");
                 pw.println(permission);
             }
@@ -547,14 +601,12 @@
     }
 
     @GuardedBy("mLock")
-    private void addActivitiesLocked(PackageParser.Package pkg,
-            List<PackageParser.ActivityIntentInfo> newIntents, boolean chatty) {
-        final int activitiesSize = pkg.activities.size();
+    private void addActivitiesLocked(AndroidPackage pkg,
+            List<ParsedActivityIntentInfo> newIntents, boolean chatty) {
+        final int activitiesSize = ArrayUtils.size(pkg.getActivities());
         StringBuilder r = null;
         for (int i = 0; i < activitiesSize; i++) {
-            PackageParser.Activity a = pkg.activities.get(i);
-            a.info.processName =
-                    fixProcessName(pkg.applicationInfo.processName, a.info.processName);
+            ParsedActivity a = pkg.getActivities().get(i);
             mActivities.addActivity(a, "activity", newIntents);
             if (DEBUG_PACKAGE_SCANNING && chatty) {
                 if (r == null) {
@@ -562,7 +614,7 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(a.info.name);
+                r.append(a.getName());
             }
         }
         if (DEBUG_PACKAGE_SCANNING && chatty) {
@@ -571,20 +623,17 @@
     }
 
     @GuardedBy("mLock")
-    private void addProvidersLocked(PackageParser.Package pkg, boolean chatty) {
-        final int providersSize = pkg.providers.size();
+    private void addProvidersLocked(AndroidPackage pkg, boolean chatty) {
+        final int providersSize = ArrayUtils.size(pkg.getProviders());
         StringBuilder r = null;
         for (int i = 0; i < providersSize; i++) {
-            PackageParser.Provider p = pkg.providers.get(i);
-            p.info.processName = fixProcessName(pkg.applicationInfo.processName,
-                    p.info.processName);
+            EffectiveProvider p = new EffectiveProvider(pkg.getProviders().get(i));
             mProviders.addProvider(p);
-            p.syncable = p.info.isSyncable;
-            if (p.info.authority != null) {
-                String[] names = p.info.authority.split(";");
-                p.info.authority = null;
+            if (p.getAuthority() != null) {
+                String[] names = p.getAuthority().split(";");
+                p.setEffectiveAuthority(null);
                 for (int j = 0; j < names.length; j++) {
-                    if (j == 1 && p.syncable) {
+                    if (j == 1 && p.isSyncable()) {
                         // We only want the first authority for a provider to possibly be
                         // syncable, so if we already added this provider using a different
                         // authority clear the syncable flag. We copy the provider before
@@ -592,23 +641,23 @@
                         // to a provider that we don't want to change.
                         // Only do this for the second authority since the resulting provider
                         // object can be the same for all future authorities for this provider.
-                        p = new PackageParser.Provider(p);
-                        p.syncable = false;
+                        p = new EffectiveProvider(p);
+                        p.setEffectiveSyncable(false);
                     }
                     if (!mProvidersByAuthority.containsKey(names[j])) {
                         mProvidersByAuthority.put(names[j], p);
-                        if (p.info.authority == null) {
-                            p.info.authority = names[j];
+                        if (p.getAuthority() == null) {
+                            p.setEffectiveAuthority(names[j]);
                         } else {
-                            p.info.authority = p.info.authority + ";" + names[j];
+                            p.setEffectiveAuthority(p.getAuthority() + ";" + names[j]);
                         }
                         if (DEBUG_PACKAGE_SCANNING && chatty) {
                             Log.d(TAG, "Registered content provider: " + names[j]
-                                    + ", className = " + p.info.name
-                                    + ", isSyncable = " + p.info.isSyncable);
+                                    + ", className = " + p.getName()
+                                    + ", isSyncable = " + p.isSyncable());
                         }
                     } else {
-                        final PackageParser.Provider other =
+                        final ParsedProvider other =
                                 mProvidersByAuthority.get(names[j]);
                         final ComponentName component =
                                 (other != null && other.getComponentName() != null)
@@ -616,7 +665,7 @@
                         final String packageName =
                                 component != null ? component.getPackageName() : "?";
                         Slog.w(TAG, "Skipping provider name " + names[j]
-                                + " (in package " + pkg.applicationInfo.packageName + ")"
+                                + " (in package " + pkg.getAppInfoPackageName() + ")"
                                 + ": name already used by " + packageName);
                     }
                 }
@@ -627,7 +676,7 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(p.info.name);
+                r.append(p.getName());
             }
         }
         if (DEBUG_PACKAGE_SCANNING && chatty) {
@@ -636,13 +685,11 @@
     }
 
     @GuardedBy("mLock")
-    private void addReceiversLocked(PackageParser.Package pkg, boolean chatty) {
-        final int receiversSize = pkg.receivers.size();
+    private void addReceiversLocked(AndroidPackage pkg, boolean chatty) {
+        final int receiversSize = ArrayUtils.size(pkg.getReceivers());
         StringBuilder r = null;
         for (int i = 0; i < receiversSize; i++) {
-            PackageParser.Activity a = pkg.receivers.get(i);
-            a.info.processName = fixProcessName(pkg.applicationInfo.processName,
-                    a.info.processName);
+            ParsedActivity a = pkg.getReceivers().get(i);
             mReceivers.addActivity(a, "receiver", null);
             if (DEBUG_PACKAGE_SCANNING && chatty) {
                 if (r == null) {
@@ -650,7 +697,7 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(a.info.name);
+                r.append(a.getName());
             }
         }
         if (DEBUG_PACKAGE_SCANNING && chatty) {
@@ -659,13 +706,11 @@
     }
 
     @GuardedBy("mLock")
-    private void addServicesLocked(PackageParser.Package pkg, boolean chatty) {
-        final int servicesSize = pkg.services.size();
+    private void addServicesLocked(AndroidPackage pkg, boolean chatty) {
+        final int servicesSize = ArrayUtils.size(pkg.getServices());
         StringBuilder r = null;
         for (int i = 0; i < servicesSize; i++) {
-            PackageParser.Service s = pkg.services.get(i);
-            s.info.processName = fixProcessName(pkg.applicationInfo.processName,
-                    s.info.processName);
+            ParsedService s = pkg.getServices().get(i);
             mServices.addService(s);
             if (DEBUG_PACKAGE_SCANNING && chatty) {
                 if (r == null) {
@@ -673,7 +718,7 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(s.info.name);
+                r.append(s.getName());
             }
         }
         if (DEBUG_PACKAGE_SCANNING && chatty) {
@@ -681,13 +726,12 @@
         }
     }
 
-
     /**
      * <em>WARNING</em> for performance reasons, the passed in intentList WILL BE
      * MODIFIED. Do not pass in a list that should not be changed.
      */
-    private static <T> void getIntentListSubset(List<ActivityIntentInfo> intentList,
-            IterGenerator<T> generator, Iterator<T> searchIterator) {
+    private static <T> void getIntentListSubset(List<ParsedActivityIntentInfo> intentList,
+            Function<ParsedActivityIntentInfo, Iterator<T>> generator, Iterator<T> searchIterator) {
         // loop through the set of actions; every one must be found in the intent filter
         while (searchIterator.hasNext()) {
             // we must have at least one filter in the list to consider a match
@@ -698,14 +742,14 @@
             final T searchAction = searchIterator.next();
 
             // loop through the set of intent filters
-            final Iterator<ActivityIntentInfo> intentIter = intentList.iterator();
+            final Iterator<ParsedActivityIntentInfo> intentIter = intentList.iterator();
             while (intentIter.hasNext()) {
-                final ActivityIntentInfo intentInfo = intentIter.next();
+                final ParsedActivityIntentInfo intentInfo = intentIter.next();
                 boolean selectionFound = false;
 
                 // loop through the intent filter's selection criteria; at least one
                 // of them must match the searched criteria
-                final Iterator<T> intentSelectionIter = generator.generate(intentInfo);
+                final Iterator<T> intentSelectionIter = generator.apply(intentInfo);
                 while (intentSelectionIter != null && intentSelectionIter.hasNext()) {
                     final T intentSelection = intentSelectionIter.next();
                     if (intentSelection != null && intentSelection.equals(searchAction)) {
@@ -723,7 +767,7 @@
         }
     }
 
-    private static boolean isProtectedAction(ActivityIntentInfo filter) {
+    private static boolean isProtectedAction(ParsedActivityIntentInfo filter) {
         final Iterator<String> actionsIter = filter.actionsIterator();
         while (actionsIter != null && actionsIter.hasNext()) {
             final String filterAction = actionsIter.next();
@@ -737,20 +781,20 @@
     /**
      * Finds a privileged activity that matches the specified activity names.
      */
-    private static PackageParser.Activity findMatchingActivity(
-            List<PackageParser.Activity> activityList, ActivityInfo activityInfo) {
-        for (PackageParser.Activity sysActivity : activityList) {
-            if (sysActivity.info.name.equals(activityInfo.name)) {
+    private static ParsedActivity findMatchingActivity(
+            List<ParsedActivity> activityList, ParsedActivity activityInfo) {
+        for (ParsedActivity sysActivity : activityList) {
+            if (sysActivity.getName().equals(activityInfo.getName())) {
                 return sysActivity;
             }
-            if (sysActivity.info.name.equals(activityInfo.targetActivity)) {
+            if (sysActivity.getName().equals(activityInfo.targetActivity)) {
                 return sysActivity;
             }
-            if (sysActivity.info.targetActivity != null) {
-                if (sysActivity.info.targetActivity.equals(activityInfo.name)) {
+            if (sysActivity.targetActivity != null) {
+                if (sysActivity.targetActivity.equals(activityInfo.getName())) {
                     return sysActivity;
                 }
-                if (sysActivity.info.targetActivity.equals(activityInfo.targetActivity)) {
+                if (sysActivity.targetActivity.equals(activityInfo.targetActivity)) {
                     return sysActivity;
                 }
             }
@@ -771,24 +815,23 @@
      * <em>NOTE:</em> There is one exception. For security reasons, the setup wizard is
      * allowed to obtain any priority on any action.
      */
-    private void adjustPriority(List<PackageParser.Activity> systemActivities,
-            ActivityIntentInfo intent, String setupWizardPackage) {
+    private void adjustPriority(List<ParsedActivity> systemActivities,
+            ParsedActivityIntentInfo intent, String setupWizardPackage) {
         // nothing to do; priority is fine as-is
         if (intent.getPriority() <= 0) {
             return;
         }
 
-        final ActivityInfo activityInfo = intent.activity.info;
-        final ApplicationInfo applicationInfo = activityInfo.applicationInfo;
+        AndroidPackage pkg = sPackageManagerInternal.getPackage(intent.getPackageName());
 
         final boolean privilegedApp =
-                ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0);
+                ((pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0);
         if (!privilegedApp) {
             // non-privileged applications can never define a priority >0
             if (DEBUG_FILTERS) {
                 Slog.i(TAG, "Non-privileged app; cap priority to 0;"
-                        + " package: " + applicationInfo.packageName
-                        + " activity: " + intent.activity.className
+                        + " package: " + pkg.getPackageName()
+                        + " activity: " + intent.getClassName()
                         + " origPrio: " + intent.getPriority());
             }
             intent.setPriority(0);
@@ -812,8 +855,8 @@
                     mProtectedFilters.add(intent);
                     if (DEBUG_FILTERS) {
                         Slog.i(TAG, "Protected action; save for later;"
-                                + " package: " + applicationInfo.packageName
-                                + " activity: " + intent.activity.className
+                                + " package: " + pkg.getPackageName()
+                                + " activity: " + intent.getClassName()
                                 + " origPrio: " + intent.getPriority());
                     }
                     return;
@@ -822,12 +865,12 @@
                         Slog.i(TAG, "No setup wizard;"
                                 + " All protected intents capped to priority 0");
                     }
-                    if (intent.activity.info.packageName.equals(setupWizardPackage)) {
+                    if (intent.getPackageName().equals(setupWizardPackage)) {
                         if (DEBUG_FILTERS) {
                             Slog.i(TAG, "Found setup wizard;"
                                     + " allow priority " + intent.getPriority() + ";"
-                                    + " package: " + intent.activity.info.packageName
-                                    + " activity: " + intent.activity.className
+                                    + " package: " + intent.getPackageName()
+                                    + " activity: " + intent.getClassName()
                                     + " priority: " + intent.getPriority());
                         }
                         // setup wizard gets whatever it wants
@@ -835,8 +878,8 @@
                     }
                     if (DEBUG_FILTERS) {
                         Slog.i(TAG, "Protected action; cap priority to 0;"
-                                + " package: " + intent.activity.info.packageName
-                                + " activity: " + intent.activity.className
+                                + " package: " + intent.getPackageName()
+                                + " activity: " + intent.getClassName()
                                 + " origPrio: " + intent.getPriority());
                     }
                     intent.setPriority(0);
@@ -848,14 +891,28 @@
         }
 
         // privileged app unbundled update ... try to find the same activity
-        final PackageParser.Activity foundActivity =
-                findMatchingActivity(systemActivities, activityInfo);
+
+        ParsedActivity foundActivity = null;
+        ParsedActivity activity = null;
+
+        if (pkg.getActivities() != null) {
+            for (ParsedActivity parsedProvider : pkg.getActivities()) {
+                if (Objects.equals(parsedProvider.className, intent.getClassName())) {
+                    activity = parsedProvider;
+                }
+            }
+        }
+
+        if (activity != null) {
+            foundActivity = findMatchingActivity(systemActivities, activity);
+        }
+
         if (foundActivity == null) {
             // this is a new activity; it cannot obtain >0 priority
             if (DEBUG_FILTERS) {
                 Slog.i(TAG, "New activity; cap priority to 0;"
-                        + " package: " + applicationInfo.packageName
-                        + " activity: " + intent.activity.className
+                        + " package: " + pkg.getPackageName()
+                        + " activity: " + intent.getClassName()
                         + " origPrio: " + intent.getPriority());
             }
             intent.setPriority(0);
@@ -865,19 +922,19 @@
         // found activity, now check for filter equivalence
 
         // a shallow copy is enough; we modify the list, not its contents
-        final List<ActivityIntentInfo> intentListCopy = new ArrayList<>(foundActivity.intents);
-        final List<ActivityIntentInfo> foundFilters = mActivities.findFilters(intent);
+        final List<ParsedActivityIntentInfo> intentListCopy =
+                new ArrayList<>(foundActivity.intents);
 
         // find matching action subsets
         final Iterator<String> actionsIterator = intent.actionsIterator();
         if (actionsIterator != null) {
-            getIntentListSubset(intentListCopy, new ActionIterGenerator(), actionsIterator);
+            getIntentListSubset(intentListCopy, IntentFilter::actionsIterator, actionsIterator);
             if (intentListCopy.size() == 0) {
                 // no more intents to match; we're not equivalent
                 if (DEBUG_FILTERS) {
                     Slog.i(TAG, "Mismatched action; cap priority to 0;"
-                            + " package: " + applicationInfo.packageName
-                            + " activity: " + intent.activity.className
+                            + " package: " + pkg.getPackageName()
+                            + " activity: " + intent.getClassName()
                             + " origPrio: " + intent.getPriority());
                 }
                 intent.setPriority(0);
@@ -888,13 +945,14 @@
         // find matching category subsets
         final Iterator<String> categoriesIterator = intent.categoriesIterator();
         if (categoriesIterator != null) {
-            getIntentListSubset(intentListCopy, new CategoriesIterGenerator(), categoriesIterator);
+            getIntentListSubset(intentListCopy, IntentFilter::categoriesIterator,
+                    categoriesIterator);
             if (intentListCopy.size() == 0) {
                 // no more intents to match; we're not equivalent
                 if (DEBUG_FILTERS) {
                     Slog.i(TAG, "Mismatched category; cap priority to 0;"
-                            + " package: " + applicationInfo.packageName
-                            + " activity: " + intent.activity.className
+                            + " package: " + pkg.getPackageName()
+                            + " activity: " + intent.getClassName()
                             + " origPrio: " + intent.getPriority());
                 }
                 intent.setPriority(0);
@@ -905,13 +963,13 @@
         // find matching schemes subsets
         final Iterator<String> schemesIterator = intent.schemesIterator();
         if (schemesIterator != null) {
-            getIntentListSubset(intentListCopy, new SchemesIterGenerator(), schemesIterator);
+            getIntentListSubset(intentListCopy, IntentFilter::schemesIterator, schemesIterator);
             if (intentListCopy.size() == 0) {
                 // no more intents to match; we're not equivalent
                 if (DEBUG_FILTERS) {
                     Slog.i(TAG, "Mismatched scheme; cap priority to 0;"
-                            + " package: " + applicationInfo.packageName
-                            + " activity: " + intent.activity.className
+                            + " package: " + pkg.getPackageName()
+                            + " activity: " + intent.getClassName()
                             + " origPrio: " + intent.getPriority());
                 }
                 intent.setPriority(0);
@@ -923,14 +981,14 @@
         final Iterator<IntentFilter.AuthorityEntry> authoritiesIterator =
                 intent.authoritiesIterator();
         if (authoritiesIterator != null) {
-            getIntentListSubset(intentListCopy, new AuthoritiesIterGenerator(),
+            getIntentListSubset(intentListCopy, IntentFilter::authoritiesIterator,
                     authoritiesIterator);
             if (intentListCopy.size() == 0) {
                 // no more intents to match; we're not equivalent
                 if (DEBUG_FILTERS) {
                     Slog.i(TAG, "Mismatched authority; cap priority to 0;"
-                            + " package: " + applicationInfo.packageName
-                            + " activity: " + intent.activity.className
+                            + " package: " + pkg.getPackageName()
+                            + " activity: " + intent.getClassName()
                             + " origPrio: " + intent.getPriority());
                 }
                 intent.setPriority(0);
@@ -947,8 +1005,8 @@
             if (DEBUG_FILTERS) {
                 Slog.i(TAG, "Found matching filter(s);"
                         + " cap priority to " + cappedPriority + ";"
-                        + " package: " + applicationInfo.packageName
-                        + " activity: " + intent.activity.className
+                        + " package: " + pkg.getPackageName()
+                        + " activity: " + intent.getClassName()
                         + " origPrio: " + intent.getPriority());
             }
             intent.setPriority(cappedPriority);
@@ -958,15 +1016,15 @@
     }
 
     @GuardedBy("mLock")
-    private void removeAllComponentsLocked(PackageParser.Package pkg, boolean chatty) {
+    private void removeAllComponentsLocked(AndroidPackage pkg, boolean chatty) {
         int componentSize;
         StringBuilder r;
         int i;
 
-        componentSize = pkg.activities.size();
+        componentSize = ArrayUtils.size(pkg.getActivities());
         r = null;
         for (i = 0; i < componentSize; i++) {
-            PackageParser.Activity a = pkg.activities.get(i);
+            ParsedActivity a = pkg.getActivities().get(i);
             mActivities.removeActivity(a, "activity");
             if (DEBUG_REMOVE && chatty) {
                 if (r == null) {
@@ -974,32 +1032,32 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(a.info.name);
+                r.append(a.getName());
             }
         }
         if (DEBUG_REMOVE && chatty) {
             Log.d(TAG, "  Activities: " + (r == null ? "<NONE>" : r));
         }
 
-        componentSize = pkg.providers.size();
+        componentSize = ArrayUtils.size(pkg.getProviders());
         r = null;
         for (i = 0; i < componentSize; i++) {
-            PackageParser.Provider p = pkg.providers.get(i);
+            ParsedProvider p = pkg.getProviders().get(i);
             mProviders.removeProvider(p);
-            if (p.info.authority == null) {
+            if (p.getAuthority() == null) {
                 // Another content provider with this authority existed when this app was
                 // installed, so this authority is null. Ignore it as we don't have to
                 // unregister the provider.
                 continue;
             }
-            String[] names = p.info.authority.split(";");
+            String[] names = p.getAuthority().split(";");
             for (int j = 0; j < names.length; j++) {
                 if (mProvidersByAuthority.get(names[j]) == p) {
                     mProvidersByAuthority.remove(names[j]);
                     if (DEBUG_REMOVE && chatty) {
                         Log.d(TAG, "Unregistered content provider: " + names[j]
-                                + ", className = " + p.info.name + ", isSyncable = "
-                                + p.info.isSyncable);
+                                + ", className = " + p.getName() + ", isSyncable = "
+                                + p.isSyncable());
                     }
                 }
             }
@@ -1009,17 +1067,17 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(p.info.name);
+                r.append(p.getName());
             }
         }
         if (DEBUG_REMOVE && chatty) {
             Log.d(TAG, "  Providers: " + (r == null ? "<NONE>" : r));
         }
 
-        componentSize = pkg.receivers.size();
+        componentSize = ArrayUtils.size(pkg.getReceivers());
         r = null;
         for (i = 0; i < componentSize; i++) {
-            PackageParser.Activity a = pkg.receivers.get(i);
+            ParsedActivity a = pkg.getReceivers().get(i);
             mReceivers.removeActivity(a, "receiver");
             if (DEBUG_REMOVE && chatty) {
                 if (r == null) {
@@ -1027,17 +1085,17 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(a.info.name);
+                r.append(a.getName());
             }
         }
         if (DEBUG_REMOVE && chatty) {
             Log.d(TAG, "  Receivers: " + (r == null ? "<NONE>" : r));
         }
 
-        componentSize = pkg.services.size();
+        componentSize = ArrayUtils.size(pkg.getServices());
         r = null;
         for (i = 0; i < componentSize; i++) {
-            PackageParser.Service s = pkg.services.get(i);
+            ParsedService s = pkg.getServices().get(i);
             mServices.removeService(s);
             if (DEBUG_REMOVE && chatty) {
                 if (r == null) {
@@ -1045,7 +1103,7 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(s.info.name);
+                r.append(s.getName());
             }
         }
         if (DEBUG_REMOVE && chatty) {
@@ -1054,26 +1112,26 @@
     }
 
     @GuardedBy("mLock")
-    private void assertProvidersNotDefinedLocked(PackageParser.Package pkg)
+    private void assertProvidersNotDefinedLocked(AndroidPackage pkg)
             throws PackageManagerException {
-        final int providersSize = pkg.providers.size();
+        final int providersSize = ArrayUtils.size(pkg.getProviders());
         int i;
         for (i = 0; i < providersSize; i++) {
-            PackageParser.Provider p = pkg.providers.get(i);
-            if (p.info.authority != null) {
-                final String[] names = p.info.authority.split(";");
+            ParsedProvider p = pkg.getProviders().get(i);
+            if (p.getAuthority() != null) {
+                final String[] names = p.getAuthority().split(";");
                 for (int j = 0; j < names.length; j++) {
                     if (mProvidersByAuthority.containsKey(names[j])) {
-                        final PackageParser.Provider other = mProvidersByAuthority.get(names[j]);
+                        final ParsedProvider other = mProvidersByAuthority.get(names[j]);
                         final String otherPackageName =
                                 (other != null && other.getComponentName() != null)
                                         ? other.getComponentName().getPackageName() : "?";
                         // if we're installing over the same already-installed package, this is ok
-                        if (!otherPackageName.equals(pkg.packageName)) {
+                        if (!otherPackageName.equals(pkg.getPackageName())) {
                             throw new PackageManagerException(
                                     INSTALL_FAILED_CONFLICTING_PROVIDER,
                                     "Can't install because provider name " + names[j]
-                                            + " (in package " + pkg.applicationInfo.packageName
+                                            + " (in package " + pkg.getPackageName()
                                             + ") is already used by " + otherPackageName);
                         }
                     }
@@ -1082,8 +1140,9 @@
         }
     }
 
-    private static final class ActivityIntentResolver
-            extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {
+    private static class ActivityIntentResolver
+            extends IntentResolver<ParsedActivityIntentInfo, ResolveInfo> {
+
         @Override
         public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
                 boolean defaultOnly, int userId) {
@@ -1104,24 +1163,24 @@
         }
 
         List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
-                int flags, List<PackageParser.Activity> packageActivities, int userId) {
+                int flags, List<ParsedActivity> packageActivities, int userId) {
             if (!sUserManager.exists(userId)) {
                 return null;
             }
             if (packageActivities == null) {
-                return null;
+                return Collections.emptyList();
             }
             mFlags = flags;
             final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
             final int activitiesSize = packageActivities.size();
-            ArrayList<PackageParser.ActivityIntentInfo[]> listCut = new ArrayList<>(activitiesSize);
+            ArrayList<ParsedActivityIntentInfo[]> listCut = new ArrayList<>(activitiesSize);
 
-            ArrayList<PackageParser.ActivityIntentInfo> intentFilters;
+            List<ParsedActivityIntentInfo> intentFilters;
             for (int i = 0; i < activitiesSize; ++i) {
                 intentFilters = packageActivities.get(i).intents;
                 if (intentFilters != null && intentFilters.size() > 0) {
-                    PackageParser.ActivityIntentInfo[] array =
-                            new PackageParser.ActivityIntentInfo[intentFilters.size()];
+                    ParsedActivityIntentInfo[] array =
+                            new ParsedActivityIntentInfo[intentFilters.size()];
                     intentFilters.toArray(array);
                     listCut.add(array);
                 }
@@ -1129,21 +1188,21 @@
             return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
         }
 
-        private void addActivity(PackageParser.Activity a, String type,
-                List<PackageParser.ActivityIntentInfo> newIntents) {
+        private void addActivity(ParsedActivity a, String type,
+                List<ParsedActivityIntentInfo> newIntents) {
             mActivities.put(a.getComponentName(), a);
             if (DEBUG_SHOW_INFO) {
-                final CharSequence label = a.info.nonLocalizedLabel != null
-                        ? a.info.nonLocalizedLabel
-                        : a.info.name;
+                final CharSequence label = a.nonLocalizedLabel != null
+                        ? a.nonLocalizedLabel
+                        : a.getName();
                 Log.v(TAG, "  " + type + " " + label + ":");
             }
             if (DEBUG_SHOW_INFO) {
-                Log.v(TAG, "    Class=" + a.info.name);
+                Log.v(TAG, "    Class=" + a.getName());
             }
             final int intentsSize = a.intents.size();
             for (int j = 0; j < intentsSize; j++) {
-                PackageParser.ActivityIntentInfo intent = a.intents.get(j);
+                ParsedActivityIntentInfo intent = a.intents.get(j);
                 if (newIntents != null && "activity".equals(type)) {
                     newIntents.add(intent);
                 }
@@ -1152,23 +1211,23 @@
                     intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
                 }
                 if (!intent.debugCheck()) {
-                    Log.w(TAG, "==> For Activity " + a.info.name);
+                    Log.w(TAG, "==> For Activity " + a.getName());
                 }
                 addFilter(intent);
             }
         }
 
-        private void removeActivity(PackageParser.Activity a, String type) {
+        private void removeActivity(ParsedActivity a, String type) {
             mActivities.remove(a.getComponentName());
             if (DEBUG_SHOW_INFO) {
                 Log.v(TAG, "  " + type + " "
-                        + (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel
-                                : a.info.name) + ":");
-                Log.v(TAG, "    Class=" + a.info.name);
+                        + (a.nonLocalizedLabel != null ? a.nonLocalizedLabel
+                                : a.getName()) + ":");
+                Log.v(TAG, "    Class=" + a.getName());
             }
             final int intentsSize = a.intents.size();
             for (int j = 0; j < intentsSize; j++) {
-                PackageParser.ActivityIntentInfo intent = a.intents.get(j);
+                ParsedActivityIntentInfo intent = a.intents.get(j);
                 if (DEBUG_SHOW_INFO) {
                     Log.v(TAG, "    IntentFilter:");
                     intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
@@ -1179,11 +1238,11 @@
 
         @Override
         protected boolean allowFilterResult(
-                PackageParser.ActivityIntentInfo filter, List<ResolveInfo> dest) {
-            ActivityInfo filterAi = filter.activity.info;
+                ParsedActivityIntentInfo filter, List<ResolveInfo> dest) {
             for (int i = dest.size() - 1; i >= 0; --i) {
                 ActivityInfo destAi = dest.get(i).activityInfo;
-                if (destAi.name == filterAi.name && destAi.packageName == filterAi.packageName) {
+                if (Objects.equals(destAi.name, filter.getClassName())
+                        && Objects.equals(destAi.packageName, filter.getPackageName())) {
                     return false;
                 }
             }
@@ -1191,34 +1250,39 @@
         }
 
         @Override
-        protected ActivityIntentInfo[] newArray(int size) {
-            return new ActivityIntentInfo[size];
+        protected ParsedActivityIntentInfo[] newArray(int size) {
+            return new ParsedActivityIntentInfo[size];
         }
 
         @Override
-        protected boolean isFilterStopped(PackageParser.ActivityIntentInfo filter, int userId) {
+        protected boolean isFilterStopped(ParsedActivityIntentInfo filter, int userId) {
             if (!sUserManager.exists(userId)) return true;
-            PackageParser.Package p = filter.activity.owner;
-            if (p != null) {
-                PackageSetting ps = (PackageSetting) p.mExtras;
-                if (ps != null) {
-                    // System apps are never considered stopped for purposes of
-                    // filtering, because there may be no way for the user to
-                    // actually re-launch them.
-                    return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
-                            && ps.getStopped(userId);
-                }
+
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+            if (pkg == null) {
+                return false;
             }
-            return false;
+
+            PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
+                    filter.getPackageName());
+            if (ps == null) {
+                return false;
+            }
+
+            // System apps are never considered stopped for purposes of
+            // filtering, because there may be no way for the user to
+            // actually re-launch them.
+            return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
+                    && ps.getStopped(userId);
         }
 
         @Override
         protected boolean isPackageForFilter(String packageName,
-                PackageParser.ActivityIntentInfo info) {
-            return packageName.equals(info.activity.owner.packageName);
+                ParsedActivityIntentInfo info) {
+            return packageName.equals(info.getPackageName());
         }
 
-        private void log(String reason, ActivityIntentInfo info, int match,
+        private void log(String reason, ParsedActivityIntentInfo info, int match,
                 int userId) {
             Slog.w(TAG, reason
                     + "; match: "
@@ -1228,7 +1292,7 @@
         }
 
         @Override
-        protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
+        protected ResolveInfo newResult(ParsedActivityIntentInfo info,
                 int match, int userId) {
             if (!sUserManager.exists(userId)) {
                 if (DEBUG) {
@@ -1236,7 +1300,29 @@
                 }
                 return null;
             }
-            if (!sPackageManagerInternal.isEnabledAndMatches(info.activity.info, mFlags, userId)) {
+
+            ParsedActivity activity = null;
+
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(info.getPackageName());
+            if (pkg == null) {
+                return null;
+            }
+
+            // TODO(b/135203078): Consider more efficient ways of doing this.
+            List<ParsedActivity> activities = getResolveList(pkg);
+            if (activities != null) {
+                for (ParsedActivity parsedActivity : activities) {
+                    if (Objects.equals(parsedActivity.className, info.getClassName())) {
+                        activity = parsedActivity;
+                    }
+                }
+            }
+
+            if (activity == null) {
+                return null;
+            }
+
+            if (!sPackageManagerInternal.isEnabledAndMatches(activity, mFlags, userId)) {
                 if (DEBUG) {
                     log("!PackageManagerInternal.isEnabledAndMatches; mFlags="
                             + DebugUtils.flagsToString(PackageManager.class, "MATCH_", mFlags),
@@ -1244,8 +1330,8 @@
                 }
                 return null;
             }
-            final PackageParser.Activity activity = info.activity;
-            PackageSetting ps = (PackageSetting) activity.owner.mExtras;
+            PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
+                    info.getPackageName());
             if (ps == null) {
                 if (DEBUG) {
                     log("info.activity.owner.mExtras == null", info, match, userId);
@@ -1254,10 +1340,10 @@
             }
             final PackageUserState userState = ps.readUserState(userId);
             ActivityInfo ai =
-                    PackageParser.generateActivityInfo(activity, mFlags, userState, userId);
+                    PackageInfoUtils.generateActivityInfo(pkg, activity, mFlags, userState, userId);
             if (ai == null) {
                 if (DEBUG) {
-                    log("Failed to create ActivityInfo based on " + info.activity, info, match,
+                    log("Failed to create ActivityInfo based on " + activity, info, match,
                             userId);
                 }
                 return null;
@@ -1307,7 +1393,7 @@
             }
             res.handleAllWebDataURI = info.handleAllWebDataURI();
             res.priority = info.getPriority();
-            res.preferredOrder = activity.owner.mPreferredOrder;
+            res.preferredOrder = pkg.getPreferredOrder();
             //System.out.println("Result: " + res.activityInfo.className +
             //                   " = " + res.priority);
             res.match = match;
@@ -1332,40 +1418,64 @@
 
         @Override
         protected void dumpFilter(PrintWriter out, String prefix,
-                PackageParser.ActivityIntentInfo filter) {
+                ParsedActivityIntentInfo filter) {
+            ParsedActivity activity = null;
+
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+            if (pkg != null && pkg.getActivities() != null) {
+                for (ParsedActivity parsedActivity : pkg.getActivities()) {
+                    if (Objects.equals(parsedActivity.className, filter.getClassName())) {
+                        activity = parsedActivity;
+                    }
+                }
+            }
+
             out.print(prefix);
-            out.print(Integer.toHexString(System.identityHashCode(filter.activity)));
+            out.print(Integer.toHexString(System.identityHashCode(activity)));
             out.print(' ');
-            filter.activity.printComponentShortName(out);
+            ComponentName.printShortString(out, filter.getPackageName(), filter.getClassName());
             out.print(" filter ");
             out.println(Integer.toHexString(System.identityHashCode(filter)));
         }
 
         @Override
-        protected Object filterToLabel(PackageParser.ActivityIntentInfo filter) {
-            return filter.activity;
+        protected Object filterToLabel(ParsedActivityIntentInfo filter) {
+            return filter;
         }
 
         protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {
-            PackageParser.Activity activity = (PackageParser.Activity) label;
+            ParsedActivityIntentInfo activity = (ParsedActivityIntentInfo) label;
             out.print(prefix);
             out.print(Integer.toHexString(System.identityHashCode(activity)));
             out.print(' ');
-            activity.printComponentShortName(out);
+            ComponentName.printShortString(out, activity.getPackageName(), activity.getClassName());
             if (count > 1) {
                 out.print(" ("); out.print(count); out.print(" filters)");
             }
             out.println();
         }
 
+        protected List<ParsedActivity> getResolveList(AndroidPackage pkg) {
+            return pkg.getActivities();
+        }
+
         // Keys are String (activity class name), values are Activity.
-        private final ArrayMap<ComponentName, PackageParser.Activity> mActivities =
+        private final ArrayMap<ComponentName, ParsedActivity> mActivities =
                 new ArrayMap<>();
         private int mFlags;
     }
 
+    // Both receivers and activities share a class, but point to different get methods
+    private static final class ReceiverIntentResolver extends ActivityIntentResolver {
+
+        @Override
+        protected List<ParsedActivity> getResolveList(AndroidPackage pkg) {
+            return pkg.getReceivers();
+        }
+    }
+
     private static final class ProviderIntentResolver
-            extends IntentResolver<PackageParser.ProviderIntentInfo, ResolveInfo> {
+            extends IntentResolver<ParsedProviderIntentInfo, ResolveInfo> {
         @Override
         public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
                 boolean defaultOnly, int userId) {
@@ -1387,24 +1497,24 @@
 
         @Nullable
         List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
-                int flags, List<PackageParser.Provider> packageProviders, int userId) {
+                int flags, List<ParsedProvider> packageProviders, int userId) {
             if (!sUserManager.exists(userId)) {
                 return null;
             }
             if (packageProviders == null) {
-                return null;
+                return Collections.emptyList();
             }
             mFlags = flags;
             final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
             final int providersSize = packageProviders.size();
-            ArrayList<PackageParser.ProviderIntentInfo[]> listCut = new ArrayList<>(providersSize);
+            ArrayList<ParsedProviderIntentInfo[]> listCut = new ArrayList<>(providersSize);
 
-            ArrayList<PackageParser.ProviderIntentInfo> intentFilters;
+            List<ParsedProviderIntentInfo> intentFilters;
             for (int i = 0; i < providersSize; ++i) {
-                intentFilters = packageProviders.get(i).intents;
+                intentFilters = packageProviders.get(i).getIntents();
                 if (intentFilters != null && intentFilters.size() > 0) {
-                    PackageParser.ProviderIntentInfo[] array =
-                            new PackageParser.ProviderIntentInfo[intentFilters.size()];
+                    ParsedProviderIntentInfo[] array =
+                            new ParsedProviderIntentInfo[intentFilters.size()];
                     intentFilters.toArray(array);
                     listCut.add(array);
                 }
@@ -1412,7 +1522,7 @@
             return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
         }
 
-        void addProvider(PackageParser.Provider p) {
+        void addProvider(ParsedProvider p) {
             if (mProviders.containsKey(p.getComponentName())) {
                 Slog.w(TAG, "Provider " + p.getComponentName() + " already defined; ignoring");
                 return;
@@ -1421,39 +1531,39 @@
             mProviders.put(p.getComponentName(), p);
             if (DEBUG_SHOW_INFO) {
                 Log.v(TAG, "  "
-                        + (p.info.nonLocalizedLabel != null
-                                ? p.info.nonLocalizedLabel
-                                : p.info.name)
+                        + (p.nonLocalizedLabel != null
+                                ? p.nonLocalizedLabel
+                                : p.getName())
                         + ":");
-                Log.v(TAG, "    Class=" + p.info.name);
+                Log.v(TAG, "    Class=" + p.getName());
             }
-            final int intentsSize = p.intents.size();
+            final int intentsSize = p.getIntents().size();
             int j;
             for (j = 0; j < intentsSize; j++) {
-                PackageParser.ProviderIntentInfo intent = p.intents.get(j);
+                ParsedProviderIntentInfo intent = p.getIntents().get(j);
                 if (DEBUG_SHOW_INFO) {
                     Log.v(TAG, "    IntentFilter:");
                     intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
                 }
                 if (!intent.debugCheck()) {
-                    Log.w(TAG, "==> For Provider " + p.info.name);
+                    Log.w(TAG, "==> For Provider " + p.getName());
                 }
                 addFilter(intent);
             }
         }
 
-        void removeProvider(PackageParser.Provider p) {
+        void removeProvider(ParsedProvider p) {
             mProviders.remove(p.getComponentName());
             if (DEBUG_SHOW_INFO) {
-                Log.v(TAG, "  " + (p.info.nonLocalizedLabel != null
-                        ? p.info.nonLocalizedLabel
-                        : p.info.name) + ":");
-                Log.v(TAG, "    Class=" + p.info.name);
+                Log.v(TAG, "  " + (p.nonLocalizedLabel != null
+                        ? p.nonLocalizedLabel
+                        : p.getName()) + ":");
+                Log.v(TAG, "    Class=" + p.getName());
             }
-            final int intentsSize = p.intents.size();
+            final int intentsSize = p.getIntents().size();
             int j;
             for (j = 0; j < intentsSize; j++) {
-                PackageParser.ProviderIntentInfo intent = p.intents.get(j);
+                ParsedProviderIntentInfo intent = p.getIntents().get(j);
                 if (DEBUG_SHOW_INFO) {
                     Log.v(TAG, "    IntentFilter:");
                     intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
@@ -1464,12 +1574,11 @@
 
         @Override
         protected boolean allowFilterResult(
-                PackageParser.ProviderIntentInfo filter, List<ResolveInfo> dest) {
-            ProviderInfo filterPi = filter.provider.info;
+                ParsedProviderIntentInfo filter, List<ResolveInfo> dest) {
             for (int i = dest.size() - 1; i >= 0; i--) {
                 ProviderInfo destPi = dest.get(i).providerInfo;
-                if (destPi.name == filterPi.name
-                        && destPi.packageName == filterPi.packageName) {
+                if (Objects.equals(destPi.name, filter.getClassName())
+                        && Objects.equals(destPi.packageName, filter.getPackageName())) {
                     return false;
                 }
             }
@@ -1477,47 +1586,68 @@
         }
 
         @Override
-        protected PackageParser.ProviderIntentInfo[] newArray(int size) {
-            return new PackageParser.ProviderIntentInfo[size];
+        protected ParsedProviderIntentInfo[] newArray(int size) {
+            return new ParsedProviderIntentInfo[size];
         }
 
         @Override
-        protected boolean isFilterStopped(PackageParser.ProviderIntentInfo filter, int userId) {
+        protected boolean isFilterStopped(ParsedProviderIntentInfo filter, int userId) {
             if (!sUserManager.exists(userId)) {
                 return true;
             }
-            PackageParser.Package p = filter.provider.owner;
-            if (p != null) {
-                PackageSetting ps = (PackageSetting) p.mExtras;
-                if (ps != null) {
-                    // System apps are never considered stopped for purposes of
-                    // filtering, because there may be no way for the user to
-                    // actually re-launch them.
-                    return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
-                            && ps.getStopped(userId);
-                }
+
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+            if (pkg == null) {
+                return false;
             }
-            return false;
+
+            PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
+                    filter.getPackageName());
+            if (ps == null) {
+                return false;
+            }
+
+            // System apps are never considered stopped for purposes of
+            // filtering, because there may be no way for the user to
+            // actually re-launch them.
+            return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
+                    && ps.getStopped(userId);
         }
 
         @Override
         protected boolean isPackageForFilter(String packageName,
-                PackageParser.ProviderIntentInfo info) {
-            return packageName.equals(info.provider.owner.packageName);
+                ParsedProviderIntentInfo info) {
+            return packageName.equals(info.getPackageName());
         }
 
         @Override
-        protected ResolveInfo newResult(PackageParser.ProviderIntentInfo filter,
+        protected ResolveInfo newResult(ParsedProviderIntentInfo filter,
                 int match, int userId) {
             if (!sUserManager.exists(userId)) {
                 return null;
             }
-            final PackageParser.ProviderIntentInfo info = filter;
-            if (!sPackageManagerInternal.isEnabledAndMatches(info.provider.info, mFlags, userId)) {
+
+            ParsedProvider provider = null;
+
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+            if (pkg != null && pkg.getProviders() != null) {
+                for (ParsedProvider parsedProvider : pkg.getProviders()) {
+                    if (Objects.equals(parsedProvider.className, filter.getClassName())) {
+                        provider = parsedProvider;
+                    }
+                }
+            }
+
+            if (provider == null) {
                 return null;
             }
-            final PackageParser.Provider provider = info.provider;
-            PackageSetting ps = (PackageSetting) provider.owner.mExtras;
+
+            if (!sPackageManagerInternal.isEnabledAndMatches(provider, mFlags, userId)) {
+                return null;
+            }
+
+            PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
+                    filter.getPackageName());
             if (ps == null) {
                 return null;
             }
@@ -1527,7 +1657,7 @@
             final boolean isInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0;
             // throw out filters that aren't visible to instant applications
             if (matchVisibleToInstantApp
-                    && !(info.isVisibleToInstantApp() || userState.instantApp)) {
+                    && !(filter.isVisibleToInstantApp() || userState.instantApp)) {
                 return null;
             }
             // throw out instant application filters if we're not explicitly requesting them
@@ -1539,8 +1669,8 @@
             if (userState.instantApp && ps.isUpdateAvailable()) {
                 return null;
             }
-            ProviderInfo pi = PackageParser.generateProviderInfo(provider, mFlags,
-                    userState, userId);
+            ProviderInfo pi = PackageInfoUtils.generateProviderInfo(pkg, provider,
+                    mFlags, userState, userId);
             if (pi == null) {
                 return null;
             }
@@ -1549,13 +1679,13 @@
             if ((mFlags & PackageManager.GET_RESOLVED_FILTER) != 0) {
                 res.filter = filter;
             }
-            res.priority = info.getPriority();
-            res.preferredOrder = provider.owner.mPreferredOrder;
+            res.priority = filter.getPriority();
+            res.preferredOrder = pkg.getPreferredOrder();
             res.match = match;
-            res.isDefault = info.hasDefault;
-            res.labelRes = info.labelRes;
-            res.nonLocalizedLabel = info.nonLocalizedLabel;
-            res.icon = info.icon;
+            res.isDefault = filter.hasDefault;
+            res.labelRes = filter.labelRes;
+            res.nonLocalizedLabel = filter.nonLocalizedLabel;
+            res.icon = filter.icon;
             res.system = res.providerInfo.applicationInfo.isSystemApp();
             return res;
         }
@@ -1567,26 +1697,37 @@
 
         @Override
         protected void dumpFilter(PrintWriter out, String prefix,
-                PackageParser.ProviderIntentInfo filter) {
+                ParsedProviderIntentInfo filter) {
+            ParsedProvider provider = null;
+
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+            if (pkg != null && pkg.getProviders() != null) {
+                for (ParsedProvider parsedProvider : pkg.getProviders()) {
+                    if (Objects.equals(parsedProvider.className, filter.getClassName())) {
+                        provider = parsedProvider;
+                    }
+                }
+            }
+
             out.print(prefix);
-            out.print(Integer.toHexString(System.identityHashCode(filter.provider)));
+            out.print(Integer.toHexString(System.identityHashCode(provider)));
             out.print(' ');
-            filter.provider.printComponentShortName(out);
+            ComponentName.printShortString(out, filter.getPackageName(), filter.getClassName());
             out.print(" filter ");
             out.println(Integer.toHexString(System.identityHashCode(filter)));
         }
 
         @Override
-        protected Object filterToLabel(PackageParser.ProviderIntentInfo filter) {
-            return filter.provider;
+        protected Object filterToLabel(ParsedProviderIntentInfo filter) {
+            return filter;
         }
 
         protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {
-            final PackageParser.Provider provider = (PackageParser.Provider) label;
+            final ParsedProviderIntentInfo provider = (ParsedProviderIntentInfo) label;
             out.print(prefix);
             out.print(Integer.toHexString(System.identityHashCode(provider)));
             out.print(' ');
-            provider.printComponentShortName(out);
+            ComponentName.printShortString(out, provider.getPackageName(), provider.getClassName());
             if (count > 1) {
                 out.print(" (");
                 out.print(count);
@@ -1595,12 +1736,12 @@
             out.println();
         }
 
-        private final ArrayMap<ComponentName, PackageParser.Provider> mProviders = new ArrayMap<>();
+        private final ArrayMap<ComponentName, ParsedProvider> mProviders = new ArrayMap<>();
         private int mFlags;
     }
 
     private static final class ServiceIntentResolver
-            extends IntentResolver<PackageParser.ServiceIntentInfo, ResolveInfo> {
+            extends IntentResolver<ParsedServiceIntentInfo, ResolveInfo> {
         @Override
         public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
                 boolean defaultOnly, int userId) {
@@ -1618,22 +1759,22 @@
         }
 
         List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
-                int flags, List<PackageParser.Service> packageServices, int userId) {
+                int flags, List<ParsedService> packageServices, int userId) {
             if (!sUserManager.exists(userId)) return null;
             if (packageServices == null) {
-                return null;
+                return Collections.emptyList();
             }
             mFlags = flags;
             final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
             final int servicesSize = packageServices.size();
-            ArrayList<PackageParser.ServiceIntentInfo[]> listCut = new ArrayList<>(servicesSize);
+            ArrayList<ParsedServiceIntentInfo[]> listCut = new ArrayList<>(servicesSize);
 
-            ArrayList<PackageParser.ServiceIntentInfo> intentFilters;
+            List<ParsedServiceIntentInfo> intentFilters;
             for (int i = 0; i < servicesSize; ++i) {
                 intentFilters = packageServices.get(i).intents;
                 if (intentFilters != null && intentFilters.size() > 0) {
-                    PackageParser.ServiceIntentInfo[] array =
-                            new PackageParser.ServiceIntentInfo[intentFilters.size()];
+                    ParsedServiceIntentInfo[] array =
+                            new ParsedServiceIntentInfo[intentFilters.size()];
                     intentFilters.toArray(array);
                     listCut.add(array);
                 }
@@ -1641,40 +1782,40 @@
             return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
         }
 
-        void addService(PackageParser.Service s) {
+        void addService(ParsedService s) {
             mServices.put(s.getComponentName(), s);
             if (DEBUG_SHOW_INFO) {
                 Log.v(TAG, "  "
-                        + (s.info.nonLocalizedLabel != null
-                        ? s.info.nonLocalizedLabel : s.info.name) + ":");
-                Log.v(TAG, "    Class=" + s.info.name);
+                        + (s.nonLocalizedLabel != null
+                        ? s.nonLocalizedLabel : s.getName()) + ":");
+                Log.v(TAG, "    Class=" + s.getName());
             }
             final int intentsSize = s.intents.size();
             int j;
             for (j = 0; j < intentsSize; j++) {
-                PackageParser.ServiceIntentInfo intent = s.intents.get(j);
+                ParsedServiceIntentInfo intent = s.intents.get(j);
                 if (DEBUG_SHOW_INFO) {
                     Log.v(TAG, "    IntentFilter:");
                     intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
                 }
                 if (!intent.debugCheck()) {
-                    Log.w(TAG, "==> For Service " + s.info.name);
+                    Log.w(TAG, "==> For Service " + s.getName());
                 }
                 addFilter(intent);
             }
         }
 
-        void removeService(PackageParser.Service s) {
+        void removeService(ParsedService s) {
             mServices.remove(s.getComponentName());
             if (DEBUG_SHOW_INFO) {
-                Log.v(TAG, "  " + (s.info.nonLocalizedLabel != null
-                        ? s.info.nonLocalizedLabel : s.info.name) + ":");
-                Log.v(TAG, "    Class=" + s.info.name);
+                Log.v(TAG, "  " + (s.nonLocalizedLabel != null
+                        ? s.nonLocalizedLabel : s.getName()) + ":");
+                Log.v(TAG, "    Class=" + s.getName());
             }
             final int intentsSize = s.intents.size();
             int j;
             for (j = 0; j < intentsSize; j++) {
-                PackageParser.ServiceIntentInfo intent = s.intents.get(j);
+                ParsedServiceIntentInfo intent = s.intents.get(j);
                 if (DEBUG_SHOW_INFO) {
                     Log.v(TAG, "    IntentFilter:");
                     intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
@@ -1685,12 +1826,11 @@
 
         @Override
         protected boolean allowFilterResult(
-                PackageParser.ServiceIntentInfo filter, List<ResolveInfo> dest) {
-            ServiceInfo filterSi = filter.service.info;
+                ParsedServiceIntentInfo filter, List<ResolveInfo> dest) {
             for (int i = dest.size() - 1; i >= 0; --i) {
                 ServiceInfo destAi = dest.get(i).serviceInfo;
-                if (destAi.name == filterSi.name
-                        && destAi.packageName == filterSi.packageName) {
+                if (Objects.equals(destAi.name, filter.getClassName())
+                        && Objects.equals(destAi.packageName, filter.getPackageName())) {
                     return false;
                 }
             }
@@ -1698,48 +1838,69 @@
         }
 
         @Override
-        protected PackageParser.ServiceIntentInfo[] newArray(int size) {
-            return new PackageParser.ServiceIntentInfo[size];
+        protected ParsedServiceIntentInfo[] newArray(int size) {
+            return new ParsedServiceIntentInfo[size];
         }
 
         @Override
-        protected boolean isFilterStopped(PackageParser.ServiceIntentInfo filter, int userId) {
+        protected boolean isFilterStopped(ParsedServiceIntentInfo filter, int userId) {
             if (!sUserManager.exists(userId)) return true;
-            PackageParser.Package p = filter.service.owner;
-            if (p != null) {
-                PackageSetting ps = (PackageSetting) p.mExtras;
-                if (ps != null) {
-                    // System apps are never considered stopped for purposes of
-                    // filtering, because there may be no way for the user to
-                    // actually re-launch them.
-                    return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
-                            && ps.getStopped(userId);
-                }
+
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+            if (pkg == null) {
+                return false;
             }
-            return false;
+
+            PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
+                    filter.getPackageName());
+            if (ps == null) {
+                return false;
+            }
+
+            // System apps are never considered stopped for purposes of
+            // filtering, because there may be no way for the user to
+            // actually re-launch them.
+            return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
+                    && ps.getStopped(userId);
         }
 
         @Override
         protected boolean isPackageForFilter(String packageName,
-                PackageParser.ServiceIntentInfo info) {
-            return packageName.equals(info.service.owner.packageName);
+                ParsedServiceIntentInfo info) {
+            return packageName.equals(info.getPackageName());
         }
 
         @Override
-        protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter,
+        protected ResolveInfo newResult(ParsedServiceIntentInfo filter,
                 int match, int userId) {
             if (!sUserManager.exists(userId)) return null;
-            final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo) filter;
-            if (!sPackageManagerInternal.isEnabledAndMatches(info.service.info, mFlags, userId)) {
+
+            ParsedService service = null;
+
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+            if (pkg != null && pkg.getServices() != null) {
+                for (ParsedService parsedService : pkg.getServices()) {
+                    if (Objects.equals(parsedService.className, filter.getClassName())) {
+                        service = parsedService;
+                    }
+                }
+            }
+
+            if (service == null) {
                 return null;
             }
-            final PackageParser.Service service = info.service;
-            PackageSetting ps = (PackageSetting) service.owner.mExtras;
+
+            if (!sPackageManagerInternal.isEnabledAndMatches(service, mFlags, userId)) {
+                return null;
+            }
+
+            PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting(
+                    filter.getPackageName());
             if (ps == null) {
                 return null;
             }
             final PackageUserState userState = ps.readUserState(userId);
-            ServiceInfo si = PackageParser.generateServiceInfo(service, mFlags,
+            ServiceInfo si = PackageInfoUtils.generateServiceInfo(pkg, service, mFlags,
                     userState, userId);
             if (si == null) {
                 return null;
@@ -1749,7 +1910,7 @@
             final boolean isInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0;
             // throw out filters that aren't visible to ephemeral apps
             if (matchVisibleToInstantApp
-                    && !(info.isVisibleToInstantApp() || userState.instantApp)) {
+                    && !(filter.isVisibleToInstantApp() || userState.instantApp)) {
                 return null;
             }
             // throw out ephemeral filters if we're not explicitly requesting them
@@ -1766,13 +1927,13 @@
             if ((mFlags & PackageManager.GET_RESOLVED_FILTER) != 0) {
                 res.filter = filter;
             }
-            res.priority = info.getPriority();
-            res.preferredOrder = service.owner.mPreferredOrder;
+            res.priority = filter.getPriority();
+            res.preferredOrder = pkg.getPreferredOrder();
             res.match = match;
-            res.isDefault = info.hasDefault;
-            res.labelRes = info.labelRes;
-            res.nonLocalizedLabel = info.nonLocalizedLabel;
-            res.icon = info.icon;
+            res.isDefault = filter.hasDefault;
+            res.labelRes = filter.labelRes;
+            res.nonLocalizedLabel = filter.nonLocalizedLabel;
+            res.icon = filter.icon;
             res.system = res.serviceInfo.applicationInfo.isSystemApp();
             return res;
         }
@@ -1784,31 +1945,42 @@
 
         @Override
         protected void dumpFilter(PrintWriter out, String prefix,
-                PackageParser.ServiceIntentInfo filter) {
+                ParsedServiceIntentInfo filter) {
+            ParsedService service = null;
+
+            AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName());
+            if (pkg != null && pkg.getServices() != null) {
+                for (ParsedService parsedService : pkg.getServices()) {
+                    if (Objects.equals(parsedService.className, filter.getClassName())) {
+                        service = parsedService;
+                    }
+                }
+            }
+
             out.print(prefix);
-            out.print(Integer.toHexString(System.identityHashCode(filter.service)));
+            out.print(Integer.toHexString(System.identityHashCode(service)));
             out.print(' ');
-            filter.service.printComponentShortName(out);
+            ComponentName.printShortString(out, filter.getPackageName(), filter.getClassName());
             out.print(" filter ");
             out.print(Integer.toHexString(System.identityHashCode(filter)));
-            if (filter.service.info.permission != null) {
-                out.print(" permission "); out.println(filter.service.info.permission);
+            if (service != null && service.getPermission() != null) {
+                out.print(" permission "); out.println(service.getPermission());
             } else {
                 out.println();
             }
         }
 
         @Override
-        protected Object filterToLabel(PackageParser.ServiceIntentInfo filter) {
-            return filter.service;
+        protected Object filterToLabel(ParsedServiceIntentInfo filter) {
+            return filter;
         }
 
         protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {
-            final PackageParser.Service service = (PackageParser.Service) label;
+            final ParsedServiceIntentInfo service = (ParsedServiceIntentInfo) label;
             out.print(prefix);
             out.print(Integer.toHexString(System.identityHashCode(service)));
             out.print(' ');
-            service.printComponentShortName(out);
+            ComponentName.printShortString(out, service.getPackageName(), service.getClassName());
             if (count > 1) {
                 out.print(" ("); out.print(count); out.print(" filters)");
             }
@@ -1816,7 +1988,7 @@
         }
 
         // Keys are String (activity class name), values are Activity.
-        private final ArrayMap<ComponentName, PackageParser.Service> mServices = new ArrayMap<>();
+        private final ArrayMap<ComponentName, ParsedService> mServices = new ArrayMap<>();
         private int mFlags;
     }
 
@@ -1905,7 +2077,7 @@
 
     /** Generic to create an {@link Iterator} for a data type */
     static class IterGenerator<E> {
-        public Iterator<E> generate(ActivityIntentInfo info) {
+        public Iterator<E> generate(ParsedActivityIntentInfo info) {
             return null;
         }
     }
@@ -1913,7 +2085,7 @@
     /** Create an {@link Iterator} for intent actions */
     static class ActionIterGenerator extends IterGenerator<String> {
         @Override
-        public Iterator<String> generate(ActivityIntentInfo info) {
+        public Iterator<String> generate(ParsedActivityIntentInfo info) {
             return info.actionsIterator();
         }
     }
@@ -1921,7 +2093,7 @@
     /** Create an {@link Iterator} for intent categories */
     static class CategoriesIterGenerator extends IterGenerator<String> {
         @Override
-        public Iterator<String> generate(ActivityIntentInfo info) {
+        public Iterator<String> generate(ParsedActivityIntentInfo info) {
             return info.categoriesIterator();
         }
     }
@@ -1929,7 +2101,7 @@
     /** Create an {@link Iterator} for intent schemes */
     static class SchemesIterGenerator extends IterGenerator<String> {
         @Override
-        public Iterator<String> generate(ActivityIntentInfo info) {
+        public Iterator<String> generate(ParsedActivityIntentInfo info) {
             return info.schemesIterator();
         }
     }
@@ -1937,9 +2109,39 @@
     /** Create an {@link Iterator} for intent authorities */
     static class AuthoritiesIterGenerator extends IterGenerator<IntentFilter.AuthorityEntry> {
         @Override
-        public Iterator<IntentFilter.AuthorityEntry> generate(ActivityIntentInfo info) {
+        public Iterator<IntentFilter.AuthorityEntry> generate(ParsedActivityIntentInfo info) {
             return info.authoritiesIterator();
         }
     }
 
+    // TODO(b/135203078): Document or remove this if possible.
+    class EffectiveProvider extends ParsedProvider {
+
+        private String mEffectiveAuthority;
+        private boolean mEffectiveSyncable;
+
+        public EffectiveProvider(ParsedProvider parsedProvider) {
+            this.setFrom(parsedProvider);
+            this.mEffectiveAuthority = parsedProvider.getAuthority();
+            this.mEffectiveSyncable = parsedProvider.isSyncable();
+        }
+
+        public void setEffectiveAuthority(String authority) {
+            this.mEffectiveAuthority = authority;
+        }
+
+        public void setEffectiveSyncable(boolean syncable) {
+            this.mEffectiveSyncable = syncable;
+        }
+
+        @Override
+        public String getAuthority() {
+            return mEffectiveAuthority;
+        }
+
+        @Override
+        public boolean isSyncable() {
+            return mEffectiveSyncable;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/DataLoaderManagerService.java b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
new file mode 100644
index 0000000..0719797
--- /dev/null
+++ b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
@@ -0,0 +1,246 @@
+/*
+ * 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.pm;
+
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IDataLoader;
+import android.content.pm.IDataLoaderManager;
+import android.content.pm.IDataLoaderStatusListener;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.SystemService;
+
+import java.util.List;
+
+/**
+ * Data loader manager service manages data loader binder services.
+ *
+ * @hide
+ */
+public class DataLoaderManagerService extends SystemService {
+    private static final String TAG = "DataLoaderManager";
+    private final Context mContext;
+    private final DataLoaderManagerBinderService mBinderService;
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private SparseArray<DataLoaderServiceConnection> mServiceConnections;
+
+    public DataLoaderManagerService(Context context) {
+        super(context);
+        mContext = context;
+        mBinderService = new DataLoaderManagerBinderService();
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(Context.DATA_LOADER_MANAGER_SERVICE, mBinderService);
+    }
+
+    final class DataLoaderManagerBinderService extends IDataLoaderManager.Stub {
+        @Override
+        public boolean initializeDataLoader(int dataLoaderId, Bundle params,
+                IDataLoaderStatusListener listener) {
+            synchronized (mLock) {
+                if (mServiceConnections == null) {
+                    mServiceConnections = new SparseArray<>();
+                }
+                if (mServiceConnections.get(dataLoaderId) != null) {
+                    Slog.e(TAG, "Data loader of ID=" + dataLoaderId + " already exists.");
+                    return false;
+                }
+            }
+            CharSequence packageNameSeq = params.getCharSequence("packageName");
+            if (packageNameSeq == null) {
+                Slog.e(TAG, "Must specify package name.");
+                return false;
+            }
+            String packageName = packageNameSeq.toString();
+            ComponentName dataLoaderComponent = getDataLoaderServiceName(packageName);
+            if (dataLoaderComponent == null) {
+                return false;
+            }
+            // Binds to the specific data loader service
+            DataLoaderServiceConnection connection =
+                    new DataLoaderServiceConnection(dataLoaderId, params, listener);
+            Intent intent = new Intent();
+            intent.setComponent(dataLoaderComponent);
+            if (!mContext.bindServiceAsUser(intent, connection, Context.BIND_AUTO_CREATE,
+                    UserHandle.of(UserHandle.getCallingUserId()))) {
+                Slog.e(TAG, "Failed to bind to data loader binder service.");
+                mContext.unbindService(connection);
+                return false;
+            }
+            return true;
+        }
+
+        /**
+         * Find the ComponentName of the data loader service provider, given its package name.
+         *
+         * @param packageName the package name of the provider.
+         * @return ComponentName of the data loader service provider. Null if provider not found.
+         */
+        private @Nullable ComponentName getDataLoaderServiceName(String packageName) {
+            final PackageManager pm = mContext.getPackageManager();
+            if (pm == null) {
+                Slog.e(TAG, "PackageManager is not available.");
+                return null;
+            }
+            Intent intent = new Intent(Intent.ACTION_LOAD_DATA);
+            intent.setPackage(packageName);
+            List<ResolveInfo> services =
+                    pm.queryIntentServicesAsUser(intent, 0, UserHandle.getCallingUserId());
+            if (services == null || services.isEmpty()) {
+                Slog.e(TAG,
+                        "Failed to find data loader service provider in package " + packageName);
+                return null;
+            }
+
+            // TODO(b/136132412): better way to enable privileged data loaders in tests
+            boolean checkLoader =
+                    android.os.SystemProperties.getBoolean("incremental.check_loader", false);
+            int numServices = services.size();
+            for (int i = 0; i < numServices; i++) {
+                ResolveInfo ri = services.get(i);
+                ComponentName componentName = new ComponentName(
+                        ri.serviceInfo.packageName, ri.serviceInfo.name);
+                // There should only be one matching provider inside the given package.
+                // If there's more than one, return the first one found.
+                try {
+                    ApplicationInfo ai = pm.getApplicationInfo(componentName.getPackageName(), 0);
+                    if (checkLoader && !ai.isPrivilegedApp()) {
+                        Slog.w(TAG,
+                                "Data loader: " + componentName.getPackageName()
+                                        + " is not a privileged app, skipping.");
+                        continue;
+                    }
+                    return componentName;
+                } catch (PackageManager.NameNotFoundException ex) {
+                    Slog.w(TAG,
+                            "Privileged data loader: " + componentName.getPackageName()
+                                    + " not found, skipping.");
+                }
+
+            }
+            Slog.e(TAG, "Didn't find any matching data loader service provider.");
+            return null;
+        }
+
+        /**
+         * Returns the binder object of a data loader, specified by its ID.
+         */
+        @Override
+        public @Nullable IDataLoader getDataLoader(int dataLoaderId) {
+            synchronized (mLock) {
+                if (mServiceConnections == null) {
+                    return null;
+                }
+                DataLoaderServiceConnection serviceConnection = mServiceConnections.get(
+                        dataLoaderId, null);
+                if (serviceConnection == null) {
+                    return null;
+                }
+                return serviceConnection.getDataLoader();
+            }
+        }
+
+        /**
+         * Destroys a data loader binder service, specified by its ID.
+         */
+        @Override
+        public void destroyDataLoader(int dataLoaderId) {
+            synchronized (mLock) {
+                if (mServiceConnections == null) {
+                    return;
+                }
+                DataLoaderServiceConnection serviceConnection = mServiceConnections.get(
+                        dataLoaderId, null);
+
+                if (serviceConnection == null) {
+                    return;
+                }
+                serviceConnection.destroy();
+            }
+        }
+    }
+
+    class DataLoaderServiceConnection implements ServiceConnection {
+        final int mId;
+        final Bundle mParams;
+        final IDataLoaderStatusListener mListener;
+        IDataLoader mDataLoader;
+
+        DataLoaderServiceConnection(int id, Bundle params, IDataLoaderStatusListener listener) {
+            mId = id;
+            mParams = params;
+            mListener = listener;
+            mDataLoader = null;
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            mDataLoader = IDataLoader.Stub.asInterface(service);
+            synchronized (mLock) {
+                mServiceConnections.append(mId, this);
+            }
+            try {
+                mDataLoader.create(mId, mParams, mListener);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to create data loader service.", e);
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName arg0) {
+            remove();
+        }
+
+        IDataLoader getDataLoader() {
+            return mDataLoader;
+        }
+
+        void destroy() {
+            try {
+                mDataLoader.destroy();
+            } catch (RemoteException ignored) {
+            }
+            mContext.unbindService(this);
+        }
+
+        private void remove() {
+            synchronized (mLock) {
+                mServiceConnections.remove(mId);
+                if (mServiceConnections.size() == 0) {
+                    mServiceConnections = null;
+                }
+            }
+            mParams.clear();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 9e04c4b..ffcd6cf 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -20,9 +20,12 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.InstantAppInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageInfoUtils;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
@@ -137,7 +140,7 @@
     public byte[] getInstantAppCookieLPw(@NonNull String packageName,
             @UserIdInt int userId) {
         // Only installed packages can get their own cookie
-        PackageParser.Package pkg = mService.mPackages.get(packageName);
+        AndroidPackage pkg = mService.mPackages.get(packageName);
         if (pkg == null) {
             return null;
         }
@@ -171,7 +174,7 @@
         }
 
         // Only an installed package can set its own cookie
-        PackageParser.Package pkg = mService.mPackages.get(packageName);
+        AndroidPackage pkg = mService.mPackages.get(packageName);
         if (pkg == null) {
             return false;
         }
@@ -264,15 +267,15 @@
     }
 
     @GuardedBy("mService.mLock")
-    public void onPackageInstalledLPw(@NonNull PackageParser.Package pkg, @NonNull int[] userIds) {
-        PackageSetting ps = (PackageSetting) pkg.mExtras;
+    public void onPackageInstalledLPw(@NonNull AndroidPackage pkg, @NonNull int[] userIds) {
+        PackageSetting ps = mService.getPackageSetting(pkg.getPackageName());
         if (ps == null) {
             return;
         }
 
         for (int userId : userIds) {
             // Ignore not installed apps
-            if (mService.mPackages.get(pkg.packageName) == null || !ps.getInstalled(userId)) {
+            if (mService.mPackages.get(pkg.getPackageName()) == null || !ps.getInstalled(userId)) {
                 continue;
             }
 
@@ -286,16 +289,16 @@
 
             // Remove the in-memory state
             removeUninstalledInstantAppStateLPw((UninstalledInstantAppState state) ->
-                            state.mInstantAppInfo.getPackageName().equals(pkg.packageName),
+                            state.mInstantAppInfo.getPackageName().equals(pkg.getPackageName()),
                     userId);
 
             // Remove the on-disk state except the cookie
-            File instantAppDir = getInstantApplicationDir(pkg.packageName, userId);
+            File instantAppDir = getInstantApplicationDir(pkg.getPackageName(), userId);
             new File(instantAppDir, INSTANT_APP_METADATA_FILE).delete();
             new File(instantAppDir, INSTANT_APP_ICON_FILE).delete();
 
             // If app signature changed - wipe the cookie
-            File currentCookieFile = peekInstantCookieFile(pkg.packageName, userId);
+            File currentCookieFile = peekInstantCookieFile(pkg.getPackageName(), userId);
             if (currentCookieFile == null) {
                 continue;
             }
@@ -310,7 +313,7 @@
             // We prefer the modern computation procedure where all certs are taken
             // into account but also allow the value from the old computation to avoid
             // data loss.
-            if (pkg.mSigningDetails.checkCapability(currentCookieSha256,
+            if (pkg.getSigningDetails().checkCapability(currentCookieSha256,
                     PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)) {
                 return;
             }
@@ -318,7 +321,7 @@
             // For backwards compatibility we accept match based on any signature, since we may have
             // recorded only the first for multiply-signed packages
             final String[] signaturesSha256Digests =
-                    PackageUtils.computeSignaturesSha256Digests(pkg.mSigningDetails.signatures);
+                    PackageUtils.computeSignaturesSha256Digests(pkg.getSigningDetails().signatures);
             for (String s : signaturesSha256Digests) {
                 if (s.equals(currentCookieSha256)) {
                     return;
@@ -326,7 +329,7 @@
             }
 
             // Sorry, you are out of luck - different signatures - nuke data
-            Slog.i(LOG_TAG, "Signature for package " + pkg.packageName
+            Slog.i(LOG_TAG, "Signature for package " + pkg.getPackageName()
                     + " changed - dropping cookie");
                 // Make sure a pending write for the old signed app is cancelled
             mCookiePersistence.cancelPendingPersistLPw(pkg, userId);
@@ -335,15 +338,15 @@
     }
 
     @GuardedBy("mService.mLock")
-    public void onPackageUninstalledLPw(@NonNull PackageParser.Package pkg,
+    public void onPackageUninstalledLPw(@NonNull AndroidPackage pkg,
             @NonNull int[] userIds) {
-        PackageSetting ps = (PackageSetting) pkg.mExtras;
+        PackageSetting ps = mService.getPackageSetting(pkg.getPackageName());
         if (ps == null) {
             return;
         }
 
         for (int userId : userIds) {
-            if (mService.mPackages.get(pkg.packageName) != null && ps.getInstalled(userId)) {
+            if (mService.mPackages.get(pkg.getPackageName()) != null && ps.getInstalled(userId)) {
                 continue;
             }
 
@@ -353,7 +356,7 @@
                 removeInstantAppLPw(userId, ps.appId);
             } else {
                 // Deleting an app prunes all instant state such as cookie
-                deleteDir(getInstantApplicationDir(pkg.packageName, userId));
+                deleteDir(getInstantApplicationDir(pkg.getPackageName(), userId));
                 mCookiePersistence.cancelPendingPersistLPw(pkg, userId);
                 removeAppLPw(userId, ps.appId);
             }
@@ -487,7 +490,7 @@
     }
 
     @GuardedBy("mService.mLock")
-    private void addUninstalledInstantAppLPw(@NonNull PackageParser.Package pkg,
+    private void addUninstalledInstantAppLPw(@NonNull AndroidPackage pkg,
             @UserIdInt int userId) {
         InstantAppInfo uninstalledApp = createInstantAppInfoForPackage(
                 pkg, userId, false);
@@ -511,14 +514,15 @@
         writeInstantApplicationIconLPw(pkg, userId);
     }
 
-    private void writeInstantApplicationIconLPw(@NonNull PackageParser.Package pkg,
+    private void writeInstantApplicationIconLPw(@NonNull AndroidPackage pkg,
             @UserIdInt int userId) {
-        File appDir = getInstantApplicationDir(pkg.packageName, userId);
+        File appDir = getInstantApplicationDir(pkg.getPackageName(), userId);
         if (!appDir.exists()) {
             return;
         }
 
-        Drawable icon = pkg.applicationInfo.loadIcon(mService.mContext.getPackageManager());
+        // TODO(b/135203078): Remove toAppInfo call? Requires significant additions/changes to PM
+        Drawable icon = pkg.toAppInfoWithoutState().loadIcon(mService.mContext.getPackageManager());
 
         final Bitmap bitmap;
         if (icon instanceof BitmapDrawable) {
@@ -531,7 +535,7 @@
             icon.draw(canvas);
         }
 
-        File iconFile = new File(getInstantApplicationDir(pkg.packageName, userId),
+        File iconFile = new File(getInstantApplicationDir(pkg.getPackageName(), userId),
                 INSTANT_APP_ICON_FILE);
 
         try (FileOutputStream out = new FileOutputStream(iconFile)) {
@@ -690,14 +694,16 @@
 
             final int packageCount = mService.mPackages.size();
             for (int i = 0; i < packageCount; i++) {
-                final PackageParser.Package pkg = mService.mPackages.valueAt(i);
+                final AndroidPackage pkg = mService.mPackages.valueAt(i);
                 if (now - pkg.getLatestPackageUseTimeInMills() < maxInstalledCacheDuration) {
                     continue;
                 }
-                if (!(pkg.mExtras instanceof PackageSetting)) {
+
+                final PackageSetting ps = mService.getPackageSetting(pkg.getPackageName());
+                if (ps == null) {
                     continue;
                 }
-                final PackageSetting  ps = (PackageSetting) pkg.mExtras;
+
                 boolean installedOnlyAsInstantApp = false;
                 for (int userId : allUsers) {
                     if (ps.getInstalled(userId)) {
@@ -713,14 +719,14 @@
                     if (packagesToDelete == null) {
                         packagesToDelete = new ArrayList<>();
                     }
-                    packagesToDelete.add(pkg.packageName);
+                    packagesToDelete.add(pkg.getPackageName());
                 }
             }
 
             if (packagesToDelete != null) {
                 packagesToDelete.sort((String lhs, String rhs) -> {
-                    final PackageParser.Package lhsPkg = mService.mPackages.get(lhs);
-                    final PackageParser.Package rhsPkg = mService.mPackages.get(rhs);
+                    final AndroidPackage lhsPkg = mService.mPackages.get(lhs);
+                    final AndroidPackage rhsPkg = mService.mPackages.get(rhs);
                     if (lhsPkg == null && rhsPkg == null) {
                         return 0;
                     } else if (lhsPkg == null) {
@@ -735,18 +741,23 @@
                                 rhsPkg.getLatestPackageUseTimeInMills()) {
                             return -1;
                         } else {
-                            if (lhsPkg.mExtras instanceof PackageSetting
-                                    && rhsPkg.mExtras instanceof PackageSetting) {
-                                final PackageSetting lhsPs = (PackageSetting) lhsPkg.mExtras;
-                                final PackageSetting rhsPs = (PackageSetting) rhsPkg.mExtras;
-                                if (lhsPs.firstInstallTime > rhsPs.firstInstallTime) {
-                                    return 1;
-                                } else {
-                                    return -1;
-                                }
-                            } else {
+                            final PackageSetting lhsPs = mService.getPackageSetting(
+                                    lhsPkg.getPackageName());
+                            if (lhsPs == null) {
                                 return 0;
                             }
+
+                            final PackageSetting rhsPs = mService.getPackageSetting(
+                                    rhsPkg.getPackageName());
+                            if (rhsPs == null) {
+                                return 0;
+                            }
+
+                            if (lhsPs.firstInstallTime > rhsPs.firstInstallTime) {
+                                return 1;
+                            } else {
+                                return -1;
+                            }
                         }
                     }
                 });
@@ -818,8 +829,8 @@
 
         final int packageCount = mService.mPackages.size();
         for (int i = 0; i < packageCount; i++) {
-            final PackageParser.Package pkg = mService.mPackages.valueAt(i);
-            final PackageSetting ps = (PackageSetting) pkg.mExtras;
+            final AndroidPackage pkg = mService.mPackages.valueAt(i);
+            final PackageSetting ps = mService.getPackageSetting(pkg.getPackageName());
             if (ps == null || !ps.getInstantApp(userId)) {
                 continue;
             }
@@ -839,9 +850,9 @@
 
     private @NonNull
     InstantAppInfo createInstantAppInfoForPackage(
-            @NonNull PackageParser.Package pkg, @UserIdInt int userId,
+            @NonNull AndroidPackage pkg, @UserIdInt int userId,
             boolean addApplicationInfo) {
-        PackageSetting ps = (PackageSetting) pkg.mExtras;
+        PackageSetting ps = mService.getPackageSetting(pkg.getPackageName());
         if (ps == null) {
             return null;
         }
@@ -849,19 +860,23 @@
             return null;
         }
 
-        String[] requestedPermissions = new String[pkg.requestedPermissions.size()];
-        pkg.requestedPermissions.toArray(requestedPermissions);
+        String[] requestedPermissions = new String[pkg.getRequestedPermissions().size()];
+        pkg.getRequestedPermissions().toArray(requestedPermissions);
 
         Set<String> permissions = ps.getPermissionsState().getPermissions(userId);
         String[] grantedPermissions = new String[permissions.size()];
         permissions.toArray(grantedPermissions);
 
+        // TODO(b/135203078): This may be broken due to inner mutability problems that were broken
+        //  as part of moving to PackageInfoUtils. Flags couldn't be determined.
+        ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo(ps.pkg, 0,
+                ps.readUserState(userId), userId);
         if (addApplicationInfo) {
-            return new InstantAppInfo(pkg.applicationInfo,
+            return new InstantAppInfo(appInfo,
                     requestedPermissions, grantedPermissions);
         } else {
-            return new InstantAppInfo(pkg.applicationInfo.packageName,
-                    pkg.applicationInfo.loadLabel(mService.mContext.getPackageManager()),
+            return new InstantAppInfo(appInfo.packageName,
+                    appInfo.loadLabel(mService.mContext.getPackageManager()),
                     requestedPermissions, grantedPermissions);
         }
     }
@@ -887,10 +902,10 @@
         return uninstalledApps;
     }
 
-    private void propagateInstantAppPermissionsIfNeeded(@NonNull PackageParser.Package pkg,
+    private void propagateInstantAppPermissionsIfNeeded(@NonNull AndroidPackage pkg,
             @UserIdInt int userId) {
         InstantAppInfo appInfo = peekOrParseUninstalledInstantAppInfo(
-                pkg.packageName, userId);
+                pkg.getPackageName(), userId);
         if (appInfo == null) {
             return;
         }
@@ -902,8 +917,10 @@
             for (String grantedPermission : appInfo.getGrantedPermissions()) {
                 final boolean propagatePermission =
                         mService.mSettings.canPropagatePermissionToInstantApp(grantedPermission);
-                if (propagatePermission && pkg.requestedPermissions.contains(grantedPermission)) {
-                    mService.grantRuntimePermission(pkg.packageName, grantedPermission, userId);
+                if (propagatePermission && pkg.getRequestedPermissions().contains(
+                        grantedPermission)) {
+                    mService.grantRuntimePermission(pkg.getPackageName(), grantedPermission,
+                            userId);
                 }
             }
         } finally {
@@ -1188,18 +1205,19 @@
             super(looper);
         }
 
-        public void schedulePersistLPw(@UserIdInt int userId, @NonNull PackageParser.Package pkg,
+        public void schedulePersistLPw(@UserIdInt int userId, @NonNull AndroidPackage pkg,
                 @NonNull byte[] cookie) {
             // Before we used only the first signature to compute the SHA 256 but some
             // apps could be singed by multiple certs and the cert order is undefined.
             // We prefer the modern computation procedure where all certs are taken
             // into account and delete the file derived via the legacy hash computation.
-            File newCookieFile = computeInstantCookieFile(pkg.packageName,
-                    PackageUtils.computeSignaturesSha256Digest(pkg.mSigningDetails.signatures), userId);
-            if (!pkg.mSigningDetails.hasSignatures()) {
+            File newCookieFile = computeInstantCookieFile(pkg.getPackageName(),
+                    PackageUtils.computeSignaturesSha256Digest(pkg.getSigningDetails().signatures),
+                    userId);
+            if (!pkg.getSigningDetails().hasSignatures()) {
                 Slog.wtf(LOG_TAG, "Parsed Instant App contains no valid signatures!");
             }
-            File oldCookieFile = peekInstantCookieFile(pkg.packageName, userId);
+            File oldCookieFile = peekInstantCookieFile(pkg.getPackageName(), userId);
             if (oldCookieFile != null && !newCookieFile.equals(oldCookieFile)) {
                 oldCookieFile.delete();
             }
@@ -1209,12 +1227,12 @@
                     PERSIST_COOKIE_DELAY_MILLIS);
         }
 
-        public @Nullable byte[] getPendingPersistCookieLPr(@NonNull PackageParser.Package pkg,
+        public @Nullable byte[] getPendingPersistCookieLPr(@NonNull AndroidPackage pkg,
                 @UserIdInt int userId) {
             ArrayMap<String, SomeArgs> pendingWorkForUser =
                     mPendingPersistCookies.get(userId);
             if (pendingWorkForUser != null) {
-                SomeArgs state = pendingWorkForUser.get(pkg.packageName);
+                SomeArgs state = pendingWorkForUser.get(pkg.getPackageName());
                 if (state != null) {
                     return (byte[]) state.arg1;
                 }
@@ -1222,7 +1240,7 @@
             return null;
         }
 
-        public void cancelPendingPersistLPw(@NonNull PackageParser.Package pkg,
+        public void cancelPendingPersistLPw(@NonNull AndroidPackage pkg,
                 @UserIdInt int userId) {
             removeMessages(userId, pkg);
             SomeArgs state = removePendingPersistCookieLPr(pkg, userId);
@@ -1232,7 +1250,7 @@
         }
 
         private void addPendingPersistCookieLPw(@UserIdInt int userId,
-                @NonNull PackageParser.Package pkg, @NonNull byte[] cookie,
+                @NonNull AndroidPackage pkg, @NonNull byte[] cookie,
                 @NonNull File cookieFile) {
             ArrayMap<String, SomeArgs> pendingWorkForUser =
                     mPendingPersistCookies.get(userId);
@@ -1243,16 +1261,16 @@
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = cookie;
             args.arg2 = cookieFile;
-            pendingWorkForUser.put(pkg.packageName, args);
+            pendingWorkForUser.put(pkg.getPackageName(), args);
         }
 
-        private SomeArgs removePendingPersistCookieLPr(@NonNull PackageParser.Package pkg,
+        private SomeArgs removePendingPersistCookieLPr(@NonNull AndroidPackage pkg,
                 @UserIdInt int userId) {
             ArrayMap<String, SomeArgs> pendingWorkForUser =
                     mPendingPersistCookies.get(userId);
             SomeArgs state = null;
             if (pendingWorkForUser != null) {
-                state = pendingWorkForUser.remove(pkg.packageName);
+                state = pendingWorkForUser.remove(pkg.getPackageName());
                 if (pendingWorkForUser.isEmpty()) {
                     mPendingPersistCookies.remove(userId);
                 }
@@ -1263,7 +1281,7 @@
         @Override
         public void handleMessage(Message message) {
             int userId = message.what;
-            PackageParser.Package pkg = (PackageParser.Package) message.obj;
+            AndroidPackage pkg = (AndroidPackage) message.obj;
             SomeArgs state = removePendingPersistCookieLPr(pkg, userId);
             if (state == null) {
                 return;
@@ -1271,7 +1289,7 @@
             byte[] cookie = (byte[]) state.arg1;
             File cookieFile = (File) state.arg2;
             state.recycle();
-            persistInstantApplicationCookie(cookie, pkg.packageName, cookieFile, userId);
+            persistInstantApplicationCookie(cookie, pkg.getPackageName(), cookieFile, userId);
         }
     }
 }
diff --git a/services/core/java/com/android/server/pm/InstructionSets.java b/services/core/java/com/android/server/pm/InstructionSets.java
index ec48713..0a065eb 100644
--- a/services/core/java/com/android/server/pm/InstructionSets.java
+++ b/services/core/java/com/android/server/pm/InstructionSets.java
@@ -16,7 +16,7 @@
 
 package com.android.server.pm;
 
-import android.content.pm.ApplicationInfo;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.Build;
 import android.os.SystemProperties;
 import android.text.TextUtils;
@@ -35,30 +35,16 @@
 public class InstructionSets {
     private static final String PREFERRED_INSTRUCTION_SET =
             VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);
-    public static String[] getAppDexInstructionSets(ApplicationInfo info) {
-        if (info.primaryCpuAbi != null) {
-            if (info.secondaryCpuAbi != null) {
+
+    public static String[] getAppDexInstructionSets(String primaryCpuAbi, String secondaryCpuAbi) {
+        if (primaryCpuAbi != null) {
+            if (secondaryCpuAbi != null) {
                 return new String[] {
-                        VMRuntime.getInstructionSet(info.primaryCpuAbi),
-                        VMRuntime.getInstructionSet(info.secondaryCpuAbi) };
+                        VMRuntime.getInstructionSet(primaryCpuAbi),
+                        VMRuntime.getInstructionSet(secondaryCpuAbi) };
             } else {
                 return new String[] {
-                        VMRuntime.getInstructionSet(info.primaryCpuAbi) };
-            }
-        }
-
-        return new String[] { getPreferredInstructionSet() };
-    }
-
-    public static String[] getAppDexInstructionSets(PackageSetting ps) {
-        if (ps.primaryCpuAbiString != null) {
-            if (ps.secondaryCpuAbiString != null) {
-                return new String[] {
-                        VMRuntime.getInstructionSet(ps.primaryCpuAbiString),
-                        VMRuntime.getInstructionSet(ps.secondaryCpuAbiString) };
-            } else {
-                return new String[] {
-                        VMRuntime.getInstructionSet(ps.primaryCpuAbiString) };
+                        VMRuntime.getInstructionSet(primaryCpuAbi) };
             }
         }
 
@@ -124,4 +110,12 @@
         return VMRuntime.getInstructionSet(abis.primary);
     }
 
+    public static String getPrimaryInstructionSet(AndroidPackage pkg) {
+        if (pkg.getPrimaryCpuAbi() == null) {
+            return getPreferredInstructionSet();
+        }
+
+        return VMRuntime.getInstructionSet(pkg.getPrimaryCpuAbi());
+    }
+
 }
diff --git a/services/core/java/com/android/server/pm/IntentFilterVerificationState.java b/services/core/java/com/android/server/pm/IntentFilterVerificationState.java
index a4e9d10..c97d85d 100644
--- a/services/core/java/com/android/server/pm/IntentFilterVerificationState.java
+++ b/services/core/java/com/android/server/pm/IntentFilterVerificationState.java
@@ -17,7 +17,7 @@
 package com.android.server.pm;
 
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.ComponentParseUtils;
 import android.util.ArraySet;
 import android.util.Slog;
 
@@ -35,7 +35,7 @@
 
     private int mState;
 
-    private ArrayList<PackageParser.ActivityIntentInfo> mFilters = new ArrayList<>();
+    private ArrayList<ComponentParseUtils.ParsedActivityIntentInfo> mFilters = new ArrayList<>();
     private ArraySet<String> mHosts = new ArraySet<>();
     private int mUserId;
 
@@ -66,7 +66,7 @@
         setState(STATE_VERIFICATION_PENDING);
     }
 
-    public ArrayList<PackageParser.ActivityIntentInfo> getFilters() {
+    public ArrayList<ComponentParseUtils.ParsedActivityIntentInfo> getFilters() {
         return mFilters;
     }
 
@@ -123,7 +123,7 @@
         return false;
     }
 
-    public void addFilter(PackageParser.ActivityIntentInfo filter) {
+    public void addFilter(ComponentParseUtils.ParsedActivityIntentInfo filter) {
         mFilters.add(filter);
         mHosts.addAll(filter.getHostsList());
     }
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 93d3b77..70c0f8d 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -20,23 +20,26 @@
 
 import static com.android.server.pm.PackageManagerService.SCAN_INITIAL;
 
-import com.android.internal.util.Preconditions;
 import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Base64;
-import android.util.Slog;
 import android.util.LongSparseArray;
+import android.util.Slog;
 
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.security.PublicKey;
-import java.util.Set;
+import com.android.internal.util.Preconditions;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.security.PublicKey;
+import java.util.Map;
+import java.util.Set;
+
 /*
  * Manages system-wide KeySet state.
  */
@@ -182,33 +185,31 @@
      *
      * Returns true if the package can safely be added to the keyset metadata.
      */
-    public void assertScannedPackageValid(PackageParser.Package pkg)
+    public void assertScannedPackageValid(AndroidPackage pkg)
             throws PackageManagerException {
-        if (pkg == null || pkg.packageName == null) {
+        if (pkg == null || pkg.getPackageName() == null) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                     "Passed invalid package to keyset validation.");
         }
-        ArraySet<PublicKey> signingKeys = pkg.mSigningDetails.publicKeys;
+        ArraySet<PublicKey> signingKeys = pkg.getSigningDetails().publicKeys;
         if (signingKeys == null || !(signingKeys.size() > 0) || signingKeys.contains(null)) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                     "Package has invalid signing-key-set.");
         }
-        ArrayMap<String, ArraySet<PublicKey>> definedMapping = pkg.mKeySetMapping;
+        Map<String, ArraySet<PublicKey>> definedMapping = pkg.getKeySetMapping();
         if (definedMapping != null) {
             if (definedMapping.containsKey(null) || definedMapping.containsValue(null)) {
                 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                         "Package has null defined key set.");
             }
-            int defMapSize = definedMapping.size();
-            for (int i = 0; i < defMapSize; i++) {
-                if (!(definedMapping.valueAt(i).size() > 0)
-                        || definedMapping.valueAt(i).contains(null)) {
+            for (ArraySet<PublicKey> value : definedMapping.values()) {
+                if (!(value.size() > 0) || value.contains(null)) {
                     throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                             "Package has null/no public keys for defined key-sets.");
                 }
             }
         }
-        ArraySet<String> upgradeAliases = pkg.mUpgradeKeySets;
+        Set<String> upgradeAliases = pkg.getUpgradeKeySets();
         if (upgradeAliases != null) {
             if (definedMapping == null || !(definedMapping.keySet().containsAll(upgradeAliases))) {
                 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
@@ -217,17 +218,17 @@
         }
     }
 
-    public void addScannedPackageLPw(PackageParser.Package pkg) {
+    public void addScannedPackageLPw(AndroidPackage pkg) {
         Preconditions.checkNotNull(pkg, "Attempted to add null pkg to ksms.");
-        Preconditions.checkNotNull(pkg.packageName, "Attempted to add null pkg to ksms.");
-        PackageSetting ps = mPackages.get(pkg.packageName);
-        Preconditions.checkNotNull(ps, "pkg: " + pkg.packageName
+        Preconditions.checkNotNull(pkg.getPackageName(), "Attempted to add null pkg to ksms.");
+        PackageSetting ps = mPackages.get(pkg.getPackageName());
+        Preconditions.checkNotNull(ps, "pkg: " + pkg.getPackageName()
                     + "does not have a corresponding entry in mPackages.");
-        addSigningKeySetToPackageLPw(ps, pkg.mSigningDetails.publicKeys);
-        if (pkg.mKeySetMapping != null) {
-            addDefinedKeySetsToPackageLPw(ps, pkg.mKeySetMapping);
-            if (pkg.mUpgradeKeySets != null) {
-                addUpgradeKeySetsToPackageLPw(ps, pkg.mUpgradeKeySets);
+        addSigningKeySetToPackageLPw(ps, pkg.getSigningDetails().publicKeys);
+        if (pkg.getKeySetMapping() != null) {
+            addDefinedKeySetsToPackageLPw(ps, pkg.getKeySetMapping());
+            if (pkg.getUpgradeKeySets() != null) {
+                addUpgradeKeySetsToPackageLPw(ps, pkg.getUpgradeKeySets());
             }
         }
     }
@@ -280,15 +281,14 @@
      * Remove any KeySets the package no longer defines.
      */
     void addDefinedKeySetsToPackageLPw(PackageSetting pkg,
-            ArrayMap<String, ArraySet<PublicKey>> definedMapping) {
+            Map<String, ArraySet<PublicKey>> definedMapping) {
         ArrayMap<String, Long> prevDefinedKeySets = pkg.keySetData.getAliases();
 
         /* add all of the newly defined KeySets */
-        ArrayMap<String, Long> newKeySetAliases = new ArrayMap<String, Long>();
-        final int defMapSize = definedMapping.size();
-        for (int i = 0; i < defMapSize; i++) {
-            String alias = definedMapping.keyAt(i);
-            ArraySet<PublicKey> pubKeys = definedMapping.valueAt(i);
+        Map<String, Long> newKeySetAliases = new ArrayMap<>();
+        for (Map.Entry<String, ArraySet<PublicKey>> entry : definedMapping.entrySet()) {
+            String alias = entry.getKey();
+            ArraySet<PublicKey> pubKeys = entry.getValue();
             if (alias != null && pubKeys != null && pubKeys.size() > 0) {
                 KeySetHandle ks = addKeySetLPw(pubKeys);
                 newKeySetAliases.put(alias, ks.getId());
@@ -313,12 +313,10 @@
      * after all of the defined KeySets have been added.
      */
     void addUpgradeKeySetsToPackageLPw(PackageSetting pkg,
-            ArraySet<String> upgradeAliases) {
-        final int uaSize = upgradeAliases.size();
-        for (int i = 0; i < uaSize; i++) {
-            pkg.keySetData.addUpgradeKeySet(upgradeAliases.valueAt(i));
+            Set<String> upgradeAliases) {
+        for (String upgradeAlias : upgradeAliases) {
+            pkg.keySetData.addUpgradeKeySet(upgradeAlias);
         }
-        return;
     }
 
     /**
@@ -364,14 +362,14 @@
         return true;
     }
 
-    public boolean checkUpgradeKeySetLocked(PackageSettingBase oldPS,
-            PackageParser.Package newPkg) {
+    public boolean checkUpgradeKeySetLocked(PackageSettingBase oldPS, AndroidPackage pkg) {
         // Upgrade keysets are being used.  Determine if new package has a superset of the
         // required keys.
         long[] upgradeKeySets = oldPS.keySetData.getUpgradeKeySets();
         for (int i = 0; i < upgradeKeySets.length; i++) {
             Set<PublicKey> upgradeSet = getPublicKeysFromKeySetLPr(upgradeKeySets[i]);
-            if (upgradeSet != null && newPkg.mSigningDetails.publicKeys.containsAll(upgradeSet)) {
+            if (upgradeSet != null
+                    && pkg.getSigningDetails().publicKeys.containsAll(upgradeSet)) {
                 return true;
             }
         }
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index f7fd1b2..673e265 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -40,13 +40,13 @@
 import android.content.pm.PackageInstaller.SessionInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ShortcutInfo;
 import android.content.pm.ShortcutServiceInternal;
 import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener;
 import android.content.pm.UserInfo;
+import android.content.pm.parsing.AndroidPackage;
 import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Binder;
@@ -447,7 +447,7 @@
             }
             final PackageManagerInternal pmInt =
                     LocalServices.getService(PackageManagerInternal.class);
-            final PackageParser.Package pkg = pmInt.getPackage(appInfo.packageName);
+            final AndroidPackage pkg = pmInt.getPackage(appInfo.packageName);
             if (pkg == null) {
                 // Should not happen, but we shouldn't be failing if it does
                 return false;
@@ -458,8 +458,8 @@
                     appInfo.packageName);
         }
 
-        private boolean requestsPermissions(@NonNull PackageParser.Package pkg) {
-            return !ArrayUtils.isEmpty(pkg.requestedPermissions);
+        private boolean requestsPermissions(@NonNull AndroidPackage pkg) {
+            return !ArrayUtils.isEmpty(pkg.getRequestedPermissions());
         }
 
         private boolean hasDefaultEnableLauncherActivity(@NonNull String packageName) {
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index d49ecdd..ae7a4a7 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -22,7 +22,7 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.pm.IOtaDexopt;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.Environment;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
@@ -118,8 +118,8 @@
         if (mDexoptCommands != null) {
             throw new IllegalStateException("already called prepare()");
         }
-        final List<PackageParser.Package> important;
-        final List<PackageParser.Package> others;
+        final List<AndroidPackage> important;
+        final List<AndroidPackage> others;
         synchronized (mPackageManagerService.mLock) {
             // Important: the packages we need to run with ab-ota compiler-reason.
             important = PackageManagerServiceUtils.getPackagesForDexopt(
@@ -133,12 +133,12 @@
             mDexoptCommands = new ArrayList<>(3 * mPackageManagerService.mPackages.size() / 2);
         }
 
-        for (PackageParser.Package p : important) {
+        for (AndroidPackage p : important) {
             mDexoptCommands.addAll(generatePackageDexopts(p, PackageManagerService.REASON_AB_OTA));
         }
-        for (PackageParser.Package p : others) {
+        for (AndroidPackage p : others) {
             // We assume here that there are no core apps left.
-            if (p.coreApp) {
+            if (p.isCoreApp()) {
                 throw new IllegalStateException("Found a core app that's not important");
             }
             mDexoptCommands.addAll(
@@ -150,8 +150,8 @@
         if (spaceAvailable < BULK_DELETE_THRESHOLD) {
             Log.i(TAG, "Low on space, deleting oat files in an attempt to free up space: "
                     + PackageManagerServiceUtils.packagesToString(others));
-            for (PackageParser.Package pkg : others) {
-                mPackageManagerService.deleteOatArtifactsOfPackage(pkg.packageName);
+            for (AndroidPackage pkg : others) {
+                mPackageManagerService.deleteOatArtifactsOfPackage(pkg.getPackageName());
             }
         }
         long spaceAvailableNow = getAvailableSpace();
@@ -161,15 +161,15 @@
         if (DEBUG_DEXOPT) {
             try {
                 // Output some data about the packages.
-                PackageParser.Package lastUsed = Collections.max(important,
+                AndroidPackage lastUsed = Collections.max(important,
                         (pkg1, pkg2) -> Long.compare(
                                 pkg1.getLatestForegroundPackageUseTimeInMills(),
                                 pkg2.getLatestForegroundPackageUseTimeInMills()));
                 Log.d(TAG, "A/B OTA: lastUsed time = "
                         + lastUsed.getLatestForegroundPackageUseTimeInMills());
                 Log.d(TAG, "A/B OTA: deprioritized packages:");
-                for (PackageParser.Package pkg : others) {
-                    Log.d(TAG, "  " + pkg.packageName + " - "
+                for (AndroidPackage pkg : others) {
+                    Log.d(TAG, "  " + pkg.getPackageName() + " - "
                             + pkg.getLatestForegroundPackageUseTimeInMills());
                 }
             } catch (Exception ignored) {
@@ -262,7 +262,7 @@
     /**
      * Generate all dexopt commands for the given package.
      */
-    private synchronized List<String> generatePackageDexopts(PackageParser.Package pkg,
+    private synchronized List<String> generatePackageDexopts(AndroidPackage pkg,
             int compilationReason) {
         // Intercept and collect dexopt requests
         final List<String> commands = new ArrayList<String>();
@@ -336,8 +336,9 @@
         optimizer.performDexOpt(pkg,
                 null /* ISAs */,
                 null /* CompilerStats.PackageStats */,
-                mPackageManagerService.getDexManager().getPackageUseInfoOrDefault(pkg.packageName),
-                new DexoptOptions(pkg.packageName, compilationReason,
+                mPackageManagerService.getDexManager().getPackageUseInfoOrDefault(
+                        pkg.getPackageName()),
+                new DexoptOptions(pkg.getPackageName(), compilationReason,
                         DexoptOptions.DEXOPT_BOOT_COMPLETE));
 
         return commands;
@@ -359,10 +360,10 @@
         }
 
         // Look into all packages.
-        Collection<PackageParser.Package> pkgs = mPackageManagerService.getPackages();
+        Collection<AndroidPackage> pkgs = mPackageManagerService.getPackages();
         int packagePaths = 0;
         int pathsSuccessful = 0;
-        for (PackageParser.Package pkg : pkgs) {
+        for (AndroidPackage pkg : pkgs) {
             if (pkg == null) {
                 continue;
             }
@@ -371,27 +372,28 @@
             if (!PackageDexOptimizer.canOptimizePackage(pkg)) {
                 continue;
             }
-            if (pkg.codePath == null) {
+            if (pkg.getCodePath() == null) {
                 Slog.w(TAG, "Package " + pkg + " can be optimized but has null codePath");
                 continue;
             }
 
             // If the path is in /system, /vendor, /product or /system_ext, ignore. It will
             // have been ota-dexopted into /data/ota and moved into the dalvik-cache already.
-            if (pkg.codePath.startsWith("/system")
-                    || pkg.codePath.startsWith("/vendor")
-                    || pkg.codePath.startsWith("/product")
-                    || pkg.codePath.startsWith("/system_ext")) {
+            if (pkg.getCodePath().startsWith("/system")
+                    || pkg.getCodePath().startsWith("/vendor")
+                    || pkg.getCodePath().startsWith("/product")
+                    || pkg.getCodePath().startsWith("/system_ext")) {
                 continue;
             }
 
-            final String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo);
+            final String[] instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(),
+                    pkg.getSecondaryCpuAbi());
             final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
             final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
             for (String dexCodeInstructionSet : dexCodeInstructionSets) {
                 for (String path : paths) {
-                    String oatDir = PackageDexOptimizer.getOatDir(new File(pkg.codePath)).
-                            getAbsolutePath();
+                    String oatDir = PackageDexOptimizer.getOatDir(
+                            new File(pkg.getCodePath())).getAbsolutePath();
 
                     // TODO: Check first whether there is an artifact, to save the roundtrip time.
 
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelper.java b/services/core/java/com/android/server/pm/PackageAbiHelper.java
index c21d0cf..d7c161c 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelper.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelper.java
@@ -17,7 +17,8 @@
 package com.android.server.pm;
 
 import android.annotation.Nullable;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ParsedPackage;
 import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -25,21 +26,21 @@
 import java.io.File;
 import java.util.Set;
 
+// TODO: Move to .parsing sub-package
 @VisibleForTesting
 public interface PackageAbiHelper {
     /**
      * Derive and get the location of native libraries for the given package,
      * which varies depending on where and how the package was installed.
      */
-    NativeLibraryPaths getNativeLibraryPaths(
-            PackageParser.Package pkg, File appLib32InstallDir);
+    NativeLibraryPaths getNativeLibraryPaths(AndroidPackage pkg, File appLib32InstallDir);
 
     /**
      * Calculate the abis for a bundled app. These can uniquely be determined from the contents of
      * the system partition, i.e whether it contains 64 or 32 bit shared libraries etc. We do not
      * validate any of this information, and instead assume that the system was built sensibly.
      */
-    Abis getBundledAppAbis(PackageParser.Package pkg);
+    Abis getBundledAppAbis(AndroidPackage pkg);
 
     /**
      * Derive the ABI of a non-system package located at {@code pkg}. This information
@@ -48,7 +49,7 @@
      * If {@code extractLibs} is true, native libraries are extracted from the app if required.
      */
     Pair<Abis, NativeLibraryPaths> derivePackageAbi(
-            PackageParser.Package pkg, String cpuAbiOverride, boolean extractLibs)
+            AndroidPackage pkg, String cpuAbiOverride, boolean extractLibs)
             throws PackageManagerException;
 
     /**
@@ -69,11 +70,11 @@
      */
     @Nullable
     String getAdjustedAbiForSharedUser(
-            Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage);
+            Set<PackageSetting> packagesForUser, AndroidPackage scannedPackage);
 
     /**
      * The native library paths and related properties that should be set on a
-     * {@link android.content.pm.PackageParser.Package}.
+     * {@link ParsedPackage}.
      */
     final class NativeLibraryPaths {
         public final String nativeLibraryRootDir;
@@ -91,11 +92,11 @@
             this.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
         }
 
-        public void applyTo(PackageParser.Package pkg) {
-            pkg.applicationInfo.nativeLibraryRootDir = nativeLibraryRootDir;
-            pkg.applicationInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
-            pkg.applicationInfo.nativeLibraryDir = nativeLibraryDir;
-            pkg.applicationInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
+        public void applyTo(ParsedPackage pkg) {
+            pkg.setNativeLibraryRootDir(nativeLibraryRootDir)
+                    .setNativeLibraryRootRequiresIsa(nativeLibraryRootRequiresIsa)
+                    .setNativeLibraryDir(nativeLibraryDir)
+                    .setSecondaryNativeLibraryDir(secondaryNativeLibraryDir);
         }
     }
 
@@ -112,13 +113,13 @@
             this.secondary = secondary;
         }
 
-        Abis(PackageParser.Package pkg) {
-            this(pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi);
+        Abis(AndroidPackage pkg) {
+            this(pkg.getPrimaryCpuAbi(), pkg.getSecondaryCpuAbi());
         }
 
-        public void applyTo(PackageParser.Package pkg) {
-            pkg.applicationInfo.primaryCpuAbi = primary;
-            pkg.applicationInfo.secondaryCpuAbi = secondary;
+        public void applyTo(ParsedPackage pkg) {
+            pkg.setPrimaryCpuAbi(primary)
+                    .setSecondaryCpuAbi(secondary);
         }
         public void applyTo(PackageSetting pkgSetting) {
             // pkgSetting might be null during rescan following uninstall of updates
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index 259200b..e550bae 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -19,6 +19,7 @@
 import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
 import static android.content.pm.PackageParser.isApkFile;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import static android.os.incremental.IncrementalManager.isIncrementalPath;
 
 import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
 import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
@@ -28,7 +29,7 @@
 import android.annotation.Nullable;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.Build;
 import android.os.Environment;
 import android.os.FileUtils;
@@ -131,10 +132,10 @@
 
     @Override
     public NativeLibraryPaths getNativeLibraryPaths(
-            PackageParser.Package pkg, File appLib32InstallDir) {
-        return getNativeLibraryPaths(new Abis(pkg), appLib32InstallDir, pkg.codePath,
-                pkg.applicationInfo.sourceDir, pkg.applicationInfo.isSystemApp(),
-                pkg.applicationInfo.isUpdatedSystemApp());
+            AndroidPackage pkg, File appLib32InstallDir) {
+        return getNativeLibraryPaths(new Abis(pkg), appLib32InstallDir, pkg.getCodePath(),
+                pkg.getBaseCodePath(), pkg.isSystemApp(),
+                pkg.isUpdatedSystemApp());
     }
 
     private static NativeLibraryPaths getNativeLibraryPaths(final Abis abis,
@@ -201,12 +202,12 @@
     }
 
     @Override
-    public Abis getBundledAppAbis(PackageParser.Package pkg) {
-        final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());
+    public Abis getBundledAppAbis(AndroidPackage pkg) {
+        final String apkName = deriveCodePathName(pkg.getCodePath());
 
         // If "/system/lib64/apkname" exists, assume that is the per-package
         // native library directory to use; otherwise use "/system/lib/apkname".
-        final String apkRoot = calculateBundledApkRoot(pkg.applicationInfo.sourceDir);
+        final String apkRoot = calculateBundledApkRoot(pkg.getBaseCodePath());
         final Abis abis = getBundledAppAbi(pkg, apkRoot, apkName);
         return abis;
     }
@@ -219,8 +220,8 @@
      *                {@code /oem} under which system libraries are installed.
      * @param apkName the name of the installed package.
      */
-    private Abis getBundledAppAbi(PackageParser.Package pkg, String apkRoot, String apkName) {
-        final File codeFile = new File(pkg.codePath);
+    private Abis getBundledAppAbi(AndroidPackage pkg, String apkRoot, String apkName) {
+        final File codeFile = new File(pkg.getCodePath());
 
         final boolean has64BitLibs;
         final boolean has32BitLibs;
@@ -272,7 +273,7 @@
             // ABI that's higher on the list, i.e, a device that's configured to prefer
             // 64 bit apps will see a 64 bit primary ABI,
 
-            if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) {
+            if ((pkg.getFlags() & ApplicationInfo.FLAG_MULTIARCH) == 0) {
                 Slog.e(PackageManagerService.TAG,
                         "Package " + pkg + " has multiple bundled libs, but is not multiarch.");
             }
@@ -293,14 +294,14 @@
 
     @Override
     public Pair<Abis, NativeLibraryPaths> derivePackageAbi(
-            PackageParser.Package pkg, String cpuAbiOverride, boolean extractLibs)
+            AndroidPackage pkg, String cpuAbiOverride, boolean extractLibs)
             throws PackageManagerException {
         // Give ourselves some initial paths; we'll come back for another
         // pass once we've determined ABI below.
         final NativeLibraryPaths initialLibraryPaths = getNativeLibraryPaths(new Abis(pkg),
-                PackageManagerService.sAppLib32InstallDir, pkg.codePath,
-                pkg.applicationInfo.sourceDir, pkg.applicationInfo.isSystemApp(),
-                pkg.applicationInfo.isUpdatedSystemApp());
+                PackageManagerService.sAppLib32InstallDir, pkg.getCodePath(),
+                pkg.getBaseCodePath(), pkg.isSystemApp(),
+                pkg.isUpdatedSystemApp());
 
         // We shouldn't attempt to extract libs from system app when it was not updated.
         if (PackageManagerService.isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
@@ -309,6 +310,7 @@
 
         final String nativeLibraryRootStr = initialLibraryPaths.nativeLibraryRootDir;
         final boolean useIsaSpecificSubdirs = initialLibraryPaths.nativeLibraryRootRequiresIsa;
+        final boolean onIncremental = isIncrementalPath(pkg.getCodePath());
 
         String primaryCpuAbi = null;
         String secondaryCpuAbi = null;
@@ -327,12 +329,13 @@
             // Null out the abis so that they can be recalculated.
             primaryCpuAbi = null;
             secondaryCpuAbi = null;
-            if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0) {
+            if ((pkg.getFlags() & ApplicationInfo.FLAG_MULTIARCH) != 0) {
                 // Warn if we've set an abiOverride for multi-lib packages..
                 // By definition, we need to copy both 32 and 64 bit libraries for
                 // such packages.
-                if (pkg.cpuAbiOverride != null
-                        && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) {
+                if (pkg.getCpuAbiOverride() != null
+                        && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(
+                        pkg.getCpuAbiOverride())) {
                     Slog.w(PackageManagerService.TAG,
                             "Ignoring abiOverride for multi arch application.");
                 }
@@ -341,10 +344,18 @@
                 int abi64 = PackageManager.NO_NATIVE_LIBRARIES;
                 if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
                     if (extractLibs) {
-                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
-                        abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
-                                nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
-                                useIsaSpecificSubdirs);
+                        if (onIncremental) {
+                            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER,
+                                    "incrementalNativeBinaries");
+                            abi32 = NativeLibraryHelper.configureNativeBinariesForSupportedAbi(pkg,
+                                    handle, nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
+                                    useIsaSpecificSubdirs);
+                        } else {
+                            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+                            abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+                                    nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
+                                    useIsaSpecificSubdirs);
+                        }
                     } else {
                         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
                         abi32 = NativeLibraryHelper.findSupportedAbi(
@@ -364,10 +375,18 @@
 
                 if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
                     if (extractLibs) {
-                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
-                        abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
-                                nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
-                                useIsaSpecificSubdirs);
+                        if (onIncremental) {
+                            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER,
+                                    "incrementalNativeBinaries");
+                            abi64 = NativeLibraryHelper.configureNativeBinariesForSupportedAbi(pkg,
+                                    handle, nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
+                                    useIsaSpecificSubdirs);
+                        } else {
+                            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+                            abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+                                    nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
+                                    useIsaSpecificSubdirs);
+                        }
                     } else {
                         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
                         abi64 = NativeLibraryHelper.findSupportedAbi(
@@ -391,7 +410,7 @@
                 if (abi32 >= 0) {
                     final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
                     if (abi64 >= 0) {
-                        if (pkg.use32bitAbi) {
+                        if (pkg.isUse32BitAbi()) {
                             secondaryCpuAbi = primaryCpuAbi;
                             primaryCpuAbi = abi;
                         } else {
@@ -418,9 +437,15 @@
 
                 final int copyRet;
                 if (extractLibs) {
-                    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
-                    copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
-                            nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
+                    if (onIncremental) {
+                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "incrementalNativeBinaries");
+                        copyRet = NativeLibraryHelper.configureNativeBinariesForSupportedAbi(pkg,
+                                handle, nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
+                    } else {
+                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+                        copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+                                nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
+                    }
                 } else {
                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
                     copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);
@@ -458,9 +483,9 @@
         final Abis abis = new Abis(primaryCpuAbi, secondaryCpuAbi);
         return new Pair<>(abis,
                 getNativeLibraryPaths(abis, PackageManagerService.sAppLib32InstallDir,
-                        pkg.codePath, pkg.applicationInfo.sourceDir,
-                        pkg.applicationInfo.isSystemApp(),
-                        pkg.applicationInfo.isUpdatedSystemApp()));
+                        pkg.getCodePath(), pkg.getBaseCodePath(),
+                        pkg.isSystemApp(),
+                        pkg.isUpdatedSystemApp()));
     }
 
     /**
@@ -479,11 +504,11 @@
     @Override
     @Nullable
     public String getAdjustedAbiForSharedUser(
-            Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage) {
+            Set<PackageSetting> packagesForUser, AndroidPackage scannedPackage) {
         String requiredInstructionSet = null;
-        if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) {
+        if (scannedPackage != null && scannedPackage.getPrimaryCpuAbi() != null) {
             requiredInstructionSet = VMRuntime.getInstructionSet(
-                    scannedPackage.applicationInfo.primaryCpuAbi);
+                    scannedPackage.getPrimaryCpuAbi());
         }
 
         PackageSetting requirer = null;
@@ -492,7 +517,7 @@
             // when scannedPackage is an update of an existing package. Without this check,
             // we will never be able to change the ABI of any package belonging to a shared
             // user, even if it's compatible with other packages.
-            if (scannedPackage != null && scannedPackage.packageName.equals(ps.name)) {
+            if (scannedPackage != null && scannedPackage.getPackageName().equals(ps.name)) {
                 continue;
             }
             if (ps.primaryCpuAbiString == null) {
@@ -530,7 +555,7 @@
         } else {
             // requirer == null implies that we're updating all ABIs in the set to
             // match scannedPackage.
-            adjustedAbi = scannedPackage.applicationInfo.primaryCpuAbi;
+            adjustedAbi = scannedPackage.getPrimaryCpuAbi();
         }
         return adjustedAbi;
     }
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 4f7c8c8..2b42221 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -41,10 +41,10 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageParser;
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.dex.ArtManager;
 import android.content.pm.dex.DexMetadataHelper;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.FileUtils;
 import android.os.PowerManager;
 import android.os.SystemClock;
@@ -53,6 +53,7 @@
 import android.os.WorkSource;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
@@ -109,9 +110,9 @@
         this.mSystemReady = from.mSystemReady;
     }
 
-    static boolean canOptimizePackage(PackageParser.Package pkg) {
+    static boolean canOptimizePackage(AndroidPackage pkg) {
         // We do not dexopt a package with no code.
-        if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) == 0) {
+        if ((pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) == 0) {
             return false;
         }
 
@@ -125,18 +126,18 @@
      * <p>Calls to {@link com.android.server.pm.Installer#dexopt} on {@link #mInstaller} are
      * synchronized on {@link #mInstallLock}.
      */
-    int performDexOpt(PackageParser.Package pkg,
+    int performDexOpt(AndroidPackage pkg,
             String[] instructionSets, CompilerStats.PackageStats packageStats,
             PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) {
-        if (pkg.applicationInfo.uid == -1) {
-            throw new IllegalArgumentException("Dexopt for " + pkg.packageName
+        if (pkg.getUid() == -1) {
+            throw new IllegalArgumentException("Dexopt for " + pkg.getPackageName()
                     + " has invalid uid.");
         }
         if (!canOptimizePackage(pkg)) {
             return DEX_OPT_SKIPPED;
         }
         synchronized (mInstallLock) {
-            final long acquireTime = acquireWakeLockLI(pkg.applicationInfo.uid);
+            final long acquireTime = acquireWakeLockLI(pkg.getUid());
             try {
                 return performDexOptLI(pkg, instructionSets,
                         packageStats, packageUseInfo, options);
@@ -151,19 +152,20 @@
      * It assumes the install lock is held.
      */
     @GuardedBy("mInstallLock")
-    private int performDexOptLI(PackageParser.Package pkg,
+    private int performDexOptLI(AndroidPackage pkg,
             String[] targetInstructionSets, CompilerStats.PackageStats packageStats,
             PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) {
-        final List<SharedLibraryInfo> sharedLibraries = pkg.usesLibraryInfos;
+        final List<SharedLibraryInfo> sharedLibraries = pkg.getUsesLibraryInfos();
         final String[] instructionSets = targetInstructionSets != null ?
-                targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
+                targetInstructionSets : getAppDexInstructionSets(pkg.getPrimaryCpuAbi(),
+                pkg.getSecondaryCpuAbi());
         final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
         final List<String> paths = pkg.getAllCodePaths();
 
-        int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+        int sharedGid = UserHandle.getSharedAppGid(pkg.getUid());
         if (sharedGid == -1) {
-            Slog.wtf(TAG, "Well this is awkward; package " + pkg.applicationInfo.name + " had UID "
-                    + pkg.applicationInfo.uid, new Throwable());
+            Slog.wtf(TAG, "Well this is awkward; package " + pkg.getAppInfoName() + " had UID "
+                    + pkg.getUid(), new Throwable());
             sharedGid = android.os.Process.NOBODY_UID;
         }
 
@@ -171,21 +173,21 @@
         // For each code path in the package, this array contains the class loader context that
         // needs to be passed to dexopt in order to ensure correct optimizations.
         boolean[] pathsWithCode = new boolean[paths.size()];
-        pathsWithCode[0] = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0;
+        pathsWithCode[0] = (pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) != 0;
         for (int i = 1; i < paths.size(); i++) {
-            pathsWithCode[i] = (pkg.splitFlags[i - 1] & ApplicationInfo.FLAG_HAS_CODE) != 0;
+            pathsWithCode[i] = (pkg.getSplitFlags()[i - 1] & ApplicationInfo.FLAG_HAS_CODE) != 0;
         }
         String[] classLoaderContexts = DexoptUtils.getClassLoaderContexts(
-                pkg.applicationInfo, sharedLibraries, pathsWithCode);
+                pkg, sharedLibraries, pathsWithCode);
 
         // Sanity check that we do not call dexopt with inconsistent data.
         if (paths.size() != classLoaderContexts.length) {
-            String[] splitCodePaths = pkg.applicationInfo.getSplitCodePaths();
+            String[] splitCodePaths = pkg.getSplitCodePaths();
             throw new IllegalStateException("Inconsistent information "
                 + "between PackageParser.Package and its ApplicationInfo. "
                 + "pkg.getAllCodePaths=" + paths
-                + " pkg.applicationInfo.getBaseCodePath=" + pkg.applicationInfo.getBaseCodePath()
-                + " pkg.applicationInfo.getSplitCodePaths="
+                + " pkg.getBaseCodePath=" + pkg.getBaseCodePath()
+                + " pkg.getSplitCodePaths="
                 + (splitCodePaths == null ? "null" : Arrays.toString(splitCodePaths)));
         }
 
@@ -211,7 +213,8 @@
                 }
             }
 
-            String profileName = ArtManager.getProfileName(i == 0 ? null : pkg.splitNames[i - 1]);
+            String profileName = ArtManager.getProfileName(
+                    i == 0 ? null : pkg.getSplitNames()[i - 1]);
 
             String dexMetadataPath = null;
             if (options.isDexoptInstallWithDexMetadata()) {
@@ -222,7 +225,7 @@
 
             final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary()
                     || packageUseInfo.isUsedByOtherApps(path);
-            final String compilerFilter = getRealCompilerFilter(pkg.applicationInfo,
+            final String compilerFilter = getRealCompilerFilter(pkg,
                 options.getCompilerFilter(), isUsedByOtherApps);
             final boolean profileUpdated = options.isCheckForProfileUpdates() &&
                 isProfileUpdated(pkg, sharedGid, profileName, compilerFilter);
@@ -257,7 +260,7 @@
      *      DEX_OPT_SKIPPED if the path does not need to be deopt-ed.
      */
     @GuardedBy("mInstallLock")
-    private int dexOptPath(PackageParser.Package pkg, String path, String isa,
+    private int dexOptPath(AndroidPackage pkg, String path, String isa,
             String compilerFilter, boolean profileUpdated, String classLoaderContext,
             int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade,
             String profileName, String dexMetadataPath, int compilationReason) {
@@ -270,7 +273,7 @@
         String oatDir = getPackageOatDirIfSupported(pkg);
 
         Log.i(TAG, "Running dexopt (dexoptNeeded=" + dexoptNeeded + ") on: " + path
-                + " pkg=" + pkg.applicationInfo.packageName + " isa=" + isa
+                + " pkg=" + pkg.getAppInfoPackageName() + " isa=" + isa
                 + " dexoptFlags=" + printDexoptFlags(dexoptFlags)
                 + " targetFilter=" + compilerFilter + " oatDir=" + oatDir
                 + " classLoaderContext=" + classLoaderContext);
@@ -281,9 +284,9 @@
             // TODO: Consider adding 2 different APIs for primary and secondary dexopt.
             // installd only uses downgrade flag for secondary dex files and ignores it for
             // primary dex files.
-            mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags,
-                    compilerFilter, pkg.volumeUuid, classLoaderContext, pkg.applicationInfo.seInfo,
-                    false /* downgrade*/, pkg.applicationInfo.targetSdkVersion,
+            mInstaller.dexopt(path, uid, pkg.getPackageName(), isa, dexoptNeeded, oatDir,
+                    dexoptFlags, compilerFilter, pkg.getVolumeUuid(), classLoaderContext,
+                    pkg.getSeInfo(), false /* downgrade*/, pkg.getTargetSdkVersion(),
                     profileName, dexMetadataPath,
                     getAugmentedReasonName(compilationReason, dexMetadataPath != null));
 
@@ -446,9 +449,10 @@
     /**
      * Dumps the dexopt state of the given package {@code pkg} to the given {@code PrintWriter}.
      */
-    void dumpDexoptState(IndentingPrintWriter pw, PackageParser.Package pkg,
+    void dumpDexoptState(IndentingPrintWriter pw, AndroidPackage pkg,
             PackageDexUsage.PackageUseInfo useInfo) {
-        final String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo);
+        final String[] instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(),
+                pkg.getSecondaryCpuAbi());
         final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
 
         final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
@@ -504,7 +508,7 @@
         // When an app or priv app is configured to run out of box, only verify it.
         if (info.isEmbeddedDexUsed()
                 || (info.isPrivilegedApp()
-                    && DexManager.isPackageSelectedToRunOob(info.packageName))) {
+                && DexManager.isPackageSelectedToRunOob(info.packageName))) {
             return "verify";
         }
 
@@ -535,12 +539,43 @@
     }
 
     /**
-     * Computes the dex flags that needs to be pass to installd for the given package and compiler
-     * filter.
+     * Returns the compiler filter that should be used to optimize the package code.
+     * The target filter will be updated if the package code is used by other apps
+     * or if it has the safe mode flag set.
      */
-    private int getDexFlags(PackageParser.Package pkg, String compilerFilter,
-            DexoptOptions options) {
-        return getDexFlags(pkg.applicationInfo, compilerFilter, options);
+    private String getRealCompilerFilter(AndroidPackage pkg, String targetCompilerFilter,
+            boolean isUsedByOtherApps) {
+        // When an app or priv app is configured to run out of box, only verify it.
+        if (pkg.isEmbeddedDexUsed()
+                || (pkg.isPrivileged()
+                    && DexManager.isPackageSelectedToRunOob(pkg.getPackageName()))) {
+            return "verify";
+        }
+
+        // We force vmSafeMode on debuggable apps as well:
+        //  - the runtime ignores their compiled code
+        //  - they generally have lots of methods that could make the compiler used run
+        //    out of memory (b/130828957)
+        // Note that forcing the compiler filter here applies to all compilations (even if they
+        // are done via adb shell commands). That's ok because right now the runtime will ignore
+        // the compiled code anyway. The alternative would have been to update either
+        // PackageDexOptimizer#canOptimizePackage or PackageManagerService#getOptimizablePackages
+        // but that would have the downside of possibly producing a big odex files which would
+        // be ignored anyway.
+        boolean vmSafeModeOrDebuggable = ((pkg.getFlags() & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0)
+                || ((pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
+
+        if (vmSafeModeOrDebuggable) {
+            return getSafeModeCompilerFilter(targetCompilerFilter);
+        }
+
+        if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps) {
+            // If the dex files is used by other apps, apply the shared filter.
+            return PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
+                    PackageManagerService.REASON_SHARED);
+        }
+
+        return targetCompilerFilter;
     }
 
     private boolean isAppImageEnabled() {
@@ -548,7 +583,24 @@
     }
 
     private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) {
-        int flags = info.flags;
+        return getDexFlags(info.flags, info.getHiddenApiEnforcementPolicy(),
+                info.splitDependencies, info.requestsIsolatedSplitLoading(), compilerFilter,
+                options);
+    }
+    private int getDexFlags(AndroidPackage pkg, String compilerFilter,
+            DexoptOptions options) {
+        return getDexFlags(pkg.getFlags(), pkg.getHiddenApiEnforcementPolicy(),
+                pkg.getSplitDependencies(), pkg.requestsIsolatedSplitLoading(), compilerFilter,
+                options);
+    }
+
+    /**
+     * Computes the dex flags that needs to be pass to installd for the given package and compiler
+     * filter.
+     */
+    private int getDexFlags(int flags, int hiddenApiEnforcementPolicy,
+            SparseArray<int[]> splitDependencies, boolean requestsIsolatedSplitLoading,
+            String compilerFilter, DexoptOptions options) {
         boolean debuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
         // Profile guide compiled oat files should not be public unles they are based
         // on profiles from dex metadata archives.
@@ -560,7 +612,9 @@
         // Some apps are executed with restrictions on hidden API usage. If this app is one
         // of them, pass a flag to dexopt to enable the same restrictions during compilation.
         // TODO we should pass the actual flag value to dexopt, rather than assuming blacklist
-        int hiddenApiFlag = info.getHiddenApiEnforcementPolicy() == HIDDEN_API_ENFORCEMENT_DISABLED
+        // TODO(b/135203078): This flag is no longer set as part of AndroidPackage
+        //  and may not be preserved
+        int hiddenApiFlag = hiddenApiEnforcementPolicy == HIDDEN_API_ENFORCEMENT_DISABLED
                 ? 0
                 : DEXOPT_ENABLE_HIDDEN_API_CHECKS;
         // Avoid generating CompactDex for modes that are latency critical.
@@ -578,8 +632,8 @@
         // declare inter-split dependencies, then all the splits will be loaded in the base
         // apk class loader (in the order of their definition, otherwise disable app images
         // because they are unsupported for multiple class loaders. b/7269679
-        boolean generateAppImage = isProfileGuidedFilter && (info.splitDependencies == null ||
-                !info.requestsIsolatedSplitLoading()) && isAppImageEnabled();
+        boolean generateAppImage = isProfileGuidedFilter && (splitDependencies == null ||
+                !requestsIsolatedSplitLoading) && isAppImageEnabled();
         int dexFlags =
                 (isPublic ? DEXOPT_PUBLIC : 0)
                 | (debuggable ? DEXOPT_DEBUGGABLE : 0)
@@ -617,7 +671,7 @@
      * current profile and the reference profile will be merged and subsequent calls
      * may return a different result.
      */
-    private boolean isProfileUpdated(PackageParser.Package pkg, int uid, String profileName,
+    private boolean isProfileUpdated(AndroidPackage pkg, int uid, String profileName,
             String compilerFilter) {
         // Check if we are allowed to merge and if the compiler filter is profile guided.
         if (!isProfileGuidedCompilerFilter(compilerFilter)) {
@@ -625,7 +679,7 @@
         }
         // Merge profiles. It returns whether or not there was an updated in the profile info.
         try {
-            return mInstaller.mergeProfiles(uid, pkg.packageName, profileName);
+            return mInstaller.mergeProfiles(uid, pkg.getPackageName(), profileName);
         } catch (InstallerException e) {
             Slog.w(TAG, "Failed to merge profiles", e);
         }
@@ -645,11 +699,11 @@
      * not needed or unsupported for the package.
      */
     @Nullable
-    private String getPackageOatDirIfSupported(PackageParser.Package pkg) {
+    private String getPackageOatDirIfSupported(AndroidPackage pkg) {
         if (!pkg.canHaveOatDir()) {
             return null;
         }
-        File codePath = new File(pkg.codePath);
+        File codePath = new File(pkg.getCodePath());
         if (!codePath.isDirectory()) {
             return null;
         }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 93249e9..dceca0a 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -494,7 +494,7 @@
             }
             // Only apps with INSTALL_PACKAGES are allowed to set an installer that is not the
             // caller.
-            if (!requestedInstallerPackageName.equals(installerPackageName)) {
+            if (!TextUtils.equals(requestedInstallerPackageName, installerPackageName)) {
                 if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
                         != PackageManager.PERMISSION_GRANTED) {
                     mAppOps.checkPackage(callingUid, requestedInstallerPackageName);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index d63e704..518ec50 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -54,6 +54,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageInstallObserver2;
 import android.content.pm.IPackageInstallerSession;
+import android.content.pm.InstallationFile;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionInfo;
@@ -65,6 +66,7 @@
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
 import android.content.pm.dex.DexMetadataHelper;
+import android.content.pm.parsing.ApkLiteParseUtils;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.os.Binder;
@@ -81,6 +83,8 @@
 import android.os.RevocableFileDescriptor;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.incremental.IncrementalFileStorages;
+import android.os.incremental.IncrementalManager;
 import android.os.storage.StorageManager;
 import android.stats.devicepolicy.DevicePolicyEnums;
 import android.system.ErrnoException;
@@ -133,6 +137,7 @@
     private static final int MSG_COMMIT = 1;
     private static final int MSG_ON_PACKAGE_INSTALLED = 2;
     private static final int MSG_SEAL = 3;
+    private static final int MSG_TRANSFER = 4;
 
     /** XML constants used for persisting a session */
     static final String TAG_SESSION = "session";
@@ -308,6 +313,8 @@
     @GuardedBy("mLock")
     private boolean mVerityFound;
 
+    private IncrementalFileStorages mIncrementalFileStorages;
+
     private static final FileFilter sAddedFilter = new FileFilter() {
         @Override
         public boolean accept(File file) {
@@ -332,6 +339,9 @@
     private final Handler.Callback mHandlerCallback = new Handler.Callback() {
         @Override
         public boolean handleMessage(Message msg) {
+            SomeArgs args;
+            String packageName;
+            IntentSender statusReceiver;
             switch (msg.what) {
                 case MSG_SEAL:
                     handleSeal((IntentSender) msg.obj);
@@ -339,12 +349,20 @@
                 case MSG_COMMIT:
                     handleCommit();
                     break;
+                case MSG_TRANSFER:
+                    args = (SomeArgs) msg.obj;
+                    packageName = (String) args.arg1;
+                    statusReceiver = (IntentSender) args.arg2;
+                    args.recycle();
+
+                    handleTransfer(statusReceiver, packageName);
+                    break;
                 case MSG_ON_PACKAGE_INSTALLED:
-                    final SomeArgs args = (SomeArgs) msg.obj;
-                    final String packageName = (String) args.arg1;
+                    args = (SomeArgs) msg.obj;
+                    packageName = (String) args.arg1;
                     final String message = (String) args.arg2;
                     final Bundle extras = (Bundle) args.arg3;
-                    final IntentSender statusReceiver = (IntentSender) args.arg4;
+                    statusReceiver = (IntentSender) args.arg4;
                     final int returnCode = args.argi1;
                     args.recycle();
 
@@ -378,7 +396,7 @@
      * Checks if the permissions still need to be confirmed.
      *
      * <p>This is dependant on the identity of the installer, hence this cannot be cached if the
-     * installer might still {@link #transfer(String) change}.
+     * installer might still {@link #transfer(String, IntentSender) change}.
      *
      * @return {@code true} iff we need to ask to confirm the permissions?
      */
@@ -459,6 +477,18 @@
         mStagedSessionErrorCode = stagedSessionErrorCode;
         mStagedSessionErrorMessage =
                 stagedSessionErrorMessage != null ? stagedSessionErrorMessage : "";
+
+        // TODO(b/136132412): sanity check if session should not be incremental
+        if (!params.isStaged && params.incrementalParams != null
+                && !params.incrementalParams.getPackageName().isEmpty()) {
+            IncrementalManager incrementalManager = (IncrementalManager) mContext.getSystemService(
+                    Context.INCREMENTAL_SERVICE);
+            if (incrementalManager != null) {
+                mIncrementalFileStorages =
+                        new IncrementalFileStorages(mPackageName, stageDir, incrementalManager,
+                                params.incrementalParams);
+            }
+        }
     }
 
     public SessionInfo generateInfo() {
@@ -862,10 +892,18 @@
             }
         }
 
+        if (mIncrementalFileStorages != null) {
+            mIncrementalFileStorages.finishSetUp();
+        }
+
         mHandler.obtainMessage(MSG_SEAL, statusReceiver).sendToTarget();
     }
 
     private void handleSeal(@NonNull IntentSender statusReceiver) {
+        // TODO(b/136132412): update with new APIs
+        if (mIncrementalFileStorages != null) {
+            mIncrementalFileStorages.startLoading();
+        }
         if (!markAsCommitted(statusReceiver)) {
             return;
         }
@@ -1183,13 +1221,11 @@
         }
     }
 
-    @Override
-    public void transfer(String packageName) {
-        Preconditions.checkNotNull(packageName);
-
+    private int assertCanBeTransferredAndReturnNewOwner(String packageName)
+            throws PackageManager.NameNotFoundException {
         ApplicationInfo newOwnerAppInfo = mPm.getApplicationInfo(packageName, 0, userId);
         if (newOwnerAppInfo == null) {
-            throw new ParcelableException(new PackageManager.NameNotFoundException(packageName));
+            throw new PackageManager.NameNotFoundException(packageName);
         }
 
         if (PackageManager.PERMISSION_GRANTED != mPm.checkUidPermission(
@@ -1204,31 +1240,104 @@
             throw new SecurityException("Can only transfer sessions that use public options");
         }
 
-        List<PackageInstallerSession> childSessions = getChildSessions();
+        return newOwnerAppInfo.uid;
+    }
+
+    @Override
+    public void transfer(String packageName, IntentSender statusReceiver) {
+        Preconditions.checkNotNull(statusReceiver);
+        Preconditions.checkNotNull(packageName);
+
+        try {
+            assertCanBeTransferredAndReturnNewOwner(packageName);
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new ParcelableException(e);
+        }
 
         synchronized (mLock) {
             assertCallerIsOwnerOrRootLocked();
             assertPreparedAndNotSealedLocked("transfer");
+        }
 
-            try {
-                sealAndValidateLocked(childSessions);
-            } catch (PackageManagerException e) {
-                throw new IllegalArgumentException("Package is not valid", e);
+        final SomeArgs args = SomeArgs.obtain();
+        args.arg1 = packageName;
+        args.arg2 = statusReceiver;
+
+        mHandler.obtainMessage(MSG_TRANSFER, args).sendToTarget();
+    }
+
+    private void handleTransfer(IntentSender statusReceiver, String packageName) {
+        List<PackageInstallerSession> childSessions = getChildSessions();
+
+        try {
+            final int uid = assertCanBeTransferredAndReturnNewOwner(packageName);
+
+            synchronized (mLock) {
+                assertPreparedAndNotSealedLocked("transfer");
+
+                try {
+                    sealAndValidateLocked(childSessions);
+                } catch (PackageManagerException e) {
+                    throw new IllegalArgumentException("Package is not valid", e);
+                }
+
+                if (!mPackageName.equals(mInstallSource.installerPackageName)) {
+                    throw new SecurityException(
+                            "Can only transfer sessions that update the original installer");
+                }
+
+                mInstallerUid = uid;
+                mInstallSource = InstallSource.create(packageName, null, packageName, false);
             }
-
-            if (!mPackageName.equals(mInstallSource.installerPackageName)) {
-                throw new SecurityException("Can only transfer sessions that update the original "
-                        + "installer");
-            }
-
-            mInstallerUid = newOwnerAppInfo.uid;
-            mInstallSource = InstallSource.create(packageName, null, packageName, false);
+        } catch (PackageManager.NameNotFoundException e) {
+            onSessionTransferStatus(statusReceiver, packageName,
+                    PackageInstaller.STATUS_FAILURE_NAME_NOT_FOUND, e.getMessage());
+            return;
+        } catch (IllegalStateException e) {
+            onSessionTransferStatus(statusReceiver, packageName,
+                    PackageInstaller.STATUS_FAILURE_ILLEGAL_STATE, e.getMessage());
+            return;
+        } catch (SecurityException e) {
+            onSessionTransferStatus(statusReceiver, packageName,
+                    PackageInstaller.STATUS_FAILURE_SECURITY, e.getMessage());
+            return;
+        } catch (Throwable e) {
+            onSessionTransferStatus(statusReceiver, packageName, PackageInstaller.STATUS_FAILURE,
+                    e.getMessage());
+            return;
         }
 
         // Persist the fact that we've sealed ourselves to prevent
         // mutations of any hard links we create. We do this without holding
         // the session lock, since otherwise it's a lock inversion.
         mCallback.onSessionSealedBlocking(this);
+
+        // Report success.
+        onSessionTransferStatus(statusReceiver, packageName, PackageInstaller.STATUS_SUCCESS, null);
+    }
+
+    private void onSessionTransferStatus(IntentSender statusReceiver, String otherPackageName,
+            int status, String statusMessage) {
+        final String packageName;
+        synchronized (mLock) {
+            packageName = mPackageName;
+        }
+
+        final Intent fillIn = new Intent();
+        fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, packageName);
+        fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
+        fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, otherPackageName);
+
+        fillIn.putExtra(PackageInstaller.EXTRA_STATUS, status);
+        if (!TextUtils.isEmpty(statusMessage)) {
+            fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, statusMessage);
+        }
+
+        try {
+            statusReceiver.sendIntent(mContext, 0, fillIn, null, null);
+        } catch (IntentSender.SendIntentException ignored) {
+        }
+
     }
 
     private void handleCommit() {
@@ -1409,6 +1518,7 @@
                 computeProgressLocked(true);
 
                 // Unpack native libraries
+                // TODO(b/136132412): skip for incremental installation
                 extractNativeLibraries(stageDir, params.abiOverride, mayInheritNativeLibs());
             }
 
@@ -1568,7 +1678,7 @@
         for (File addedFile : addedFiles) {
             final ApkLite apk;
             try {
-                apk = PackageParser.parseApkLite(
+                apk = ApkLiteParseUtils.parseApkLite(
                         addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
             } catch (PackageParserException e) {
                 throw PackageManagerException.from(e);
@@ -1667,7 +1777,7 @@
             ApplicationInfo appInfo = pkgInfo.applicationInfo;
             try {
                 existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
-                existingBase = PackageParser.parseApkLite(new File(appInfo.getBaseCodePath()),
+                existingBase = ApkLiteParseUtils.parseApkLite(new File(appInfo.getBaseCodePath()),
                         PackageParser.PARSE_COLLECT_CERTIFICATES);
             } catch (PackageParserException e) {
                 throw PackageManagerException.from(e);
@@ -2099,7 +2209,6 @@
             }
             destroyInternal();
         }
-
         dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
     }
 
@@ -2185,6 +2294,20 @@
         return mParentSessionId;
     }
 
+    @Override
+    public void addFile(@NonNull String name, long size, @NonNull byte[] metadata) {
+        if (mIncrementalFileStorages == null) {
+            throw new IllegalStateException(
+                    "Cannot add Incremental File to a non-Incremental session.");
+        }
+        try {
+            mIncrementalFileStorages.addFile(new InstallationFile(name, size, metadata));
+        } catch (IOException ex) {
+            throw new IllegalStateException(
+                    "Failed to add and configure Incremental File: " + name, ex);
+        }
+    }
+
     private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
         final IntentSender statusReceiver;
         final String packageName;
@@ -2307,6 +2430,9 @@
         // since these packages are supposed to be read on reboot.
         // Those dirs are deleted when the staged session has reached a final state.
         if (stageDir != null && !params.isStaged) {
+            if (mIncrementalFileStorages != null) {
+                mIncrementalFileStorages.cleanUp();
+            }
             try {
                 mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
             } catch (InstallerException ignored) {
@@ -2320,6 +2446,9 @@
                 mSessionProvider.getSession(childSessionId).cleanStageDir();
             }
         } else {
+            if (mIncrementalFileStorages != null) {
+                mIncrementalFileStorages.cleanUp();
+            }
             try {
                 mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
             } catch (InstallerException ignored) {
diff --git a/services/core/java/com/android/server/pm/PackageKeySetData.java b/services/core/java/com/android/server/pm/PackageKeySetData.java
index 031b5ce..10685b0 100644
--- a/services/core/java/com/android/server/pm/PackageKeySetData.java
+++ b/services/core/java/com/android/server/pm/PackageKeySetData.java
@@ -20,6 +20,8 @@
 
 import com.android.internal.util.ArrayUtils;
 
+import java.util.Map;
+
 public class PackageKeySetData {
 
     static final long KEYSET_UNASSIGNED = -1;
@@ -90,16 +92,13 @@
     /*
      * Replace defined keysets with new ones.
      */
-    protected void setAliases(ArrayMap<String, Long> newAliases) {
+    protected void setAliases(Map<String, Long> newAliases) {
 
         /* remove old aliases */
         removeAllDefinedKeySets();
 
         /* add new ones */
-        final int newAliasSize = newAliases.size();
-        for (int i = 0; i < newAliasSize; i++) {
-            mKeySetAliases.put(newAliases.keyAt(i), newAliases.valueAt(i));;
-        }
+        mKeySetAliases.putAll(newAliases);
     }
 
     protected void addDefinedKeySet(long ks, String alias) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0e075b1..73ab82d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -34,7 +34,6 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
-import static android.content.pm.PackageManager.DELETE_KEEP_DATA;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
@@ -87,6 +86,7 @@
 import static android.content.pm.PackageManager.RESTRICTION_NONE;
 import static android.content.pm.PackageParser.isApkFile;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import static android.os.incremental.IncrementalManager.isIncrementalPath;
 import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
 import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
 import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
@@ -152,13 +152,13 @@
 import android.content.pm.IPackageManagerNative;
 import android.content.pm.IPackageMoveObserver;
 import android.content.pm.IPackageStatsObserver;
+import android.content.pm.InstallSourceInfo;
 import android.content.pm.InstantAppInfo;
 import android.content.pm.InstantAppRequest;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.KeySet;
 import android.content.pm.ModuleInfo;
-import android.content.pm.PackageBackwardCompatibility;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInfoLite;
 import android.content.pm.PackageInstaller;
@@ -168,7 +168,6 @@
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageManagerInternal.PackageListObserver;
 import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.ActivityIntentInfo;
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
 import android.content.pm.PackageParser.ParseFlags;
@@ -193,6 +192,19 @@
 import android.content.pm.dex.ArtManager;
 import android.content.pm.dex.DexMetadataHelper;
 import android.content.pm.dex.IArtManager;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ApkParseUtils;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
+import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
+import android.content.pm.parsing.ComponentParseUtils.ParsedService;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.PackageInfoUtils;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.library.PackageBackwardCompatibility;
 import android.content.res.Resources;
 import android.content.rollback.IRollbackManager;
 import android.database.ContentObserver;
@@ -226,6 +238,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.UserManagerInternal;
+import android.os.incremental.IncrementalManager;
 import android.os.storage.DiskInfo;
 import android.os.storage.IStorageManager;
 import android.os.storage.StorageEventListener;
@@ -459,20 +472,19 @@
     static final int SCAN_REQUIRE_KNOWN = 1 << 7;
     static final int SCAN_MOVE = 1 << 8;
     static final int SCAN_INITIAL = 1 << 9;
-    static final int SCAN_CHECK_ONLY = 1 << 10;
-    static final int SCAN_DONT_KILL_APP = 1 << 11;
-    static final int SCAN_IGNORE_FROZEN = 1 << 12;
-    static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1 << 13;
-    static final int SCAN_AS_INSTANT_APP = 1 << 14;
-    static final int SCAN_AS_FULL_APP = 1 << 15;
-    static final int SCAN_AS_VIRTUAL_PRELOAD = 1 << 16;
-    static final int SCAN_AS_SYSTEM = 1 << 17;
-    static final int SCAN_AS_PRIVILEGED = 1 << 18;
-    static final int SCAN_AS_OEM = 1 << 19;
-    static final int SCAN_AS_VENDOR = 1 << 20;
-    static final int SCAN_AS_PRODUCT = 1 << 21;
-    static final int SCAN_AS_SYSTEM_EXT = 1 << 22;
-    static final int SCAN_AS_ODM = 1 << 23;
+    static final int SCAN_DONT_KILL_APP = 1 << 10;
+    static final int SCAN_IGNORE_FROZEN = 1 << 11;
+    static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1 << 12;
+    static final int SCAN_AS_INSTANT_APP = 1 << 13;
+    static final int SCAN_AS_FULL_APP = 1 << 14;
+    static final int SCAN_AS_VIRTUAL_PRELOAD = 1 << 15;
+    static final int SCAN_AS_SYSTEM = 1 << 16;
+    static final int SCAN_AS_PRIVILEGED = 1 << 17;
+    static final int SCAN_AS_OEM = 1 << 18;
+    static final int SCAN_AS_VENDOR = 1 << 19;
+    static final int SCAN_AS_PRODUCT = 1 << 20;
+    static final int SCAN_AS_SYSTEM_EXT = 1 << 21;
+    static final int SCAN_AS_ODM = 1 << 22;
 
     @IntDef(flag = true, prefix = { "SCAN_" }, value = {
             SCAN_NO_DEX,
@@ -483,7 +495,6 @@
             SCAN_REQUIRE_KNOWN,
             SCAN_MOVE,
             SCAN_INITIAL,
-            SCAN_CHECK_ONLY,
             SCAN_DONT_KILL_APP,
             SCAN_IGNORE_FROZEN,
             SCAN_FIRST_BOOT_OR_UPGRADE,
@@ -602,11 +613,19 @@
     public static final int REASON_LAST = REASON_SHARED;
 
     /**
-     * Whether the package parser cache is enabled.
+     * The initial enabled state of the cache before other checks are done.
      */
     private static final boolean DEFAULT_PACKAGE_PARSER_CACHE_ENABLED = true;
 
     /**
+     * Whether to skip all other checks and force the cache to be enabled.
+     *
+     * Setting this to true will cause the cache to be named "debug" to avoid eviction from
+     * build fingerprint changes.
+     */
+    private static final boolean FORCE_PACKAGE_PARSED_CACHE_ENABLED = false;
+
+    /**
      * Permissions required in order to receive instant application lifecycle broadcasts.
      */
     private static final String[] INSTANT_APP_BROADCAST_PERMISSION =
@@ -663,7 +682,7 @@
 
     // Keys are String (package name), values are Package.
     @GuardedBy("mLock")
-    final ArrayMap<String, PackageParser.Package> mPackages = new ArrayMap<>();
+    final ArrayMap<String, AndroidPackage> mPackages = new ArrayMap<>();
 
     // Keys are isolated uids and values are the uid of the application
     // that created the isolated proccess.
@@ -748,7 +767,7 @@
      * specificity (the more generic, the earlier in the list a partition appears).
      */
     @VisibleForTesting(visibility = Visibility.PRIVATE)
-    static final List<SystemPartition> SYSTEM_PARTITIONS = Collections.unmodifiableList(
+    public static final List<SystemPartition> SYSTEM_PARTITIONS = Collections.unmodifiableList(
             Arrays.asList(
                     new SystemPartition(Environment.getRootDirectory(), 0 /* scanFlag */,
                             false /* hasOverlays */),
@@ -987,12 +1006,12 @@
             new ArrayMap<>();
 
     // Mapping from instrumentation class names to info about them.
-    final ArrayMap<ComponentName, PackageParser.Instrumentation> mInstrumentation =
+    final ArrayMap<ComponentName, ParsedInstrumentation> mInstrumentation =
             new ArrayMap<>();
 
     // Packages whose data we have transfered into another package, thus
     // should no longer exist.
-    final ArraySet<String> mTransferedPackages = new ArraySet<>();
+    final ArraySet<String> mTransferredPackages = new ArraySet<>();
 
     // Broadcast actions that are only available to the system.
     @GuardedBy("mProtectedBroadcasts")
@@ -1036,13 +1055,13 @@
     final ActivityInfo mResolveActivity = new ActivityInfo();
     final ResolveInfo mResolveInfo = new ResolveInfo();
     ComponentName mResolveComponentName;
-    PackageParser.Package mPlatformPackage;
+    AndroidPackage mPlatformPackage;
     ComponentName mCustomResolverComponentName;
 
     boolean mResolverReplaced = false;
 
     private final @Nullable ComponentName mIntentFilterVerifierComponent;
-    private final @Nullable IntentFilterVerifier<ActivityIntentInfo> mIntentFilterVerifier;
+    private final @Nullable IntentFilterVerifier<ParsedActivityIntentInfo> mIntentFilterVerifier;
 
     private int mIntentFilterVerificationToken = 0;
 
@@ -1074,15 +1093,22 @@
 
     private Future<?> mPrepareAppDataFuture;
 
+    private final IncrementalManager mIncrementalManager;
+
     private static class IFVerificationParams {
-        PackageParser.Package pkg;
+        String packageName;
+        boolean hasDomainUrls;
+        List<ParsedActivity> activities;
         boolean replacing;
         int userId;
         int verifierUid;
 
-        public IFVerificationParams(PackageParser.Package _pkg, boolean _replacing,
+        public IFVerificationParams(String packageName, boolean hasDomainUrls,
+                List<ParsedActivity> activities, boolean _replacing,
                 int _userId, int _verifierUid) {
-            pkg = _pkg;
+            this.packageName = packageName;
+            this.hasDomainUrls = hasDomainUrls;
+            this.activities = activities;
             replacing = _replacing;
             userId = _userId;
             verifierUid = _verifierUid;
@@ -1096,7 +1122,7 @@
         void receiveVerificationResponse(int verificationId);
     }
 
-    private class IntentVerifierProxy implements IntentFilterVerifier<ActivityIntentInfo> {
+    private class IntentVerifierProxy implements IntentFilterVerifier<ParsedActivityIntentInfo> {
         private Context mContext;
         private ComponentName mIntentFilterVerifierComponent;
         private ArrayList<Integer> mCurrentIntentFilterVerifications = new ArrayList<>();
@@ -1121,11 +1147,11 @@
 
                 String packageName = ivs.getPackageName();
 
-                ArrayList<PackageParser.ActivityIntentInfo> filters = ivs.getFilters();
+                ArrayList<ParsedActivityIntentInfo> filters = ivs.getFilters();
                 final int filterCount = filters.size();
                 ArraySet<String> domainsSet = new ArraySet<>();
                 for (int m=0; m<filterCount; m++) {
-                    PackageParser.ActivityIntentInfo filter = filters.get(m);
+                    ParsedActivityIntentInfo filter = filters.get(m);
                     domainsSet.addAll(filter.getHostsList());
                 }
                 synchronized (mLock) {
@@ -1177,14 +1203,14 @@
 
             final boolean verified = ivs.isVerified();
 
-            ArrayList<PackageParser.ActivityIntentInfo> filters = ivs.getFilters();
+            ArrayList<ParsedActivityIntentInfo> filters = ivs.getFilters();
             final int count = filters.size();
             if (DEBUG_DOMAIN_VERIFICATION) {
                 Slog.i(TAG, "Received verification response " + verificationId
                         + " for " + count + " filters, verified=" + verified);
             }
             for (int n=0; n<count; n++) {
-                PackageParser.ActivityIntentInfo filter = filters.get(n);
+                ParsedActivityIntentInfo filter = filters.get(n);
                 filter.setVerified(verified);
 
                 if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "IntentFilter " + filter.toString()
@@ -1297,7 +1323,7 @@
 
         @Override
         public boolean addOneIntentFilterVerification(int verifierUid, int userId, int verificationId,
-                    ActivityIntentInfo filter, String packageName) {
+                ParsedActivityIntentInfo filter, String packageName) {
             if (!hasValidDomains(filter)) {
                 return false;
             }
@@ -1326,7 +1352,7 @@
         }
     }
 
-    private static boolean hasValidDomains(ActivityIntentInfo filter) {
+    private static boolean hasValidDomains(ParsedActivityIntentInfo filter) {
         return filter.hasCategory(Intent.CATEGORY_BROWSABLE)
                 && (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
                         filter.hasDataScheme(IntentFilter.SCHEME_HTTPS));
@@ -1593,7 +1619,7 @@
                         final List<String> whitelistedRestrictedPermissions = ((args.installFlags
                                 & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0
                                     && parentRes.pkg != null)
-                                ? parentRes.pkg.requestedPermissions
+                                ? parentRes.pkg.getRequestedPermissions()
                                 : args.whitelistedRestrictedPermissions;
 
                         // Handle the parent package
@@ -1739,8 +1765,8 @@
                 }
                 case START_INTENT_FILTER_VERIFICATIONS: {
                     IFVerificationParams params = (IFVerificationParams) msg.obj;
-                    verifyIntentFiltersIfNeeded(params.userId, params.verifierUid,
-                            params.replacing, params.pkg);
+                    verifyIntentFiltersIfNeeded(params.userId, params.verifierUid, params.replacing,
+                            params.packageName, params.hasDomainUrls, params.activities);
                     break;
                 }
                 case INTENT_FILTER_VERIFIED: {
@@ -1890,20 +1916,11 @@
                                     ? res.removedInfo.installerPackageName
                                     : null;
 
-            // If this is the first time we have child packages for a disabled privileged
-            // app that had no children, we grant requested runtime permissions to the new
-            // children if the parent on the system image had them already granted.
-            if (res.pkg.parentPackage != null) {
-                final int callingUid = Binder.getCallingUid();
-                mPermissionManager.grantRuntimePermissionsGrantedToDisabledPackage(
-                        res.pkg, callingUid);
-            }
-
             synchronized (mLock) {
                 mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers);
             }
 
-            final String packageName = res.pkg.applicationInfo.packageName;
+            final String packageName = res.pkg.getAppInfoPackageName();
 
             // Determine the set of users who are adding this package for
             // the first time vs. those who are seeing an update.
@@ -1912,7 +1929,7 @@
             int[] updateUserIds = EMPTY_INT_ARRAY;
             int[] instantUserIds = EMPTY_INT_ARRAY;
             final boolean allNewUsers = res.origUsers == null || res.origUsers.length == 0;
-            final PackageSetting ps = (PackageSetting) res.pkg.mExtras;
+            final PackageSetting ps = getPackageSetting(res.pkg.getPackageName());
             for (int newUser : res.newUsers) {
                 final boolean isInstantApp = ps.getInstantApp(newUser);
                 if (allNewUsers) {
@@ -1946,13 +1963,14 @@
             }
 
             // Send installed broadcasts if the package is not a static shared lib.
-            if (res.pkg.staticSharedLibName == null) {
-                mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(res.pkg.baseCodePath);
+            if (res.pkg.getStaticSharedLibName() == null) {
+                mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(
+                        res.pkg.getBaseCodePath());
 
                 // Send added for users that see the package for the first time
                 // sendPackageAddedForNewUsers also deals with system apps
                 int appId = UserHandle.getAppId(res.uid);
-                boolean isSystem = res.pkg.applicationInfo.isSystemApp();
+                boolean isSystem = res.pkg.isSystemApp();
                 sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
                         virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds);
 
@@ -2030,30 +2048,30 @@
                         final StorageManager storage = mInjector.getStorageManager();
                         VolumeInfo volume =
                                 storage.findVolumeByUuid(
-                                        res.pkg.applicationInfo.storageUuid.toString());
+                                        res.pkg.getStorageUuid().toString());
                         int packageExternalStorageType =
                                 getPackageExternalStorageType(volume, isExternal(res.pkg));
                         // If the package was installed externally, log it.
                         if (packageExternalStorageType != StorageEnums.UNKNOWN) {
                             StatsLog.write(StatsLog.APP_INSTALL_ON_EXTERNAL_STORAGE_REPORTED,
-                                    packageExternalStorageType, res.pkg.packageName);
+                                    packageExternalStorageType, res.pkg.getPackageName());
                         }
                     }
                     if (DEBUG_INSTALL) {
                         Slog.i(TAG, "upgrading pkg " + res.pkg + " is external");
                     }
-                    final int[] uidArray = new int[]{res.pkg.applicationInfo.uid};
+                    final int[] uidArray = new int[]{res.pkg.getUid()};
                     ArrayList<String> pkgList = new ArrayList<>(1);
                     pkgList.add(packageName);
                     sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null);
                 }
             } else if (!ArrayUtils.isEmpty(res.libraryConsumers)) { // if static shared lib
                 for (int i = 0; i < res.libraryConsumers.size(); i++) {
-                    PackageParser.Package pkg = res.libraryConsumers.get(i);
+                    AndroidPackage pkg = res.libraryConsumers.get(i);
                     // send broadcast that all consumers of the static shared library have changed
-                    sendPackageChangedBroadcast(pkg.packageName, false /* dontKillApp */,
-                            new ArrayList<>(Collections.singletonList(pkg.packageName)),
-                            pkg.applicationInfo.uid, null);
+                    sendPackageChangedBroadcast(pkg.getPackageName(), false /* dontKillApp */,
+                            new ArrayList<>(Collections.singletonList(pkg.getPackageName())),
+                            pkg.getUid(), null);
                 }
             }
 
@@ -2183,7 +2201,7 @@
 
     private void scheduleDeferredNoKillInstallObserver(PackageInstalledInfo info,
             IPackageInstallObserver2 observer) {
-        String packageName = info.pkg.packageName;
+        String packageName = info.pkg.getPackageName();
         mNoKillInstallObservers.put(packageName, Pair.create(info, observer));
         Message message = mHandler.obtainMessage(DEFERRED_NO_KILL_INSTALL_OBSERVER, packageName);
         mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS);
@@ -2360,6 +2378,37 @@
         PackageManagerService m = new PackageManagerService(injector, factoryTest, onlyCore);
         t.traceEnd(); // "create package manager"
 
+        injector.getCompatibility().registerListener(SELinuxMMAC.SELINUX_LATEST_CHANGES,
+                packageName -> {
+                    synchronized (m.mInstallLock) {
+                        final AndroidPackage pkg;
+                        final SharedUserSetting sharedUser;
+                        synchronized (m.mLock) {
+                            PackageSetting ps = m.mSettings.getPackageLPr(packageName);
+                            if (ps == null) {
+                                Slog.e(TAG, "Failed to find package setting " + packageName);
+                                return;
+                            }
+                            pkg = ps.pkg;
+                            sharedUser = ps.sharedUser;
+                        }
+
+                        if (pkg == null) {
+                            Slog.e(TAG, "Failed to find package " + packageName);
+                            return;
+                        }
+                        final String newSeInfo = SELinuxMMAC.getSeInfo(pkg, sharedUser,
+                                m.mInjector.getCompatibility());
+
+                        if (!newSeInfo.equals(pkg.getSeInfo())) {
+                            Slog.i(TAG, "Updating seInfo for package " + packageName + " from: "
+                                    + pkg.getSeInfo() + " to: " + newSeInfo);
+                            pkg.mutate().setSeInfo(newSeInfo);
+                            m.prepareAppDataAfterInstallLIF(pkg);
+                        }
+                    }
+                });
+
         m.installWhitelistedSystemPackages();
         ServiceManager.addService("package", m);
         final PackageManagerNative pmn = m.new PackageManagerNative();
@@ -2417,7 +2466,7 @@
     }
 
     @VisibleForTesting(visibility = Visibility.PRIVATE)
-    static class SystemPartition {
+    public static class SystemPartition {
         public final File folder;
         public final int scanFlag;
         public final File appFolder;
@@ -2509,6 +2558,8 @@
         mPermissionManager = injector.getPermissionManagerServiceInternal();
         mSettings = injector.getSettings();
         mPermissionManagerService = (IPermissionManager) ServiceManager.getService("permissionmgr");
+        mIncrementalManager =
+                (IncrementalManager) mContext.getSystemService(Context.INCREMENTAL_SERVICE);
 
         // CHECKSTYLE:ON IndentationCheck
         t.traceEnd();
@@ -2567,7 +2618,7 @@
 
         mProtectedPackages = new ProtectedPackages(mContext);
 
-        mApexManager = ApexManager.create(mContext);
+        mApexManager = ApexManager.getInstance();
         mAppsFilter = mInjector.getAppsFilter();
 
         mDirsToScanAsSystem = new ArrayList<>();
@@ -2745,11 +2796,11 @@
             final List<String> stubSystemApps = new ArrayList<>();
             if (!mOnlyCore) {
                 // do this first before mucking with mPackages for the "expecting better" case
-                final Iterator<PackageParser.Package> pkgIterator = mPackages.values().iterator();
+                final Iterator<AndroidPackage> pkgIterator = mPackages.values().iterator();
                 while (pkgIterator.hasNext()) {
-                    final PackageParser.Package pkg = pkgIterator.next();
-                    if (pkg.isStub) {
-                        stubSystemApps.add(pkg.packageName);
+                    final AndroidPackage pkg = pkgIterator.next();
+                    if (pkg.isStub()) {
+                        stubSystemApps.add(pkg.getPackageName());
                     }
                 }
 
@@ -2768,7 +2819,7 @@
                     /*
                      * If the package is scanned, it's not erased.
                      */
-                    final PackageParser.Package scannedPkg = mPackages.get(ps.name);
+                    final AndroidPackage scannedPkg = mPackages.get(ps.name);
                     if (scannedPkg != null) {
                         /*
                          * If the system app is both scanned and in the
@@ -2845,7 +2896,7 @@
                 // app completely. Otherwise, revoke their system privileges.
                 for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) {
                     final String packageName = possiblyDeletedUpdatedSystemApps.get(i);
-                    final PackageParser.Package pkg = mPackages.get(packageName);
+                    final AndroidPackage pkg = mPackages.get(packageName);
                     final String msg;
 
                     // remove from the disabled system list; do this first so any future
@@ -2871,7 +2922,7 @@
                         // special privileges
                         removePackageLI(pkg, true);
                         try {
-                            final File codePath = new File(pkg.applicationInfo.getCodePath());
+                            final File codePath = new File(pkg.getAppInfoCodePath());
                             scanPackageTracedLI(codePath, 0, scanFlags, 0, null);
                         } catch (PackageManagerException e) {
                             Slog.e(TAG, "Failed to parse updated, ex-system package: "
@@ -3067,7 +3118,7 @@
                 }
                 int count = 0;
                 for (String pkgName : deferPackages) {
-                    PackageParser.Package pkg = null;
+                    AndroidPackage pkg = null;
                     synchronized (mLock) {
                         PackageSetting ps = mSettings.getPackageLPr(pkgName);
                         if (ps != null && ps.getInstalled(UserHandle.USER_SYSTEM)) {
@@ -3167,12 +3218,12 @@
 
             // Initialize InstantAppRegistry's Instant App list for all users.
             final int[] userIds = UserManagerService.getInstance().getUserIds();
-            for (PackageParser.Package pkg : mPackages.values()) {
+            for (AndroidPackage pkg : mPackages.values()) {
                 if (pkg.isSystem()) {
                     continue;
                 }
                 for (int userId : userIds) {
-                    final PackageSetting ps = (PackageSetting) pkg.mExtras;
+                    final PackageSetting ps = getPackageSetting(pkg.getPackageName());
                     if (ps == null || !ps.getInstantApp(userId) || !ps.getInstalled(userId)) {
                         continue;
                     }
@@ -3259,7 +3310,7 @@
                 continue;
             }
             // skip if the package isn't installed (?!); this should never happen
-            final PackageParser.Package pkg = mPackages.get(packageName);
+            final AndroidPackage pkg = mPackages.get(packageName);
             if (pkg == null) {
                 systemStubPackageNames.remove(i);
                 continue;
@@ -3303,43 +3354,46 @@
      * APK will be installed and the package will be disabled. To recover from this situation,
      * the user will need to go into system settings and re-enable the package.
      */
-    private boolean enableCompressedPackage(PackageParser.Package stubPkg) {
+    private boolean enableCompressedPackage(AndroidPackage stubPkg) {
         final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
                 | PackageParser.PARSE_ENFORCE_CODE;
         synchronized (mInstallLock) {
-            final PackageParser.Package pkg;
+            final AndroidPackage pkg;
             try (PackageFreezer freezer =
-                    freezePackage(stubPkg.packageName, "setEnabledSetting")) {
+                    freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) {
                 pkg = installStubPackageLI(stubPkg, parseFlags, 0 /*scanFlags*/);
                 synchronized (mLock) {
                     prepareAppDataAfterInstallLIF(pkg);
                     try {
-                        updateSharedLibrariesLocked(pkg, null, mPackages);
+                        updateSharedLibrariesLocked(pkg, null,
+                                Collections.unmodifiableMap(mPackages));
                     } catch (PackageManagerException e) {
                         Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e);
                     }
-                    mPermissionManager.updatePermissions(pkg.packageName, pkg);
+                    mPermissionManager.updatePermissions(pkg.getPackageName(), pkg);
                     mSettings.writeLPr();
                 }
             } catch (PackageManagerException e) {
                 // Whoops! Something went very wrong; roll back to the stub and disable the package
                 try (PackageFreezer freezer =
-                        freezePackage(stubPkg.packageName, "setEnabledSetting")) {
+                        freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) {
                     synchronized (mLock) {
                         // NOTE: Ensure the system package is enabled; even for a compressed stub.
                         // If we don't, installing the system package fails during scan
                         enableSystemPackageLPw(stubPkg);
                     }
-                    installPackageFromSystemLIF(stubPkg.codePath,
+                    installPackageFromSystemLIF(stubPkg.getCodePath(),
                             null /*allUserHandles*/, null /*origUserHandles*/,
                             null /*origPermissionsState*/, true /*writeSettings*/);
                 } catch (PackageManagerException pme) {
                     // Serious WTF; we have to be able to install the stub
-                    Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.packageName, pme);
+                    Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.getPackageName(),
+                            pme);
                 } finally {
                     // Disable the package; the stub by itself is not runnable
                     synchronized (mLock) {
-                        final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.packageName);
+                        final PackageSetting stubPs = mSettings.mPackages.get(
+                                stubPkg.getPackageName());
                         if (stubPs != null) {
                             stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED,
                                     UserHandle.USER_SYSTEM, "android");
@@ -3351,31 +3405,33 @@
             }
             clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
                     | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
-            mDexManager.notifyPackageUpdated(pkg.packageName,
-                    pkg.baseCodePath, pkg.splitCodePaths);
+            mDexManager.notifyPackageUpdated(pkg.getPackageName(),
+                    pkg.getBaseCodePath(), pkg.getSplitCodePaths());
         }
         return true;
     }
 
-    private PackageParser.Package installStubPackageLI(PackageParser.Package stubPkg,
+    private AndroidPackage installStubPackageLI(AndroidPackage stubPkg,
             @ParseFlags int parseFlags, @ScanFlags int scanFlags)
                     throws PackageManagerException {
         if (DEBUG_COMPRESSION) {
-            Slog.i(TAG, "Uncompressing system stub; pkg: " + stubPkg.packageName);
+            Slog.i(TAG, "Uncompressing system stub; pkg: " + stubPkg.getPackageName());
         }
         // uncompress the binary to its eventual destination on /data
-        final File scanFile = decompressPackage(stubPkg.packageName, stubPkg.codePath);
+        final File scanFile = decompressPackage(stubPkg.getPackageName(), stubPkg.getCodePath());
         if (scanFile == null) {
-            throw new PackageManagerException("Unable to decompress stub at " + stubPkg.codePath);
+            throw new PackageManagerException(
+                    "Unable to decompress stub at " + stubPkg.getCodePath());
         }
         synchronized (mLock) {
-            mSettings.disableSystemPackageLPw(stubPkg.packageName, true /*replaced*/);
+            mSettings.disableSystemPackageLPw(stubPkg.getPackageName(), true /*replaced*/);
         }
         removePackageLI(stubPkg, true /*chatty*/);
         try {
             return scanPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null);
         } catch (PackageManagerException e) {
-            Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.packageName, e);
+            Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.getPackageName(),
+                    e);
             // Remove the failed install
             removeCodePathLI(scanFile);
             throw e;
@@ -3458,18 +3514,20 @@
     }
 
     private static @Nullable File preparePackageParserCache() {
-        if (!DEFAULT_PACKAGE_PARSER_CACHE_ENABLED) {
-            return null;
-        }
+        if (!FORCE_PACKAGE_PARSED_CACHE_ENABLED) {
+            if (!DEFAULT_PACKAGE_PARSER_CACHE_ENABLED) {
+                return null;
+            }
 
-        // Disable package parsing on eng builds to allow for faster incremental development.
-        if (Build.IS_ENG) {
-            return null;
-        }
+            // Disable package parsing on eng builds to allow for faster incremental development.
+            if (Build.IS_ENG) {
+                return null;
+            }
 
-        if (SystemProperties.getBoolean("pm.boot.disable_package_cache", false)) {
-            Slog.i(TAG, "Disabling package parser cache due to system property.");
-            return null;
+            if (SystemProperties.getBoolean("pm.boot.disable_package_cache", false)) {
+                Slog.i(TAG, "Disabling package parser cache due to system property.");
+                return null;
+            }
         }
 
         // The base directory for the package parser cache lives under /data/system/.
@@ -3481,10 +3539,12 @@
         // There are several items that need to be combined together to safely
         // identify cached items. In particular, changing the value of certain
         // feature flags should cause us to invalidate any caches.
-        final String cacheName = SystemProperties.digestOf(
-                "ro.build.fingerprint",
-                StorageManager.PROP_ISOLATED_STORAGE,
-                StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT);
+        final String cacheName = FORCE_PACKAGE_PARSED_CACHE_ENABLED ? "debug"
+                : SystemProperties.digestOf(
+                        "ro.build.fingerprint",
+                        StorageManager.PROP_ISOLATED_STORAGE,
+                        StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT
+                );
 
         // Reconcile cache directories, keeping only what we'd actually use.
         for (File cacheDir : FileUtils.listFilesOrEmpty(cacheBaseDir)) {
@@ -3808,7 +3868,7 @@
         ArraySet<String> packages = systemConfig.getLinkedApps();
 
         for (String packageName : packages) {
-            PackageParser.Package pkg = mPackages.get(packageName);
+            AndroidPackage pkg = mPackages.get(packageName);
             if (pkg != null) {
                 if (!pkg.isSystem()) {
                     Slog.w(TAG, "Non-system app '" + packageName + "' in sysconfig <app-link>");
@@ -3816,13 +3876,15 @@
                 }
 
                 ArraySet<String> domains = null;
-                for (PackageParser.Activity a : pkg.activities) {
-                    for (ActivityIntentInfo filter : a.intents) {
-                        if (hasValidDomains(filter)) {
-                            if (domains == null) {
-                                domains = new ArraySet<>();
+                if (pkg.getActivities() != null) {
+                    for (ParsedActivity a : pkg.getActivities()) {
+                        for (ParsedActivityIntentInfo filter : a.intents) {
+                            if (hasValidDomains(filter)) {
+                                if (domains == null) {
+                                    domains = new ArraySet<>();
+                                }
+                                domains.addAll(filter.getHostsList());
                             }
-                            domains.addAll(filter.getHostsList());
                         }
                     }
                 }
@@ -3938,7 +4000,7 @@
         }
 
         final PackageUserState state = ps.readUserState(userId);
-        PackageParser.Package p = ps.pkg;
+        AndroidPackage p = ps.pkg;
         if (p != null) {
             final PermissionsState permissionsState = ps.getPermissionsState();
 
@@ -3946,10 +4008,10 @@
             final int[] gids = (flags & PackageManager.GET_GIDS) == 0
                     ? EMPTY_INT_ARRAY : permissionsState.computeGids(userId);
             // Compute granted permissions only if package has requested permissions
-            final Set<String> permissions = ArrayUtils.isEmpty(p.requestedPermissions)
+            final Set<String> permissions = ArrayUtils.isEmpty(p.getRequestedPermissions())
                     ? Collections.emptySet() : permissionsState.getPermissions(userId);
 
-            PackageInfo packageInfo = PackageParser.generatePackageInfo(p, gids, flags,
+            PackageInfo packageInfo = PackageInfoUtils.generate(p, gids, flags,
                     ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId);
 
             if (packageInfo == null) {
@@ -4012,7 +4074,7 @@
                 throw new SecurityException("Package " + packageName + " is currently frozen!");
             }
 
-            if (!userKeyUnlocked && !ps.pkg.applicationInfo.isEncryptionAware()) {
+            if (!userKeyUnlocked && !ps.pkg.isEncryptionAware()) {
                 throw new SecurityException("Package " + packageName + " is not encryption aware!");
             }
         }
@@ -4025,9 +4087,9 @@
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /*requireFullPermission*/, false /*checkShell*/, "is package available");
         synchronized (mLock) {
-            PackageParser.Package p = mPackages.get(packageName);
+            AndroidPackage p = mPackages.get(packageName);
             if (p != null) {
-                final PackageSetting ps = (PackageSetting) p.mExtras;
+                final PackageSetting ps = getPackageSetting(p.getPackageName());
                 if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                     return false;
                 }
@@ -4092,21 +4154,22 @@
                 }
             }
 
-            PackageParser.Package p = mPackages.get(packageName);
+            AndroidPackage p = mPackages.get(packageName);
             if (matchFactoryOnly && p != null && !isSystemApp(p)) {
                 return null;
             }
             if (DEBUG_PACKAGE_INFO)
                 Log.v(TAG, "getPackageInfo " + packageName + ": " + p);
             if (p != null) {
-                final PackageSetting ps = (PackageSetting) p.mExtras;
+                final PackageSetting ps = getPackageSetting(p.getPackageName());
                 if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
                     return null;
                 }
                 if (ps != null && shouldFilterApplicationLocked(ps, filterCallingUid, userId)) {
                     return null;
                 }
-                return generatePackageInfo((PackageSetting)p.mExtras, flags, userId);
+
+                return generatePackageInfo(ps, flags, userId);
             }
             if (!matchFactoryOnly && (flags & MATCH_KNOWN_PACKAGES) != 0) {
                 final PackageSetting ps = mSettings.mPackages.get(packageName);
@@ -4142,34 +4205,34 @@
     private boolean isComponentVisibleToInstantApp(
             @Nullable ComponentName component, @ComponentType int type) {
         if (type == TYPE_ACTIVITY) {
-            final PackageParser.Activity activity = mComponentResolver.getActivity(component);
+            final ParsedActivity activity = mComponentResolver.getActivity(component);
             if (activity == null) {
                 return false;
             }
             final boolean visibleToInstantApp =
-                    (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
+                    (activity.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
             final boolean explicitlyVisibleToInstantApp =
-                    (activity.info.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
+                    (activity.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
             return visibleToInstantApp && explicitlyVisibleToInstantApp;
         } else if (type == TYPE_RECEIVER) {
-            final PackageParser.Activity activity = mComponentResolver.getReceiver(component);
+            final ParsedActivity activity = mComponentResolver.getReceiver(component);
             if (activity == null) {
                 return false;
             }
             final boolean visibleToInstantApp =
-                    (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
+                    (activity.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
             final boolean explicitlyVisibleToInstantApp =
-                    (activity.info.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
+                    (activity.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
             return visibleToInstantApp && !explicitlyVisibleToInstantApp;
         } else if (type == TYPE_SERVICE) {
-            final PackageParser.Service service = mComponentResolver.getService(component);
+            final ParsedService service = mComponentResolver.getService(component);
             return service != null
-                    ? (service.info.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
+                    ? (service.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
                     : false;
         } else if (type == TYPE_PROVIDER) {
-            final PackageParser.Provider provider = mComponentResolver.getProvider(component);
+            final ParsedProvider provider = mComponentResolver.getProvider(component);
             return provider != null
-                    ? (provider.info.flags & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
+                    ? (provider.getFlags() & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
                     : false;
         } else if (type == TYPE_UNKNOWN) {
             return isComponentVisibleToInstantApp(component);
@@ -4213,16 +4276,16 @@
             // request for a specific component; if it hasn't been explicitly exposed through
             // property or instrumentation target, filter
             if (component != null) {
-                final PackageParser.Instrumentation instrumentation =
+                final ParsedInstrumentation instrumentation =
                         mInstrumentation.get(component);
                 if (instrumentation != null
-                        && isCallerSameApp(instrumentation.info.targetPackage, callingUid)) {
+                        && isCallerSameApp(instrumentation.getTargetPackage(), callingUid)) {
                     return false;
                 }
                 return !isComponentVisibleToInstantApp(component, componentType);
             }
             // request for application; if no components have been explicitly exposed, filter
-            return !ps.pkg.visibleToInstantApps;
+            return !ps.pkg.isVisibleToInstantApps();
         }
         if (ps.getInstantApp(userId)) {
             // caller can see all components of all instant applications, don't filter
@@ -4271,12 +4334,12 @@
         }
 
         // No package means no static lib as it is always on internal storage
-        if (ps == null || ps.pkg == null || !ps.pkg.applicationInfo.isStaticSharedLibrary()) {
+        if (ps == null || ps.pkg == null || !ps.pkg.isStaticSharedLibrary()) {
             return false;
         }
 
-        final SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(ps.pkg.staticSharedLibName,
-                ps.pkg.staticSharedLibVersion);
+        final SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(
+                ps.pkg.getStaticSharedLibName(), ps.pkg.getStaticSharedLibVersion());
         if (libraryInfo == null) {
             return false;
         }
@@ -4298,7 +4361,8 @@
                 if (index < 0) {
                     continue;
                 }
-                if (uidPs.pkg.usesStaticLibrariesVersions[index] == libraryInfo.getLongVersion()) {
+                if (uidPs.pkg.getUsesStaticLibrariesVersions()[index]
+                        == libraryInfo.getLongVersion()) {
                     return false;
                 }
             }
@@ -4372,13 +4436,13 @@
 
         // reader
         synchronized (mLock) {
-            final PackageParser.Package p = mPackages.get(packageName);
+            final AndroidPackage p = mPackages.get(packageName);
             if (p != null && p.isMatch(flags)) {
-                PackageSetting ps = (PackageSetting) p.mExtras;
+                PackageSetting ps = getPackageSetting(p.getPackageName());
                 if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                     return -1;
                 }
-                return UserHandle.getUid(userId, p.applicationInfo.uid);
+                return UserHandle.getUid(userId, p.getUid());
             }
             if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
                 final PackageSetting ps = mSettings.mPackages.get(packageName);
@@ -4402,9 +4466,9 @@
 
         // reader
         synchronized (mLock) {
-            final PackageParser.Package p = mPackages.get(packageName);
+            final AndroidPackage p = mPackages.get(packageName);
             if (p != null && p.isMatch(flags)) {
-                PackageSetting ps = (PackageSetting) p.mExtras;
+                PackageSetting ps = getPackageSetting(p.getPackageName());
                 if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                     return null;
                 }
@@ -4454,7 +4518,7 @@
                 }
                 return null;
             }
-            ApplicationInfo ai = PackageParser.generateApplicationInfo(ps.pkg, flags,
+            ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(ps.pkg, flags,
                     ps.readUserState(userId), userId);
             if (ai != null) {
                 ai.packageName = resolveExternalPackageNameLPr(ps.pkg);
@@ -4492,7 +4556,7 @@
             packageName = resolveInternalPackageNameLPr(packageName,
                     PackageManager.VERSION_CODE_HIGHEST);
 
-            PackageParser.Package p = mPackages.get(packageName);
+            AndroidPackage p = mPackages.get(packageName);
             if (DEBUG_PACKAGE_INFO) Log.v(
                     TAG, "getApplicationInfo " + packageName
                     + ": " + p);
@@ -4506,7 +4570,7 @@
                     return null;
                 }
                 // Note: isEnabledLP() does not apply here - always return info
-                ApplicationInfo ai = PackageParser.generateApplicationInfo(
+                ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(
                         p, flags, ps.readUserState(userId), userId);
                 if (ai != null) {
                     ai.packageName = resolveExternalPackageNameLPr(p);
@@ -4878,17 +4942,19 @@
         }
 
         synchronized (mLock) {
-            PackageParser.Activity a = mComponentResolver.getActivity(component);
+            ParsedActivity a = mComponentResolver.getActivity(component);
 
             if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);
-            if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
+
+            AndroidPackage pkg = a == null ? null : mPackages.get(a.getPackageName());
+            if (pkg != null && mSettings.isEnabledAndMatchLPr(pkg, a, flags, userId)) {
                 PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                 if (ps == null) return null;
                 if (shouldFilterApplicationLocked(
                         ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) {
                     return null;
                 }
-                return PackageParser.generateActivityInfo(
+                return PackageInfoUtils.generateActivityInfo(pkg,
                         a, flags, ps.readUserState(userId), userId);
             }
             if (mResolveComponentName.equals(component)) {
@@ -4925,7 +4991,7 @@
             }
             final int callingUid = Binder.getCallingUid();
             final int callingUserId = UserHandle.getUserId(callingUid);
-            PackageParser.Activity a = mComponentResolver.getActivity(component);
+            ParsedActivity a = mComponentResolver.getActivity(component);
             if (a == null) {
                 return false;
             }
@@ -4955,17 +5021,27 @@
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /* requireFullPermission */, false /* checkShell */, "get receiver info");
         synchronized (mLock) {
-            PackageParser.Activity a = mComponentResolver.getReceiver(component);
+            ParsedActivity a = mComponentResolver.getReceiver(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
                 TAG, "getReceiverInfo " + component + ": " + a);
-            if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
+
+            if (a == null) {
+                return null;
+            }
+
+            AndroidPackage pkg = mPackages.get(a.getPackageName());
+            if (pkg == null) {
+                return null;
+            }
+
+            if (mSettings.isEnabledAndMatchLPr(pkg, a, flags, userId)) {
                 PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                 if (ps == null) return null;
                 if (shouldFilterApplicationLocked(
                         ps, callingUid, component, TYPE_RECEIVER, userId)) {
                     return null;
                 }
-                return PackageParser.generateActivityInfo(
+                return PackageInfoUtils.generateActivityInfo(pkg,
                         a, flags, ps.readUserState(userId), userId);
             }
         }
@@ -5144,13 +5220,13 @@
                 }
                 // If the dependent is a static shared lib, use the public package name
                 String dependentPackageName = ps.name;
-                if (ps.pkg != null && ps.pkg.applicationInfo.isStaticSharedLibrary()) {
-                    dependentPackageName = ps.pkg.manifestPackageName;
+                if (ps.pkg != null && ps.pkg.isStaticSharedLibrary()) {
+                    dependentPackageName = ps.pkg.getManifestPackageName();
                 }
                 versionedPackages.add(new VersionedPackage(dependentPackageName, ps.versionCode));
             } else if (ps.pkg != null) {
-                if (ArrayUtils.contains(ps.pkg.usesLibraries, libName)
-                        || ArrayUtils.contains(ps.pkg.usesOptionalLibraries, libName)) {
+                if (ArrayUtils.contains(ps.pkg.getUsesLibraries(), libName)
+                        || ArrayUtils.contains(ps.pkg.getUsesOptionalLibraries(), libName)) {
                     if (versionedPackages == null) {
                         versionedPackages = new ArrayList<>();
                     }
@@ -5170,17 +5246,22 @@
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /* requireFullPermission */, false /* checkShell */, "get service info");
         synchronized (mLock) {
-            PackageParser.Service s = mComponentResolver.getService(component);
+            ParsedService s = mComponentResolver.getService(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
-                TAG, "getServiceInfo " + component + ": " + s);
-            if (s != null && mSettings.isEnabledAndMatchLPr(s.info, flags, userId)) {
+                    TAG, "getServiceInfo " + component + ": " + s);
+            if (s == null) {
+                return null;
+            }
+
+            AndroidPackage pkg = mPackages.get(s.getPackageName());
+            if (mSettings.isEnabledAndMatchLPr(pkg, s, flags, userId)) {
                 PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                 if (ps == null) return null;
                 if (shouldFilterApplicationLocked(
                         ps, callingUid, component, TYPE_SERVICE, userId)) {
                     return null;
                 }
-                return PackageParser.generateServiceInfo(
+                return PackageInfoUtils.generateServiceInfo(pkg,
                         s, flags, ps.readUserState(userId), userId);
             }
         }
@@ -5195,18 +5276,27 @@
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /* requireFullPermission */, false /* checkShell */, "get provider info");
         synchronized (mLock) {
-            PackageParser.Provider p = mComponentResolver.getProvider(component);
+            ParsedProvider p = mComponentResolver.getProvider(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
-                TAG, "getProviderInfo " + component + ": " + p);
-            if (p != null && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) {
+                    TAG, "getProviderInfo " + component + ": " + p);
+            if (p == null) {
+                return null;
+            }
+
+            AndroidPackage pkg = mPackages.get(p.getPackageName());
+            if (pkg == null) {
+                return null;
+            }
+
+            if (mSettings.isEnabledAndMatchLPr(pkg, p, flags, userId)) {
                 PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                 if (ps == null) return null;
                 if (shouldFilterApplicationLocked(
                         ps, callingUid, component, TYPE_PROVIDER, userId)) {
                     return null;
                 }
-                return PackageParser.generateProviderInfo(
-                        p, flags, ps.readUserState(userId), userId);
+                PackageUserState state = ps.readUserState(userId);
+                return PackageInfoUtils.generateProviderInfo(pkg, p, flags, state, userId);
             }
         }
         return null;
@@ -5464,21 +5554,21 @@
     @Override
     public int checkSignatures(String pkg1, String pkg2) {
         synchronized (mLock) {
-            final PackageParser.Package p1 = mPackages.get(pkg1);
-            final PackageParser.Package p2 = mPackages.get(pkg2);
-            if (p1 == null || p1.mExtras == null
-                    || p2 == null || p2.mExtras == null) {
+            final AndroidPackage p1 = mPackages.get(pkg1);
+            final AndroidPackage p2 = mPackages.get(pkg2);
+            final PackageSetting ps1 = p1 == null ? null : getPackageSetting(p1.getPackageName());
+            final PackageSetting ps2 = p2 == null ? null : getPackageSetting(p2.getPackageName());
+            if (p1 == null || ps1 == null || p2 == null || ps2 == null) {
                 return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
             }
             final int callingUid = Binder.getCallingUid();
             final int callingUserId = UserHandle.getUserId(callingUid);
-            final PackageSetting ps1 = (PackageSetting) p1.mExtras;
-            final PackageSetting ps2 = (PackageSetting) p2.mExtras;
             if (shouldFilterApplicationLocked(ps1, callingUid, callingUserId)
                     || shouldFilterApplicationLocked(ps2, callingUid, callingUserId)) {
                 return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
             }
-            return compareSignatures(p1.mSigningDetails.signatures, p2.mSigningDetails.signatures);
+            return compareSignatures(p1.getSigningDetails().signatures,
+                    p2.getSigningDetails().signatures);
         }
     }
 
@@ -5541,21 +5631,21 @@
             String packageName, byte[] certificate, @PackageManager.CertificateInputType int type) {
 
         synchronized (mLock) {
-            final PackageParser.Package p = mPackages.get(packageName);
-            if (p == null || p.mExtras == null) {
+            final AndroidPackage p = mPackages.get(packageName);
+            final PackageSetting ps = getPackageSetting(p.getPackageName());
+            if (p == null || ps == null) {
                 return false;
             }
             final int callingUid = Binder.getCallingUid();
             final int callingUserId = UserHandle.getUserId(callingUid);
-            final PackageSetting ps = (PackageSetting) p.mExtras;
             if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
                 return false;
             }
             switch (type) {
                 case CERT_INPUT_RAW_X509:
-                    return p.mSigningDetails.hasCertificate(certificate);
+                    return p.getSigningDetails().hasCertificate(certificate);
                 case CERT_INPUT_SHA256:
-                    return p.mSigningDetails.hasSha256Certificate(certificate);
+                    return p.getSigningDetails().hasSha256Certificate(certificate);
                 default:
                     return false;
             }
@@ -5608,16 +5698,16 @@
      * external storage) is less than the version where package signatures
      * were updated, return true.
      */
-    private boolean isCompatSignatureUpdateNeeded(PackageParser.Package scannedPkg) {
-        return isCompatSignatureUpdateNeeded(getSettingsVersionForPackage(scannedPkg));
+    private boolean isCompatSignatureUpdateNeeded(AndroidPackage pkg) {
+        return isCompatSignatureUpdateNeeded(getSettingsVersionForPackage(pkg));
     }
 
     private static boolean isCompatSignatureUpdateNeeded(VersionInfo ver) {
         return ver.databaseVersion < DatabaseVersion.SIGNATURE_END_ENTITY;
     }
 
-    private boolean isRecoverSignatureUpdateNeeded(PackageParser.Package scannedPkg) {
-        return isRecoverSignatureUpdateNeeded(getSettingsVersionForPackage(scannedPkg));
+    private boolean isRecoverSignatureUpdateNeeded(AndroidPackage pkg) {
+        return isRecoverSignatureUpdateNeeded(getSettingsVersionForPackage(pkg));
     }
 
     private static boolean isRecoverSignatureUpdateNeeded(VersionInfo ver) {
@@ -5636,24 +5726,23 @@
             final List<String> result = new ArrayList<>();
             if (instantAppPkgName != null) {
                 // caller is an instant application; filter unexposed applications
-                for (PackageParser.Package pkg : mPackages.values()) {
-                    if (!pkg.visibleToInstantApps) {
+                for (AndroidPackage pkg : mPackages.values()) {
+                    if (!pkg.isVisibleToInstantApps()) {
                         continue;
                     }
-                    result.add(pkg.packageName);
+                    result.add(pkg.getPackageName());
                 }
             } else {
                 // caller is a normal application; filter instant applications
-                for (PackageParser.Package pkg : mPackages.values()) {
-                    final PackageSetting ps =
-                            pkg.mExtras != null ? (PackageSetting) pkg.mExtras : null;
+                for (AndroidPackage pkg : mPackages.values()) {
+                    final PackageSetting ps = getPackageSetting(pkg.getPackageName());
                     if (ps != null
                             && ps.getInstantApp(callingUserId)
                             && !mInstantAppRegistry.isInstantAccessGranted(
                                     callingUserId, UserHandle.getAppId(callingUid), ps.appId)) {
                         continue;
                     }
-                    result.add(pkg.packageName);
+                    result.add(pkg.getPackageName());
                 }
             }
             return result;
@@ -6497,7 +6586,7 @@
             if (obj instanceof PackageSetting) {
                 final PackageSetting ps = (PackageSetting) obj;
                 final boolean isInstantApp = ps.getInstantApp(UserHandle.getUserId(callingUid));
-                return isInstantApp ? ps.pkg.packageName : null;
+                return isInstantApp ? ps.pkg.getPackageName() : null;
             }
         }
         return null;
@@ -6569,9 +6658,11 @@
                     list.add(ri);
                 }
             }
-            return applyPostResolutionFilter(
+
+            List<ResolveInfo> result = applyPostResolutionFilter(
                     list, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart,
                     userId, intent);
+            return result;
         }
 
         // reader
@@ -6648,11 +6739,11 @@
                     sortResult = true;
                 }
             } else {
-                final PackageParser.Package pkg = mPackages.get(pkgName);
+                final AndroidPackage pkg = mPackages.get(pkgName);
                 result = null;
                 if (pkg != null) {
                     result = filterIfNotSystemUser(mComponentResolver.queryActivities(
-                            intent, resolvedType, flags, pkg.activities, userId), userId);
+                            intent, resolvedType, flags, pkg.getActivities(), userId), userId);
                 }
                 if (result == null || result.size() == 0) {
                     // the caller wants to resolve for a particular package; however, there
@@ -7546,10 +7637,10 @@
                         result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId,
                         intent);
             }
-            final PackageParser.Package pkg = mPackages.get(pkgName);
+            final AndroidPackage pkg = mPackages.get(pkgName);
             if (pkg != null) {
                 final List<ResolveInfo> result = mComponentResolver.queryReceivers(
-                        intent, resolvedType, flags, pkg.receivers, userId);
+                        intent, resolvedType, flags, pkg.getReceivers(), userId);
                 if (result == null) {
                     return Collections.emptyList();
                 }
@@ -7655,10 +7746,10 @@
                         resolveInfos,
                         instantAppPkgName);
             }
-            final PackageParser.Package pkg = mPackages.get(pkgName);
+            final AndroidPackage pkg = mPackages.get(pkgName);
             if (pkg != null) {
                 final List<ResolveInfo> resolveInfos = mComponentResolver.queryServices(intent,
-                        resolvedType, flags, pkg.services,
+                        resolvedType, flags, pkg.getServices(),
                         userId);
                 if (resolveInfos == null) {
                     return Collections.emptyList();
@@ -7782,11 +7873,11 @@
                         resolveInfos,
                         instantAppPkgName);
             }
-            final PackageParser.Package pkg = mPackages.get(pkgName);
+            final AndroidPackage pkg = mPackages.get(pkgName);
             if (pkg != null) {
                 final List<ResolveInfo> resolveInfos = mComponentResolver.queryProviders(intent,
                         resolvedType, flags,
-                        pkg.providers, userId);
+                        pkg.getProviders(), userId);
                 if (resolveInfos == null) {
                     return Collections.emptyList();
                 }
@@ -7876,16 +7967,15 @@
                 }
             } else {
                 list = new ArrayList<>(mPackages.size());
-                for (PackageParser.Package p : mPackages.values()) {
-                    final PackageSetting ps = (PackageSetting) p.mExtras;
+                for (AndroidPackage p : mPackages.values()) {
+                    final PackageSetting ps = getPackageSetting(p.getPackageName());
                     if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
                         continue;
                     }
                     if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                         continue;
                     }
-                    final PackageInfo pi = generatePackageInfo((PackageSetting)
-                            p.mExtras, flags, userId);
+                    final PackageInfo pi = generatePackageInfo(ps, flags, userId);
                     if (pi != null) {
                         list.add(pi);
                     }
@@ -7964,8 +8054,8 @@
                             userId);
                 }
             } else {
-                for (PackageParser.Package pkg : mPackages.values()) {
-                    PackageSetting ps = (PackageSetting)pkg.mExtras;
+                for (AndroidPackage pkg : mPackages.values()) {
+                    PackageSetting ps = getPackageSetting(pkg.getPackageName());
                     if (ps != null) {
                         addPackageHoldingPermissions(list, ps, permissions, tmpBools, flags,
                                 userId);
@@ -8018,7 +8108,7 @@
                         if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                             continue;
                         }
-                        ai = PackageParser.generateApplicationInfo(ps.pkg, effectiveFlags,
+                        ai = PackageInfoUtils.generateApplicationInfo(ps.pkg, effectiveFlags,
                                 ps.readUserState(userId), userId);
                         if (ai != null) {
                             ai.packageName = resolveExternalPackageNameLPr(ps.pkg);
@@ -8035,16 +8125,16 @@
                 }
             } else {
                 list = new ArrayList<>(mPackages.size());
-                for (PackageParser.Package p : mPackages.values()) {
-                    if (p.mExtras != null) {
-                        PackageSetting ps = (PackageSetting) p.mExtras;
+                for (AndroidPackage p : mPackages.values()) {
+                    final PackageSetting ps = getPackageSetting(p.getPackageName());
+                    if (ps != null) {
                         if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) {
                             continue;
                         }
                         if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                             continue;
                         }
-                        ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
+                        ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(p, flags,
                                 ps.readUserState(userId), userId);
                         if (ai != null) {
                             ai.packageName = resolveExternalPackageNameLPr(p);
@@ -8100,7 +8190,6 @@
                 callingUid = mIsolatedOwners.get(callingUid);
             }
             final PackageSetting ps = mSettings.mPackages.get(packageName);
-            PackageParser.Package pkg = mPackages.get(packageName);
             final boolean returnAllowed =
                     ps != null
                     && (isCallerSameApp(packageName, callingUid)
@@ -8171,9 +8260,9 @@
     }
 
     private boolean isCallerSameApp(String packageName, int uid) {
-        PackageParser.Package pkg = mPackages.get(packageName);
+        AndroidPackage pkg = mPackages.get(packageName);
         return pkg != null
-                && UserHandle.getAppId(uid) == pkg.applicationInfo.uid;
+                && UserHandle.getAppId(uid) == pkg.getUid();
     }
 
     @Override
@@ -8189,23 +8278,22 @@
 
         // reader
         synchronized (mLock) {
-            final Iterator<PackageParser.Package> i = mPackages.values().iterator();
+            final Iterator<AndroidPackage> i = mPackages.values().iterator();
             final int userId = UserHandle.getCallingUserId();
             while (i.hasNext()) {
-                final PackageParser.Package p = i.next();
-                if (p.applicationInfo == null) continue;
+                final AndroidPackage p = i.next();
 
                 final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0)
-                        && !p.applicationInfo.isDirectBootAware();
+                        && !p.isDirectBootAware();
                 final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)
-                        && p.applicationInfo.isDirectBootAware();
+                        && p.isDirectBootAware();
 
-                if ((p.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0
+                if ((p.getFlags() & ApplicationInfo.FLAG_PERSISTENT) != 0
                         && (!mSafeMode || isSystemApp(p))
                         && (matchesUnaware || matchesAware)) {
-                    PackageSetting ps = mSettings.mPackages.get(p.packageName);
+                    PackageSetting ps = mSettings.mPackages.get(p.getPackageName());
                     if (ps != null) {
-                        ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
+                        ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(p, flags,
                                 ps.readUserState(userId), userId);
                         if (ai != null) {
                             finalList.add(ai);
@@ -8303,14 +8391,16 @@
         synchronized (mLock) {
             final int callingUid = Binder.getCallingUid();
             final int callingUserId = UserHandle.getUserId(callingUid);
-            final PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
-            if (ps == null) return null;
+            String packageName = component.getPackageName();
+            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            AndroidPackage pkg = mPackages.get(packageName);
+            if (ps == null || pkg == null) return null;
             if (shouldFilterApplicationLocked(
                     ps, callingUid, component, TYPE_UNKNOWN, callingUserId)) {
                 return null;
             }
-            final PackageParser.Instrumentation i = mInstrumentation.get(component);
-            return PackageParser.generateInstrumentationInfo(i, flags);
+            final ParsedInstrumentation i = mInstrumentation.get(component);
+            return PackageInfoUtils.generateInstrumentationInfo(i, pkg, flags);
         }
     }
 
@@ -8332,15 +8422,18 @@
 
         // reader
         synchronized (mLock) {
-            final Iterator<PackageParser.Instrumentation> i = mInstrumentation.values().iterator();
+            final Iterator<ParsedInstrumentation> i = mInstrumentation.values().iterator();
             while (i.hasNext()) {
-                final PackageParser.Instrumentation p = i.next();
+                final ParsedInstrumentation p = i.next();
                 if (targetPackage == null
-                        || targetPackage.equals(p.info.targetPackage)) {
-                    InstrumentationInfo ii = PackageParser.generateInstrumentationInfo(p,
-                            flags);
-                    if (ii != null) {
-                        finalList.add(ii);
+                        || targetPackage.equals(p.getTargetPackage())) {
+                    AndroidPackage pkg = mPackages.get(p.getPackageName());
+                    if (pkg != null) {
+                        InstrumentationInfo ii = PackageInfoUtils.generateInstrumentationInfo(p,
+                                pkg, flags);
+                        if (ii != null) {
+                            finalList.add(ii);
+                        }
                     }
                 }
             }
@@ -8394,18 +8487,18 @@
                 if (throwable == null) {
                     // TODO(toddke): move lower in the scan chain
                     // Static shared libraries have synthetic package names
-                    if (parseResult.pkg.applicationInfo.isStaticSharedLibrary()) {
-                        renameStaticSharedLibraryPackage(parseResult.pkg);
+                    if (parseResult.parsedPackage.isStaticSharedLibrary()) {
+                        renameStaticSharedLibraryPackage(parseResult.parsedPackage);
                     }
                     try {
-                        scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags,
+                        addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
                                 currentTime, null);
                     } catch (PackageManagerException e) {
                         errorCode = e.error;
                         Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage());
                     }
-                } else if (throwable instanceof PackageParser.PackageParserException) {
-                    PackageParser.PackageParserException e = (PackageParser.PackageParserException)
+                } else if (throwable instanceof PackageParserException) {
+                    PackageParserException e = (PackageParserException)
                             throwable;
                     errorCode = e.error;
                     Slog.w(TAG, "Failed to parse " + parseResult.scanFile + ": " + e.getMessage());
@@ -8429,15 +8522,16 @@
         logCriticalInfo(priority, msg);
     }
 
-    private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg,
+    private void collectCertificatesLI(PackageSetting ps, ParsedPackage parsedPackage,
             boolean forceCollect, boolean skipVerify) throws PackageManagerException {
         // When upgrading from pre-N MR1, verify the package time stamp using the package
         // directory and not the APK file.
         final long lastModifiedTime = mIsPreNMR1Upgrade
-                ? new File(pkg.codePath).lastModified() : getLastModifiedTime(pkg);
-        final VersionInfo settingsVersionForPackage = getSettingsVersionForPackage(pkg);
+                ? new File(parsedPackage.getCodePath()).lastModified()
+                : getLastModifiedTime(parsedPackage);
+        final VersionInfo settingsVersionForPackage = getSettingsVersionForPackage(parsedPackage);
         if (ps != null && !forceCollect
-                && ps.codePathString.equals(pkg.codePath)
+                && ps.codePathString.equals(parsedPackage.getCodePath())
                 && ps.timeStamp == lastModifiedTime
                 && !isCompatSignatureUpdateNeeded(settingsVersionForPackage)
                 && !isRecoverSignatureUpdateNeeded(settingsVersionForPackage)) {
@@ -8447,21 +8541,21 @@
                             != SignatureSchemeVersion.UNKNOWN) {
                 // Optimization: reuse the existing cached signing data
                 // if the package appears to be unchanged.
-                pkg.mSigningDetails =
-                        new PackageParser.SigningDetails(ps.signatures.mSigningDetails);
+                parsedPackage.setSigningDetails(
+                        new PackageParser.SigningDetails(ps.signatures.mSigningDetails));
                 return;
             }
 
             Slog.w(TAG, "PackageSetting for " + ps.name
                     + " is missing signatures.  Collecting certs again to recover them.");
         } else {
-            Slog.i(TAG, pkg.codePath + " changed; collecting certs" +
+            Slog.i(TAG, parsedPackage.getCodePath() + " changed; collecting certs" +
                     (forceCollect ? " (forced)" : ""));
         }
 
         try {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
-            PackageParser.collectCertificates(pkg, skipVerify);
+            ApkParseUtils.collectCertificates(parsedPackage, skipVerify);
         } catch (PackageParserException e) {
             throw PackageManagerException.from(e);
         } finally {
@@ -8475,20 +8569,20 @@
      */
     private void maybeClearProfilesForUpgradesLI(
             @Nullable PackageSetting originalPkgSetting,
-            @NonNull PackageParser.Package currentPkg) {
+            @NonNull AndroidPackage pkg) {
         if (originalPkgSetting == null || !isDeviceUpgrading()) {
           return;
         }
-        if (originalPkgSetting.versionCode == currentPkg.mVersionCode) {
+        if (originalPkgSetting.versionCode == pkg.getVersionCode()) {
           return;
         }
 
-        clearAppProfilesLIF(currentPkg, UserHandle.USER_ALL);
+        clearAppProfilesLIF(pkg, UserHandle.USER_ALL);
         if (DEBUG_INSTALL) {
             Slog.d(TAG, originalPkgSetting.name
                   + " clear profile due to version change "
                   + originalPkgSetting.versionCode + " != "
-                  + currentPkg.mVersionCode);
+                  + pkg.getVersionCode());
         }
     }
 
@@ -8497,7 +8591,7 @@
      *  @see #scanPackageLI(File, int, int, long, UserHandle)
      */
     @GuardedBy({"mInstallLock", "mLock"})
-    private PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags,
+    private AndroidPackage scanPackageTracedLI(File scanFile, final int parseFlags,
             int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]");
         try {
@@ -8512,7 +8606,7 @@
      *  Returns {@code null} in case of errors and the error code is stored in mLastScanError
      */
     @GuardedBy({"mInstallLock", "mLock"})
-    private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
+    private AndroidPackage scanPackageLI(File scanFile, int parseFlags, int scanFlags,
             long currentTime, UserHandle user) throws PackageManagerException {
         if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
         PackageParser pp = new PackageParser();
@@ -8522,9 +8616,9 @@
         pp.setCallback(mPackageParserCallback);
 
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
-        final PackageParser.Package pkg;
+        final ParsedPackage parsedPackage;
         try {
-            pkg = pp.parsePackage(scanFile, parseFlags);
+            parsedPackage = pp.parseParsedPackage(scanFile, parseFlags, false);
         } catch (PackageParserException e) {
             throw PackageManagerException.from(e);
         } finally {
@@ -8532,66 +8626,25 @@
         }
 
         // Static shared libraries have synthetic package names
-        if (pkg.applicationInfo.isStaticSharedLibrary()) {
-            renameStaticSharedLibraryPackage(pkg);
+        if (parsedPackage.isStaticSharedLibrary()) {
+            renameStaticSharedLibraryPackage(parsedPackage);
         }
 
-        return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);
-    }
-
-    /**
-     *  Scans a package and returns the newly parsed package.
-     *  @throws PackageManagerException on a parse error.
-     */
-    @GuardedBy({"mInstallLock", "mLock"})
-    private PackageParser.Package scanPackageChildLI(PackageParser.Package pkg,
-            final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
-            @Nullable UserHandle user)
-                    throws PackageManagerException {
-        // If the package has children and this is the first dive in the function
-        // we scan the package with the SCAN_CHECK_ONLY flag set to see whether all
-        // packages (parent and children) would be successfully scanned before the
-        // actual scan since scanning mutates internal state and we want to atomically
-        // install the package and its children.
-        if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
-            if (pkg.childPackages != null && pkg.childPackages.size() > 0) {
-                scanFlags |= SCAN_CHECK_ONLY;
-            }
-        } else {
-            scanFlags &= ~SCAN_CHECK_ONLY;
-        }
-
-        // Scan the parent
-        PackageParser.Package scannedPkg = addForInitLI(pkg, parseFlags,
-                scanFlags, currentTime, user);
-
-        // Scan the children
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            PackageParser.Package childPackage = pkg.childPackages.get(i);
-            addForInitLI(childPackage, parseFlags, scanFlags,
-                    currentTime, user);
-        }
-
-
-        if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
-            return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);
-        }
-
-        return scannedPkg;
+        return addForInitLI(parsedPackage, parseFlags, scanFlags, currentTime, user);
     }
 
     /**
      * Returns if forced apk verification can be skipped for the whole package, including splits.
      */
-    private boolean canSkipForcedPackageVerification(PackageParser.Package pkg) {
-        if (!canSkipForcedApkVerification(pkg.baseCodePath)) {
+    private boolean canSkipForcedPackageVerification(AndroidPackage pkg) {
+        if (!canSkipForcedApkVerification(pkg.getBaseCodePath())) {
             return false;
         }
         // TODO: Allow base and splits to be verified individually.
-        if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
-            for (int i = 0; i < pkg.splitCodePaths.length; i++) {
-                if (!canSkipForcedApkVerification(pkg.splitCodePaths[i])) {
+        String[] splitCodePaths = pkg.getSplitCodePaths();
+        if (!ArrayUtils.isEmpty(splitCodePaths)) {
+            for (int i = 0; i < splitCodePaths.length; i++) {
+                if (!canSkipForcedApkVerification(splitCodePaths[i])) {
                     return false;
                 }
             }
@@ -8640,7 +8693,7 @@
      * <p>NOTE: The return value should be removed. It's the passed in package object.
      */
     @GuardedBy({"mInstallLock", "mLock"})
-    private PackageParser.Package addForInitLI(PackageParser.Package pkg,
+    private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
             @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
             @Nullable UserHandle user)
                     throws PackageManagerException {
@@ -8656,25 +8709,27 @@
         // stack [such as scanPackageOnly()]. However, we verify the application
         // info prior to that [in scanPackageNew()] and thus have to setup
         // the application info early.
-        pkg.setApplicationVolumeUuid(pkg.volumeUuid);
-        pkg.setApplicationInfoCodePath(pkg.codePath);
-        pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath);
-        pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths);
-        pkg.setApplicationInfoResourcePath(pkg.codePath);
-        pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath);
-        pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);
+        // TODO(b/135203078): Remove all of these application info calls
+        parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid())
+                .setApplicationInfoCodePath(parsedPackage.getCodePath())
+                .setApplicationInfoResourcePath(parsedPackage.getCodePath())
+                .setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath())
+                .setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths());
 
         synchronized (mLock) {
-            renamedPkgName = mSettings.getRenamedPackageLPr(pkg.mRealPackage);
-            final String realPkgName = getRealPackageName(pkg, renamedPkgName);
+            renamedPkgName = mSettings.getRenamedPackageLPr(parsedPackage.getRealPackage());
+            final String realPkgName = getRealPackageName(parsedPackage, renamedPkgName);
             if (realPkgName != null) {
-                ensurePackageRenamed(pkg, renamedPkgName);
+                ensurePackageRenamed(parsedPackage, renamedPkgName);
             }
-            final PackageSetting originalPkgSetting = getOriginalPackageLocked(pkg, renamedPkgName);
-            final PackageSetting installedPkgSetting = mSettings.getPackageLPr(pkg.packageName);
+            final PackageSetting originalPkgSetting = getOriginalPackageLocked(parsedPackage,
+                    renamedPkgName);
+            final PackageSetting installedPkgSetting = mSettings.getPackageLPr(
+                    parsedPackage.getPackageName());
             pkgSetting = originalPkgSetting == null ? installedPkgSetting : originalPkgSetting;
             pkgAlreadyExists = pkgSetting != null;
-            final String disabledPkgName = pkgAlreadyExists ? pkgSetting.name : pkg.packageName;
+            final String disabledPkgName = pkgAlreadyExists
+                    ? pkgSetting.name : parsedPackage.getPackageName();
             if (scanSystemPartition && !pkgAlreadyExists
                     && mSettings.getDisabledSystemPkgLPr(disabledPkgName) != null) {
                 // The updated-package data for /system apk remains inconsistently
@@ -8692,49 +8747,29 @@
                 Slog.d(TAG, "updatedPkg = " + disabledPkgSetting);
             }
 
-            final SharedUserSetting sharedUserSetting = (pkg.mSharedUserId != null)
-                    ? mSettings.getSharedUserLPw(pkg.mSharedUserId,
+            final SharedUserSetting sharedUserSetting = (parsedPackage.getSharedUserId() != null)
+                    ? mSettings.getSharedUserLPw(parsedPackage.getSharedUserId(),
                             0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true)
                     : null;
             if (DEBUG_PACKAGE_SCANNING
                     && (parseFlags & PackageParser.PARSE_CHATTY) != 0
                     && sharedUserSetting != null) {
-                Log.d(TAG, "Shared UserID " + pkg.mSharedUserId
+                Log.d(TAG, "Shared UserID " + parsedPackage.getSharedUserId()
                         + " (uid=" + sharedUserSetting.userId + "):"
                         + " packages=" + sharedUserSetting.packages);
             }
 
             if (scanSystemPartition) {
-                // Potentially prune child packages. If the application on the /system
-                // partition has been updated via OTA, but, is still disabled by a
-                // version on /data, cycle through all of its children packages and
-                // remove children that are no longer defined.
                 if (isSystemPkgUpdated) {
-                    final int scannedChildCount = (pkg.childPackages != null)
-                            ? pkg.childPackages.size() : 0;
-                    final int disabledChildCount = disabledPkgSetting.childPackageNames != null
-                            ? disabledPkgSetting.childPackageNames.size() : 0;
-                    for (int i = 0; i < disabledChildCount; i++) {
-                        String disabledChildPackageName =
-                                disabledPkgSetting.childPackageNames.get(i);
-                        boolean disabledPackageAvailable = false;
-                        for (int j = 0; j < scannedChildCount; j++) {
-                            PackageParser.Package childPkg = pkg.childPackages.get(j);
-                            if (childPkg.packageName.equals(disabledChildPackageName)) {
-                                disabledPackageAvailable = true;
-                                break;
-                            }
-                        }
-                        if (!disabledPackageAvailable) {
-                            mSettings.removeDisabledSystemPackageLPw(disabledChildPackageName);
-                        }
-                    }
                     // we're updating the disabled package, so, scan it as the package setting
-                    final ScanRequest request = new ScanRequest(pkg, sharedUserSetting, null,
-                            disabledPkgSetting /* pkgSetting */, null /* disabledPkgSetting */,
-                            null /* originalPkgSetting */, null, parseFlags, scanFlags,
-                            (pkg == mPlatformPackage), user);
-                    applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage);
+                    boolean isPlatformPackage = mPlatformPackage != null
+                            && Objects.equals(mPlatformPackage.getPackageName(),
+                            parsedPackage.getPackageName());
+                    final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting,
+                            null, disabledPkgSetting /* pkgSetting */,
+                            null /* disabledPkgSetting */, null /* originalPkgSetting */,
+                            null, parseFlags, scanFlags, isPlatformPackage, user);
+                    applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage);
                     final ScanResult scanResult =
                             scanPackageOnlyLI(request, mInjector, mFactoryTest, -1L);
                     if (scanResult.existingSettingCopied && scanResult.request.pkgSetting != null) {
@@ -8745,9 +8780,9 @@
         }
 
         final boolean newPkgChangedPaths =
-                pkgAlreadyExists && !pkgSetting.codePathString.equals(pkg.codePath);
+                pkgAlreadyExists && !pkgSetting.codePathString.equals(parsedPackage.getCodePath());
         final boolean newPkgVersionGreater =
-                pkgAlreadyExists && pkg.getLongVersionCode() > pkgSetting.versionCode;
+                pkgAlreadyExists && parsedPackage.getLongVersionCode() > pkgSetting.versionCode;
         final boolean isSystemPkgBetter = scanSystemPartition && isSystemPkgUpdated
                 && newPkgChangedPaths && newPkgVersionGreater;
         if (isSystemPkgBetter) {
@@ -8763,12 +8798,13 @@
             logCriticalInfo(Log.WARN,
                     "System package updated;"
                     + " name: " + pkgSetting.name
-                    + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode()
-                    + "; " + pkgSetting.codePathString + " --> " + pkg.codePath);
+                    + "; " + pkgSetting.versionCode + " --> " + parsedPackage.getLongVersionCode()
+                    + "; " + pkgSetting.codePathString + " --> " + parsedPackage.getCodePath());
 
             final InstallArgs args = createInstallArgsForExisting(
                     pkgSetting.codePathString,
-                    pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
+                    pkgSetting.resourcePathString, getAppDexInstructionSets(
+                            pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
             args.cleanUpResourcesLI();
             synchronized (mLock) {
                 mSettings.enableSystemPackageLPw(pkgSetting.name);
@@ -8779,9 +8815,10 @@
             // The version of the application on the /system partition is less than or
             // equal to the version on the /data partition. Throw an exception and use
             // the application already installed on the /data partition.
-            throw new PackageManagerException(Log.WARN, "Package " + pkg.packageName + " at "
-                    + pkg.codePath + " ignored: updated version " + pkgSetting.versionCode
-                    + " better than this " + pkg.getLongVersionCode());
+            throw new PackageManagerException(Log.WARN, "Package " + parsedPackage.getPackageName()
+                    + " at " + parsedPackage.getCodePath() + " ignored: updated version "
+                    + pkgSetting.versionCode + " better than this "
+                    + parsedPackage.getLongVersionCode());
         }
 
         // Verify certificates against what was last scanned. Force re-collecting certificate in two
@@ -8792,18 +8829,19 @@
         final boolean forceCollect = scanSystemPartition ? mIsUpgrade
                 : PackageManagerServiceUtils.isApkVerificationForced(pkgSetting);
         if (DEBUG_VERIFY && forceCollect) {
-            Slog.d(TAG, "Force collect certificate of " + pkg.packageName);
+            Slog.d(TAG, "Force collect certificate of " + parsedPackage.getPackageName());
         }
 
         // Full APK verification can be skipped during certificate collection, only if the file is
         // in verified partition, or can be verified on access (when apk verity is enabled). In both
         // cases, only data in Signing Block is verified instead of the whole file.
+        // TODO(b/136132412): skip for Incremental installation
         final boolean skipVerify = scanSystemPartition
-                || (forceCollect && canSkipForcedPackageVerification(pkg));
-        collectCertificatesLI(pkgSetting, pkg, forceCollect, skipVerify);
+                || (forceCollect && canSkipForcedPackageVerification(parsedPackage));
+        collectCertificatesLI(pkgSetting, parsedPackage, forceCollect, skipVerify);
 
         // Reset profile if the application version is changed
-        maybeClearProfilesForUpgradesLI(pkgSetting, pkg);
+        maybeClearProfilesForUpgradesLI(pkgSetting, parsedPackage);
 
         /*
          * A new system app appeared, but we already had a non-system one of the
@@ -8815,17 +8853,20 @@
         if (scanSystemPartition && !isSystemPkgUpdated && pkgAlreadyExists
                 && !pkgSetting.isSystem()) {
 
-            if (!pkg.mSigningDetails.checkCapability(pkgSetting.signatures.mSigningDetails,
+            if (!parsedPackage.getSigningDetails()
+                    .checkCapability(pkgSetting.signatures.mSigningDetails,
                     PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
                             && !pkgSetting.signatures.mSigningDetails.checkCapability(
-                                    pkg.mSigningDetails,
+                                    parsedPackage.getSigningDetails(),
                                     PackageParser.SigningDetails.CertCapabilities.ROLLBACK)) {
                 logCriticalInfo(Log.WARN,
                         "System package signature mismatch;"
                         + " name: " + pkgSetting.name);
-                try (PackageFreezer freezer = freezePackage(pkg.packageName,
+                try (@SuppressWarnings("unused") PackageFreezer freezer = freezePackage(
+                        parsedPackage.getPackageName(),
                         "scanPackageInternalLI")) {
-                    deletePackageLIF(pkg.packageName, null, true, null, 0, null, false, null);
+                    deletePackageLIF(parsedPackage.getPackageName(), null, true, null, 0, null,
+                            false, null);
                 }
                 pkgSetting = null;
             } else if (newPkgVersionGreater) {
@@ -8834,12 +8875,15 @@
                 // and replace it with the version on /system.
                 logCriticalInfo(Log.WARN,
                         "System package enabled;"
-                        + " name: " + pkgSetting.name
-                        + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode()
-                        + "; " + pkgSetting.codePathString + " --> " + pkg.codePath);
+                                + " name: " + pkgSetting.name
+                                + "; " + pkgSetting.versionCode + " --> "
+                                + parsedPackage.getLongVersionCode()
+                                + "; " + pkgSetting.codePathString + " --> "
+                                + parsedPackage.getCodePath());
                 InstallArgs args = createInstallArgsForExisting(
                         pkgSetting.codePathString,
-                        pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting));
+                        pkgSetting.resourcePathString, getAppDexInstructionSets(
+                                pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
                 synchronized (mInstallLock) {
                     args.cleanUpResourcesLI();
                 }
@@ -8850,13 +8894,15 @@
                 shouldHideSystemApp = true;
                 logCriticalInfo(Log.INFO,
                         "System package disabled;"
-                        + " name: " + pkgSetting.name
-                        + "; old: " + pkgSetting.codePathString + " @ " + pkgSetting.versionCode
-                        + "; new: " + pkg.codePath + " @ " + pkg.codePath);
+                                + " name: " + pkgSetting.name
+                                + "; old: " + pkgSetting.codePathString + " @ "
+                                + pkgSetting.versionCode
+                                + "; new: " + parsedPackage.getCodePath() + " @ "
+                                + parsedPackage.getCodePath());
             }
         }
 
-        final ScanResult scanResult = scanPackageNewLI(pkg, parseFlags, scanFlags
+        final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags, scanFlags
                 | SCAN_UPDATE_SIGNATURE, currentTime, user);
         if (scanResult.success) {
             synchronized (mLock) {
@@ -8869,7 +8915,7 @@
                                     mSharedLibraries,
                                     mPackages,
                                     Collections.singletonMap(
-                                            pkgName, getSettingsVersionForPackage(pkg)),
+                                            pkgName, getSettingsVersionForPackage(parsedPackage)),
                                     Collections.singletonMap(pkgName,
                                             getSharedLibLatestVersionSetting(scanResult))),
                             mSettings.mKeySetManagerService);
@@ -8886,16 +8932,17 @@
 
         if (shouldHideSystemApp) {
             synchronized (mLock) {
-                mSettings.disableSystemPackageLPw(pkg.packageName, true);
+                mSettings.disableSystemPackageLPw(parsedPackage.getPackageName(), true);
             }
         }
         return scanResult.pkgSetting.pkg;
     }
 
-    private static void renameStaticSharedLibraryPackage(PackageParser.Package pkg) {
+    // TODO:(b/135203078): Move to parsing
+    private static void renameStaticSharedLibraryPackage(ParsedPackage parsedPackage) {
         // Derive the new package synthetic package name
-        pkg.setPackageName(pkg.packageName + STATIC_SHARED_LIB_DELIMITER
-                + pkg.staticSharedLibVersion);
+        parsedPackage.setPackageName(parsedPackage.getPackageName() + STATIC_SHARED_LIB_DELIMITER
+                + parsedPackage.getStaticSharedLibVersion());
     }
 
     static String fixProcessName(String defProcessName, String processName) {
@@ -8996,7 +9043,7 @@
             return;
         }
 
-        List<PackageParser.Package> pkgs;
+        List<AndroidPackage> pkgs;
         synchronized (mLock) {
             pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
         }
@@ -9019,8 +9066,8 @@
     /*
      * Return the prebuilt profile path given a package base code path.
      */
-    private static String getPrebuildProfilePath(PackageParser.Package pkg) {
-        return pkg.baseCodePath + ".prof";
+    private static String getPrebuildProfilePath(AndroidPackage pkg) {
+        return pkg.getBaseCodePath() + ".prof";
     }
 
     /**
@@ -9029,7 +9076,7 @@
      * which are (in order) {@code numberOfPackagesOptimized}, {@code numberOfPackagesSkipped}
      * and {@code numberOfPackagesFailed}.
      */
-    private int[] performDexOptUpgrade(List<PackageParser.Package> pkgs, boolean showDialog,
+    private int[] performDexOptUpgrade(List<AndroidPackage> pkgs, boolean showDialog,
             final int compilationReason, boolean bootComplete) {
 
         int numberOfPackagesVisited = 0;
@@ -9038,7 +9085,7 @@
         int numberOfPackagesFailed = 0;
         final int numberOfPackagesToDexopt = pkgs.size();
 
-        for (PackageParser.Package pkg : pkgs) {
+        for (AndroidPackage pkg : pkgs) {
             numberOfPackagesVisited++;
 
             boolean useProfileForDexopt = false;
@@ -9054,7 +9101,7 @@
                         // PackageDexOptimizer to prevent this happening on first boot. The issue
                         // is that we don't have a good way to say "do this only once".
                         if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
-                                pkg.applicationInfo.uid, pkg.packageName,
+                                pkg.getUid(), pkg.getPackageName(),
                                 ArtManager.getProfileName(null))) {
                             Log.e(TAG, "Installer failed to copy system profile!");
                         } else {
@@ -9067,11 +9114,12 @@
                                 e);
                     }
                 } else {
-                    PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(pkg.packageName);
+                    PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(
+                            pkg.getPackageName());
                     // Handle compressed APKs in this path. Only do this for stubs with profiles to
                     // minimize the number off apps being speed-profile compiled during first boot.
                     // The other paths will not change the filter.
-                    if (disabledPs != null && disabledPs.pkg.isStub) {
+                    if (disabledPs != null && disabledPs.pkg.isStub()) {
                         // The package is the stub one, remove the stub suffix to get the normal
                         // package and APK names.
                         String systemProfilePath =
@@ -9090,7 +9138,7 @@
                                 // issue is that we don't have a good way to say "do this only
                                 // once".
                                 if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
-                                        pkg.applicationInfo.uid, pkg.packageName,
+                                        pkg.getUid(), pkg.getPackageName(),
                                         ArtManager.getProfileName(null))) {
                                     Log.e(TAG, "Failed to copy system profile for stub package!");
                                 } else {
@@ -9107,7 +9155,7 @@
 
             if (!PackageDexOptimizer.canOptimizePackage(pkg)) {
                 if (DEBUG_DEXOPT) {
-                    Log.i(TAG, "Skipping update of of non-optimizable app " + pkg.packageName);
+                    Log.i(TAG, "Skipping update of non-optimizable app " + pkg.getPackageName());
                 }
                 numberOfPackagesSkipped++;
                 continue;
@@ -9115,7 +9163,7 @@
 
             if (DEBUG_DEXOPT) {
                 Log.i(TAG, "Updating app " + numberOfPackagesVisited + " of " +
-                        numberOfPackagesToDexopt + ": " + pkg.packageName);
+                        numberOfPackagesToDexopt + ": " + pkg.getPackageName());
             }
 
             if (showDialog) {
@@ -9152,7 +9200,7 @@
                 dexoptFlags |= DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE;
             }
             int primaryDexOptStaus = performDexOptTraced(new DexoptOptions(
-                    pkg.packageName,
+                    pkg.getPackageName(),
                     pkgCompilationReason,
                     dexoptFlags));
 
@@ -9196,11 +9244,11 @@
 
     @GuardedBy("mLock")
     private void notifyPackageUseLocked(String packageName, int reason) {
-        final PackageParser.Package p = mPackages.get(packageName);
+        final AndroidPackage p = mPackages.get(packageName);
         if (p == null) {
             return;
         }
-        p.mLastPackageUsageTimeInMills[reason] = System.currentTimeMillis();
+        p.mutate().setLastPackageUsageTimeInMills(reason, System.currentTimeMillis());
     }
 
     @Override
@@ -9280,7 +9328,7 @@
     */
     @Override
     public boolean compileLayouts(String packageName) {
-        PackageParser.Package pkg;
+        AndroidPackage pkg;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
             if (pkg == null) {
@@ -9327,7 +9375,7 @@
     // Run dexopt on a given package. Returns true if dexopt did not fail, i.e.
     // if the package can now be considered up to date for the given filter.
     private int performDexOptInternal(DexoptOptions options) {
-        PackageParser.Package p;
+        AndroidPackage p;
         synchronized (mLock) {
             p = mPackages.get(options.getPackageName());
             if (p == null) {
@@ -9350,16 +9398,16 @@
     public ArraySet<String> getOptimizablePackages() {
         ArraySet<String> pkgs = new ArraySet<>();
         synchronized (mLock) {
-            for (PackageParser.Package p : mPackages.values()) {
+            for (AndroidPackage p : mPackages.values()) {
                 if (PackageDexOptimizer.canOptimizePackage(p)) {
-                    pkgs.add(p.packageName);
+                    pkgs.add(p.getPackageName());
                 }
             }
         }
         return pkgs;
     }
 
-    private int performDexOptInternalWithDependenciesLI(PackageParser.Package p,
+    private int performDexOptInternalWithDependenciesLI(AndroidPackage p,
             DexoptOptions options) {
         // Select the dex optimizer based on the force parameter.
         // Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to
@@ -9376,14 +9424,15 @@
         // and the first package that uses the library will dexopt it. The
         // others will see that the compiled code for the library is up to date.
         Collection<SharedLibraryInfo> deps = findSharedLibraries(p);
-        final String[] instructionSets = getAppDexInstructionSets(p.applicationInfo);
+        final String[] instructionSets = getAppDexInstructionSets(p.getPrimaryCpuAbi(),
+                p.getSecondaryCpuAbi());
         if (!deps.isEmpty()) {
             DexoptOptions libraryOptions = new DexoptOptions(options.getPackageName(),
                     options.getCompilationReason(), options.getCompilerFilter(),
                     options.getSplitName(),
                     options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY);
             for (SharedLibraryInfo info : deps) {
-                PackageParser.Package depPackage = null;
+                AndroidPackage depPackage = null;
                 synchronized (mLock) {
                     depPackage = mPackages.get(info.getPackageName());
                 }
@@ -9391,7 +9440,7 @@
                     // TODO: Analyze and investigate if we (should) profile libraries.
                     pdo.performDexOpt(depPackage, instructionSets,
                             getOrCreateCompilerPackageStats(depPackage),
-                            mDexManager.getPackageUseInfoOrDefault(depPackage.packageName),
+                            mDexManager.getPackageUseInfoOrDefault(depPackage.getPackageName()),
                             libraryOptions);
                 } else {
                     // TODO(ngeoffray): Support dexopting system shared libraries.
@@ -9400,7 +9449,7 @@
         }
         return pdo.performDexOpt(p, instructionSets,
                 getOrCreateCompilerPackageStats(p),
-                mDexManager.getPackageUseInfoOrDefault(p.packageName), options);
+                mDexManager.getPackageUseInfoOrDefault(p.getPackageName()), options);
     }
 
     /**
@@ -9441,11 +9490,11 @@
         }
     }
 
-    private static List<SharedLibraryInfo> findSharedLibraries(PackageParser.Package p) {
-        if (p.usesLibraryInfos != null) {
+    private static List<SharedLibraryInfo> findSharedLibraries(AndroidPackage p) {
+        if (p.getUsesLibraryInfos() != null) {
             ArrayList<SharedLibraryInfo> retValue = new ArrayList<>();
             Set<String> collectedNames = new HashSet<>();
-            for (SharedLibraryInfo info : p.usesLibraryInfos) {
+            for (SharedLibraryInfo info : p.getUsesLibraryInfos()) {
                 findSharedLibrariesRecursive(info, retValue, collectedNames);
             }
             return retValue;
@@ -9468,13 +9517,13 @@
         }
     }
 
-    List<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package pkg) {
+    List<AndroidPackage> findSharedNonSystemLibraries(AndroidPackage pkg) {
         List<SharedLibraryInfo> deps = findSharedLibraries(pkg);
         if (!deps.isEmpty()) {
-            ArrayList<PackageParser.Package> retValue = new ArrayList<>();
+            ArrayList<AndroidPackage> retValue = new ArrayList<>();
             synchronized (mLock) {
                 for (SharedLibraryInfo info : deps) {
-                    PackageParser.Package depPackage = mPackages.get(info.getPackageName());
+                    AndroidPackage depPackage = mPackages.get(info.getPackageName());
                     if (depPackage != null) {
                         retValue.add(depPackage);
                     }
@@ -9512,9 +9561,9 @@
         return versionedLib.get(version);
     }
 
-    private SharedLibraryInfo getLatestSharedLibraVersionLPr(PackageParser.Package pkg) {
+    private SharedLibraryInfo getLatestSharedLibraVersionLPr(AndroidPackage pkg) {
         LongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(
-                pkg.staticSharedLibName);
+                pkg.getStaticSharedLibName());
         if (versionedLib == null) {
             return null;
         }
@@ -9522,7 +9571,7 @@
         final int versionCount = versionedLib.size();
         for (int i = 0; i < versionCount; i++) {
             final long libVersion = versionedLib.keyAt(i);
-            if (libVersion < pkg.staticSharedLibVersion) {
+            if (libVersion < pkg.getStaticSharedLibVersion()) {
                 previousLibVersion = Math.max(previousLibVersion, libVersion);
             }
         }
@@ -9538,7 +9587,7 @@
         PackageSetting sharedLibPackage = null;
         synchronized (mLock) {
             final SharedLibraryInfo latestSharedLibraVersionLPr =
-                    getLatestSharedLibraVersionLPr(scanResult.pkgSetting.pkg);
+                    getLatestSharedLibraVersionLPr(scanResult.request.parsedPackage);
             if (latestSharedLibraVersionLPr != null) {
                 sharedLibPackage = mSettings.getPackageLPr(
                         latestSharedLibraVersionLPr.getPackageName());
@@ -9567,7 +9616,7 @@
 
     @Override
     public void dumpProfiles(String packageName) {
-        PackageParser.Package pkg;
+        AndroidPackage pkg;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
             if (pkg == null) {
@@ -9578,7 +9627,7 @@
         int callingUid = Binder.getCallingUid();
         if (callingUid != Process.SHELL_UID &&
             callingUid != Process.ROOT_UID &&
-            callingUid != pkg.applicationInfo.uid) {
+            callingUid != pkg.getUid()) {
             throw new SecurityException("dumpProfiles");
         }
 
@@ -9593,7 +9642,7 @@
     public void forceDexOpt(String packageName) {
         enforceSystemOrRoot("forceDexOpt");
 
-        PackageParser.Package pkg;
+        AndroidPackage pkg;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
             if (pkg == null) {
@@ -9620,15 +9669,15 @@
     }
 
     @GuardedBy("mLock")
-    private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, PackageParser.Package newPkg) {
+    private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, AndroidPackage newPkg) {
         if ((oldPkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
             Slog.w(TAG, "Unable to update from " + oldPkg.name
-                    + " to " + newPkg.packageName
+                    + " to " + newPkg.getPackageName()
                     + ": old package not in system partition");
             return false;
         } else if (mPackages.get(oldPkg.name) != null) {
             Slog.w(TAG, "Unable to update from " + oldPkg.name
-                    + " to " + newPkg.packageName
+                    + " to " + newPkg.getPackageName()
                     + ": old package still exists");
             return false;
         }
@@ -9652,122 +9701,86 @@
         return (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] { userId };
     }
 
-    private void clearAppDataLIF(PackageParser.Package pkg, int userId, int flags) {
+    private void clearAppDataLIF(AndroidPackage pkg, int userId, int flags) {
         if (pkg == null) {
             Slog.wtf(TAG, "Package was null!", new Throwable());
             return;
         }
         clearAppDataLeafLIF(pkg, userId, flags);
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            clearAppDataLeafLIF(pkg.childPackages.get(i), userId, flags);
-        }
 
         if ((flags & Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES) == 0) {
             clearAppProfilesLIF(pkg, UserHandle.USER_ALL);
         }
     }
 
-    private void clearAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
+    private void clearAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
         final PackageSetting ps;
         synchronized (mLock) {
-            ps = mSettings.mPackages.get(pkg.packageName);
+            ps = mSettings.mPackages.get(pkg.getPackageName());
         }
         for (int realUserId : resolveUserIds(userId)) {
             final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0;
             try {
-                mInstaller.clearAppData(pkg.volumeUuid, pkg.packageName, realUserId, flags,
-                        ceDataInode);
+                mInstaller.clearAppData(pkg.getVolumeUuid(), pkg.getPackageName(), realUserId,
+                        flags, ceDataInode);
             } catch (InstallerException e) {
                 Slog.w(TAG, String.valueOf(e));
             }
         }
     }
 
-    private void destroyAppDataLIF(PackageParser.Package pkg, int userId, int flags) {
+    private void destroyAppDataLIF(AndroidPackage pkg, int userId, int flags) {
         if (pkg == null) {
             Slog.wtf(TAG, "Package was null!", new Throwable());
             return;
         }
         destroyAppDataLeafLIF(pkg, userId, flags);
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            destroyAppDataLeafLIF(pkg.childPackages.get(i), userId, flags);
-        }
     }
 
-    private void destroyAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
+    private void destroyAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
         final PackageSetting ps;
         synchronized (mLock) {
-            ps = mSettings.mPackages.get(pkg.packageName);
+            ps = mSettings.mPackages.get(pkg.getPackageName());
         }
         for (int realUserId : resolveUserIds(userId)) {
             final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0;
             try {
-                mInstaller.destroyAppData(pkg.volumeUuid, pkg.packageName, realUserId, flags,
-                        ceDataInode);
+                mInstaller.destroyAppData(pkg.getVolumeUuid(), pkg.getPackageName(), realUserId,
+                        flags, ceDataInode);
             } catch (InstallerException e) {
                 Slog.w(TAG, String.valueOf(e));
             }
-            mDexManager.notifyPackageDataDestroyed(pkg.packageName, userId);
+            mDexManager.notifyPackageDataDestroyed(pkg.getPackageName(), userId);
         }
     }
 
-    private void destroyAppProfilesLIF(PackageParser.Package pkg) {
+    private void destroyAppProfilesLIF(AndroidPackage pkg) {
         if (pkg == null) {
             Slog.wtf(TAG, "Package was null!", new Throwable());
             return;
         }
         destroyAppProfilesLeafLIF(pkg);
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            destroyAppProfilesLeafLIF(pkg.childPackages.get(i));
-        }
     }
 
-    private void destroyAppProfilesLeafLIF(PackageParser.Package pkg) {
+    private void destroyAppProfilesLeafLIF(AndroidPackage pkg) {
         try {
-            mInstaller.destroyAppProfiles(pkg.packageName);
+            mInstaller.destroyAppProfiles(pkg.getPackageName());
         } catch (InstallerException e) {
             Slog.w(TAG, String.valueOf(e));
         }
     }
 
-    private void clearAppProfilesLIF(PackageParser.Package pkg, int userId) {
+    private void clearAppProfilesLIF(AndroidPackage pkg, int userId) {
         if (pkg == null) {
             Slog.wtf(TAG, "Package was null!", new Throwable());
             return;
         }
         mArtManagerService.clearAppProfiles(pkg);
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            mArtManagerService.clearAppProfiles(pkg.childPackages.get(i));
-        }
-    }
-
-    private void setInstallAndUpdateTime(PackageParser.Package pkg, long firstInstallTime,
-            long lastUpdateTime) {
-        // Set parent install/update time
-        PackageSetting ps = (PackageSetting) pkg.mExtras;
-        if (ps != null) {
-            ps.firstInstallTime = firstInstallTime;
-            ps.lastUpdateTime = lastUpdateTime;
-        }
-        // Set children install/update time
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            PackageParser.Package childPkg = pkg.childPackages.get(i);
-            ps = (PackageSetting) childPkg.mExtras;
-            if (ps != null) {
-                ps.firstInstallTime = firstInstallTime;
-                ps.lastUpdateTime = lastUpdateTime;
-            }
-        }
     }
 
     @GuardedBy("mLock")
     private void applyDefiningSharedLibraryUpdateLocked(
-            PackageParser.Package pkg, SharedLibraryInfo libInfo,
+            AndroidPackage pkg, SharedLibraryInfo libInfo,
             BiConsumer<SharedLibraryInfo, SharedLibraryInfo> action) {
         // Note that libraries defined by this package may be null if:
         // - Package manager was unable to create the shared library. The package still
@@ -9776,14 +9789,14 @@
         // - Package manager is in a state where package isn't scanned yet. This will
         //   get called again after scanning to fix the dependencies.
         if (pkg.isLibrary()) {
-            if (pkg.staticSharedLibName != null) {
+            if (pkg.getStaticSharedLibName() != null) {
                 SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr(
-                        pkg.staticSharedLibName, pkg.staticSharedLibVersion);
+                        pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion());
                 if (definedLibrary != null) {
                     action.accept(definedLibrary, libInfo);
                 }
             } else {
-                for (String libraryName : pkg.libraryNames) {
+                for (String libraryName : pkg.getLibraryNames()) {
                     SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr(
                             libraryName, SharedLibraryInfo.VERSION_UNDEFINED);
                     if (definedLibrary != null) {
@@ -9795,19 +9808,19 @@
     }
 
     @GuardedBy("mLock")
-    private void addSharedLibraryLPr(PackageParser.Package pkg, Set<String> usesLibraryFiles,
-            SharedLibraryInfo libInfo, PackageParser.Package changingLib) {
+    private void addSharedLibraryLPr(AndroidPackage pkg, Set<String> usesLibraryFiles,
+            SharedLibraryInfo libInfo, AndroidPackage changingLib) {
         if (libInfo.getPath() != null) {
             usesLibraryFiles.add(libInfo.getPath());
             return;
         }
-        PackageParser.Package p = mPackages.get(libInfo.getPackageName());
-        if (changingLib != null && changingLib.packageName.equals(libInfo.getPackageName())) {
+        AndroidPackage p = mPackages.get(libInfo.getPackageName());
+        if (changingLib != null && changingLib.getPackageName().equals(libInfo.getPackageName())) {
             // If we are doing this while in the middle of updating a library apk,
             // then we need to make sure to use that new apk for determining the
             // dependencies here.  (We haven't yet finished committing the new apk
             // to the package manager state.)
-            if (p == null || p.packageName.equals(changingLib.packageName)) {
+            if (p == null || p.getPackageName().equals(changingLib.getPackageName())) {
                 p = changingLib;
             }
         }
@@ -9817,23 +9830,23 @@
             applyDefiningSharedLibraryUpdateLocked(pkg, libInfo, (definingLibrary, dependency) -> {
                 definingLibrary.addDependency(dependency);
             });
-            if (p.usesLibraryFiles != null) {
-                Collections.addAll(usesLibraryFiles, p.usesLibraryFiles);
+            if (p.getUsesLibraryFiles() != null) {
+                Collections.addAll(usesLibraryFiles, p.getUsesLibraryFiles());
             }
         }
     }
 
     @GuardedBy("mLock")
-    private void updateSharedLibrariesLocked(PackageParser.Package pkg,
-            PackageParser.Package changingLib, Map<String, PackageParser.Package> availablePackages)
+    private void updateSharedLibrariesLocked(AndroidPackage pkg,
+            AndroidPackage changingLib, Map<String, AndroidPackage> availablePackages)
                     throws PackageManagerException {
         final ArrayList<SharedLibraryInfo> sharedLibraryInfos =
                 collectSharedLibraryInfos(pkg, availablePackages, mSharedLibraries, null);
         executeSharedLibrariesUpdateLPr(pkg, changingLib, sharedLibraryInfos);
     }
 
-    private static ArrayList<SharedLibraryInfo> collectSharedLibraryInfos(PackageParser.Package pkg,
-            Map<String, PackageParser.Package> availablePackages,
+    private static ArrayList<SharedLibraryInfo> collectSharedLibraryInfos(AndroidPackage pkg,
+            Map<String, AndroidPackage> availablePackages,
             @NonNull final Map<String, LongSparseArray<SharedLibraryInfo>> existingLibraries,
             @Nullable final Map<String, LongSparseArray<SharedLibraryInfo>> newLibraries)
             throws PackageManagerException {
@@ -9844,44 +9857,45 @@
         // that libraries are searched in the correct order) and must have no
         // duplicates.
         ArrayList<SharedLibraryInfo> usesLibraryInfos = null;
-        if (pkg.usesLibraries != null) {
-            usesLibraryInfos = collectSharedLibraryInfos(pkg.usesLibraries, null, null,
-                    pkg.packageName, true, pkg.applicationInfo.targetSdkVersion, null,
+        if (pkg.getUsesLibraries() != null) {
+            usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesLibraries(), null, null,
+                    pkg.getPackageName(), true, pkg.getTargetSdkVersion(), null,
                     availablePackages, existingLibraries, newLibraries);
         }
-        if (pkg.usesStaticLibraries != null) {
-            usesLibraryInfos = collectSharedLibraryInfos(pkg.usesStaticLibraries,
-                    pkg.usesStaticLibrariesVersions, pkg.usesStaticLibrariesCertDigests,
-                    pkg.packageName, true, pkg.applicationInfo.targetSdkVersion, usesLibraryInfos,
+        if (pkg.getUsesStaticLibraries() != null) {
+            usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesStaticLibraries(),
+                    pkg.getUsesStaticLibrariesVersions(), pkg.getUsesStaticLibrariesCertDigests(),
+                    pkg.getPackageName(), true, pkg.getTargetSdkVersion(), usesLibraryInfos,
                     availablePackages, existingLibraries, newLibraries);
         }
-        if (pkg.usesOptionalLibraries != null) {
-            usesLibraryInfos = collectSharedLibraryInfos(pkg.usesOptionalLibraries,
-                    null, null, pkg.packageName, false, pkg.applicationInfo.targetSdkVersion,
+        if (pkg.getUsesOptionalLibraries() != null) {
+            usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesOptionalLibraries(),
+                    null, null, pkg.getPackageName(), false, pkg.getTargetSdkVersion(),
                     usesLibraryInfos, availablePackages, existingLibraries, newLibraries);
         }
         return usesLibraryInfos;
     }
 
-    private void executeSharedLibrariesUpdateLPr(PackageParser.Package pkg,
-            PackageParser.Package changingLib, ArrayList<SharedLibraryInfo> usesLibraryInfos) {
+    private void executeSharedLibrariesUpdateLPr(AndroidPackage pkg,
+            AndroidPackage changingLib, ArrayList<SharedLibraryInfo> usesLibraryInfos) {
         // If the package provides libraries, clear their old dependencies.
         // This method will set them up again.
         applyDefiningSharedLibraryUpdateLocked(pkg, null, (definingLibrary, dependency) -> {
             definingLibrary.clearDependencies();
         });
         if (usesLibraryInfos != null) {
-            pkg.usesLibraryInfos = usesLibraryInfos;
+            pkg.mutate().setUsesLibraryInfos(usesLibraryInfos);
             // Use LinkedHashSet to preserve the order of files added to
             // usesLibraryFiles while eliminating duplicates.
             Set<String> usesLibraryFiles = new LinkedHashSet<>();
             for (SharedLibraryInfo libInfo : usesLibraryInfos) {
                 addSharedLibraryLPr(pkg, usesLibraryFiles, libInfo, changingLib);
             }
-            pkg.usesLibraryFiles = usesLibraryFiles.toArray(new String[usesLibraryFiles.size()]);
+            pkg.mutate().setUsesLibraryFiles(usesLibraryFiles.toArray(
+                    new String[usesLibraryFiles.size()]));
         } else {
-            pkg.usesLibraryInfos = null;
-            pkg.usesLibraryFiles = null;
+            pkg.mutate().setUsesLibraryInfos(null)
+                    .setUsesLibraryFiles(null);
         }
     }
 
@@ -9891,7 +9905,7 @@
             @Nullable long[] requiredVersions, @Nullable String[][] requiredCertDigests,
             @NonNull String packageName, boolean required, int targetSdk,
             @Nullable ArrayList<SharedLibraryInfo> outUsedLibraries,
-            @NonNull final Map<String, PackageParser.Package> availablePackages,
+            @NonNull final Map<String, AndroidPackage> availablePackages,
             @NonNull final Map<String, LongSparseArray<SharedLibraryInfo>> existingLibraries,
             @Nullable final Map<String, LongSparseArray<SharedLibraryInfo>> newLibraries)
             throws PackageManagerException {
@@ -9920,8 +9934,8 @@
                                     + " library " + libName + " version "
                                     + libraryInfo.getLongVersion() + "; failing!");
                     }
-                    PackageParser.Package libPkg =
-                            availablePackages.get(libraryInfo.getPackageName());
+                    AndroidPackage pkg = availablePackages.get(libraryInfo.getPackageName());
+                    SigningDetails libPkg = pkg == null ? null : pkg.getSigningDetails();
                     if (libPkg == null) {
                         throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
                                 "Package " + packageName + " requires unavailable static shared"
@@ -9932,9 +9946,9 @@
                         // For apps targeting O MR1 we require explicit enumeration of all certs.
                         final String[] libCertDigests = (targetSdk >= Build.VERSION_CODES.O_MR1)
                                 ? PackageUtils.computeSignaturesSha256Digests(
-                                libPkg.mSigningDetails.signatures)
+                                libPkg.signatures)
                                 : PackageUtils.computeSignaturesSha256Digests(
-                                        new Signature[]{libPkg.mSigningDetails.signatures[0]});
+                                        new Signature[]{libPkg.signatures[0]});
 
                         // Take a shortcut if sizes don't match. Note that if an app doesn't
                         // target O we don't parse the "additional-certificate" tags similarly
@@ -9964,7 +9978,7 @@
                         // if the new one has been blessed by the old
                         byte[] digestBytes = HexEncoding.decode(
                                 expectedCertDigests[0], false /* allowSingleChar */);
-                        if (!libPkg.mSigningDetails.hasSha256Certificate(digestBytes)) {
+                        if (!libPkg.hasSha256Certificate(digestBytes)) {
                             throw new PackageManagerException(
                                     INSTALL_FAILED_MISSING_SHARED_LIBRARY,
                                     "Package " + packageName + " requires differently signed" +
@@ -9996,28 +10010,28 @@
     }
 
     @GuardedBy("mLock")
-    private ArrayList<PackageParser.Package> updateAllSharedLibrariesLocked(
-            PackageParser.Package updatedPkg,
-            Map<String, PackageParser.Package> availablePackages) {
-        ArrayList<PackageParser.Package> resultList = null;
+    private ArrayList<AndroidPackage> updateAllSharedLibrariesLocked(
+            AndroidPackage updatedPkg,
+            Map<String, AndroidPackage> availablePackages) {
+        ArrayList<AndroidPackage> resultList = null;
         // Set of all descendants of a library; used to eliminate cycles
         ArraySet<String> descendants = null;
         // The current list of packages that need updating
-        ArrayList<PackageParser.Package> needsUpdating = null;
+        ArrayList<AndroidPackage> needsUpdating = null;
         if (updatedPkg != null) {
             needsUpdating = new ArrayList<>(1);
             needsUpdating.add(updatedPkg);
         }
         do {
-            final PackageParser.Package changingPkg =
+            final AndroidPackage changingPkg =
                     (needsUpdating == null) ? null : needsUpdating.remove(0);
             for (int i = mPackages.size() - 1; i >= 0; --i) {
-                final PackageParser.Package pkg = mPackages.valueAt(i);
+                final AndroidPackage pkg = mPackages.valueAt(i);
                 if (changingPkg != null
-                        && !hasString(pkg.usesLibraries, changingPkg.libraryNames)
-                        && !hasString(pkg.usesOptionalLibraries, changingPkg.libraryNames)
-                        && !ArrayUtils.contains(pkg.usesStaticLibraries,
-                                changingPkg.staticSharedLibName)) {
+                        && !hasString(pkg.getUsesLibraries(), changingPkg.getLibraryNames())
+                        && !hasString(pkg.getUsesOptionalLibraries(), changingPkg.getLibraryNames())
+                        && !ArrayUtils.contains(pkg.getUsesStaticLibraries(),
+                                changingPkg.getStaticSharedLibName())) {
                     continue;
                 }
                 if (resultList == null) {
@@ -10029,8 +10043,8 @@
                     if (descendants == null) {
                         descendants = new ArraySet<>();
                     }
-                    if (!descendants.contains(pkg.packageName)) {
-                        descendants.add(pkg.packageName);
+                    if (!descendants.contains(pkg.getPackageName())) {
+                        descendants.add(pkg.getPackageName());
                         needsUpdating.add(pkg);
                     }
                 }
@@ -10045,8 +10059,9 @@
                     if (!pkg.isSystem() || pkg.isUpdatedSystemApp()) {
                         final int flags = pkg.isUpdatedSystemApp()
                                 ? PackageManager.DELETE_KEEP_DATA : 0;
-                        deletePackageLIF(pkg.packageName, null, true, mUserManager.getUserIds(),
-                                flags , null, true, null);
+                        deletePackageLIF(pkg.getPackageName(), null, true,
+                                mUserManager.getUserIds(), flags, null,
+                                true, null);
                     }
                     Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
                 }
@@ -10056,43 +10071,15 @@
     }
 
     @GuardedBy({"mInstallLock", "mLock"})
-    private List<ScanResult> scanPackageTracedLI(PackageParser.Package pkg,
+    private ScanResult scanPackageTracedLI(ParsedPackage parsedPackage,
             final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
             @Nullable UserHandle user) throws PackageManagerException {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage");
-        // If the package has children and this is the first dive in the function
-        // we recursively scan the package with the SCAN_CHECK_ONLY flag set to see
-        // whether all packages (parent and children) would be successfully scanned
-        // before the actual scan since scanning mutates internal state and we want
-        // to atomically install the package and its children.
-        if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
-            if (pkg.childPackages != null && pkg.childPackages.size() > 0) {
-                scanFlags |= SCAN_CHECK_ONLY;
-            }
-        } else {
-            scanFlags &= ~SCAN_CHECK_ONLY;
-        }
-
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        final List<ScanResult> scanResults = new ArrayList<>(1 + childCount);
         try {
-            // Scan the parent
-            scanResults.add(scanPackageNewLI(pkg, parseFlags, scanFlags, currentTime, user));
-            // Scan the children
-            for (int i = 0; i < childCount; i++) {
-                PackageParser.Package childPkg = pkg.childPackages.get(i);
-                scanResults.add(scanPackageNewLI(childPkg, parseFlags,
-                        scanFlags, currentTime, user));
-            }
+            return scanPackageNewLI(parsedPackage, parseFlags, scanFlags, currentTime, user);
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
-
-        if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
-            return scanPackageTracedLI(pkg, parseFlags, scanFlags, currentTime, user);
-        }
-
-        return scanResults;
     }
 
     /** The result of a package scan. */
@@ -10139,9 +10126,9 @@
     @VisibleForTesting
     static class ScanRequest {
         /** The parsed package */
-        @NonNull public final PackageParser.Package pkg;
+        @NonNull public final ParsedPackage parsedPackage;
         /** The package this package replaces */
-        @Nullable public final PackageParser.Package oldPkg;
+        @Nullable public final AndroidPackage oldPkg;
         /** Shared user settings, if the package has a shared user */
         @Nullable public final SharedUserSetting sharedUserSetting;
         /**
@@ -10165,9 +10152,9 @@
         /** Whether or not the platform package is being scanned */
         public final boolean isPlatformPackage;
         public ScanRequest(
-                @NonNull PackageParser.Package pkg,
+                @NonNull ParsedPackage parsedPackage,
                 @Nullable SharedUserSetting sharedUserSetting,
-                @Nullable PackageParser.Package oldPkg,
+                @Nullable AndroidPackage oldPkg,
                 @Nullable PackageSetting pkgSetting,
                 @Nullable PackageSetting disabledPkgSetting,
                 @Nullable PackageSetting originalPkgSetting,
@@ -10176,7 +10163,7 @@
                 @ScanFlags int scanFlags,
                 boolean isPlatformPackage,
                 @Nullable UserHandle user) {
-            this.pkg = pkg;
+            this.parsedPackage = parsedPackage;
             this.oldPkg = oldPkg;
             this.pkgSetting = pkgSetting;
             this.sharedUserSetting = sharedUserSetting;
@@ -10209,7 +10196,7 @@
      */
     private @ScanFlags int adjustScanFlags(@ScanFlags int scanFlags,
             PackageSetting pkgSetting, PackageSetting disabledPkgSetting, UserHandle user,
-            PackageParser.Package pkg) {
+            AndroidPackage pkg) {
 
         // TODO(patb): Do away entirely with disabledPkgSetting here. PkgSetting will always contain
         // the correct isSystem value now that we don't disable system packages before scan.
@@ -10261,12 +10248,14 @@
                 && SystemProperties.getInt("ro.vndk.version", 28) < 28;
         if (((scanFlags & SCAN_AS_PRIVILEGED) == 0)
                 && !pkg.isPrivileged()
-                && (pkg.mSharedUserId != null)
+                && (pkg.getSharedUserId() != null)
                 && !skipVendorPrivilegeScan) {
             SharedUserSetting sharedUserSetting = null;
             try {
-                sharedUserSetting = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, 0, false);
-            } catch (PackageManagerException ignore) {}
+                sharedUserSetting = mSettings.getSharedUserLPw(pkg.getSharedUserId(), 0,
+                        0, false);
+            } catch (PackageManagerException ignore) {
+            }
             if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) {
                 // Exempt SharedUsers signed with the platform key.
                 // TODO(b/72378145) Fix this exemption. Force signature apps
@@ -10275,7 +10264,8 @@
                 synchronized (mLock) {
                     PackageSetting platformPkgSetting = mSettings.mPackages.get("android");
                     if ((compareSignatures(platformPkgSetting.signatures.mSigningDetails.signatures,
-                                pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH)) {
+                            pkg.getSigningDetails().signatures)
+                            != PackageManager.SIGNATURE_MATCH)) {
                         scanFlags |= SCAN_AS_PRIVILEGED;
                     }
                 }
@@ -10290,46 +10280,50 @@
     // method. Also, we need to solve the problem of potentially creating a new shared user
     // setting. That can probably be done later and patch things up after the fact.
     @GuardedBy({"mInstallLock", "mLock"})
-    private ScanResult scanPackageNewLI(@NonNull PackageParser.Package pkg,
+    private ScanResult scanPackageNewLI(@NonNull ParsedPackage parsedPackage,
             final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
             @Nullable UserHandle user) throws PackageManagerException {
 
-        final String renamedPkgName = mSettings.getRenamedPackageLPr(pkg.mRealPackage);
-        final String realPkgName = getRealPackageName(pkg, renamedPkgName);
+        final String renamedPkgName = mSettings.getRenamedPackageLPr(
+                parsedPackage.getRealPackage());
+        final String realPkgName = getRealPackageName(parsedPackage, renamedPkgName);
         if (realPkgName != null) {
-            ensurePackageRenamed(pkg, renamedPkgName);
+            ensurePackageRenamed(parsedPackage, renamedPkgName);
         }
-        final PackageSetting originalPkgSetting = getOriginalPackageLocked(pkg, renamedPkgName);
-        final PackageSetting pkgSetting = mSettings.getPackageLPr(pkg.packageName);
+        final PackageSetting originalPkgSetting = getOriginalPackageLocked(parsedPackage,
+                renamedPkgName);
+        final PackageSetting pkgSetting = mSettings.getPackageLPr(parsedPackage.getPackageName());
         final PackageSetting disabledPkgSetting =
-                mSettings.getDisabledSystemPkgLPr(pkg.packageName);
+                mSettings.getDisabledSystemPkgLPr(parsedPackage.getPackageName());
 
-        if (mTransferedPackages.contains(pkg.packageName)) {
-            Slog.w(TAG, "Package " + pkg.packageName
+        if (mTransferredPackages.contains(parsedPackage.getPackageName())) {
+            Slog.w(TAG, "Package " + parsedPackage.getPackageName()
                     + " was transferred to another, but its .apk remains");
         }
 
-        scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user, pkg);
+        scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user, parsedPackage);
         synchronized (mLock) {
-            applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage);
-            assertPackageIsValid(pkg, parseFlags, scanFlags);
+            applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage);
+            assertPackageIsValid(parsedPackage, parseFlags, scanFlags);
 
             SharedUserSetting sharedUserSetting = null;
-            if (pkg.mSharedUserId != null) {
+            if (parsedPackage.getSharedUserId() != null) {
                 // SIDE EFFECTS; may potentially allocate a new shared user
-                sharedUserSetting = mSettings.getSharedUserLPw(
-                        pkg.mSharedUserId, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/);
+                sharedUserSetting = mSettings.getSharedUserLPw(parsedPackage.getSharedUserId(),
+                        0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/);
                 if (DEBUG_PACKAGE_SCANNING) {
                     if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
-                        Log.d(TAG, "Shared UserID " + pkg.mSharedUserId
+                        Log.d(TAG, "Shared UserID " + parsedPackage.getSharedUserId()
                                 + " (uid=" + sharedUserSetting.userId + "):"
                                 + " packages=" + sharedUserSetting.packages);
                 }
             }
-            final ScanRequest request = new ScanRequest(pkg, sharedUserSetting,
+            String platformPackageName = mPlatformPackage == null
+                    ? null : mPlatformPackage.getPackageName();
+            final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting,
                     pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting,
                     originalPkgSetting, realPkgName, parseFlags, scanFlags,
-                    (pkg == mPlatformPackage), user);
+                    Objects.equals(parsedPackage.getPackageName(), platformPackageName), user);
             return scanPackageOnlyLI(request, mInjector, mFactoryTest, currentTime);
         }
     }
@@ -10372,11 +10366,18 @@
      * possible and the system is not left in an inconsistent state.
      */
     @GuardedBy({"mLock", "mInstallLock"})
-    private void commitReconciledScanResultLocked(@NonNull ReconciledPackage reconciledPkg) {
+    private AndroidPackage commitReconciledScanResultLocked(
+            @NonNull ReconciledPackage reconciledPkg) {
         final ScanResult result = reconciledPkg.scanResult;
         final ScanRequest request = result.request;
-        final PackageParser.Package pkg = request.pkg;
-        final PackageParser.Package oldPkg = request.oldPkg;
+        // TODO(b/135203078): Move this even further away
+        ParsedPackage parsedPackage = request.parsedPackage;
+        if ("android".equals(parsedPackage.getPackageName())) {
+            // TODO(b/135203078): Move this to initial parse
+            parsedPackage.setVersionCode(mSdkVersion)
+                    .setVersionCodeMajor(0);
+        }
+        final AndroidPackage oldPkg = request.oldPkg;
         final @ParseFlags int parseFlags = request.parseFlags;
         final @ScanFlags int scanFlags = request.scanFlags;
         final PackageSetting oldPkgSetting = request.oldPkgSetting;
@@ -10393,14 +10394,12 @@
         if (result.existingSettingCopied) {
             pkgSetting = request.pkgSetting;
             pkgSetting.updateFrom(result.pkgSetting);
-            pkg.mExtras = pkgSetting;
         } else {
             pkgSetting = result.pkgSetting;
             if (originalPkgSetting != null) {
-                mSettings.addRenamedPackageLPw(pkg.packageName, originalPkgSetting.name);
-            }
-            if (originalPkgSetting != null && (scanFlags & SCAN_CHECK_ONLY) == 0) {
-                mTransferedPackages.add(originalPkgSetting.name);
+                mSettings.addRenamedPackageLPw(parsedPackage.getPackageName(),
+                        originalPkgSetting.name);
+                mTransferredPackages.add(originalPkgSetting.name);
             }
         }
         if (pkgSetting.sharedUser != null) {
@@ -10412,12 +10411,13 @@
         // We need to have this here because addUserToSettingLPw() is sometimes responsible
         // for creating the application ID. If we did this earlier, we would be saving the
         // correct ID.
-        pkg.applicationInfo.uid = pkgSetting.appId;
+        parsedPackage.setUid(pkgSetting.appId);
+        final AndroidPackage pkg = parsedPackage.hideAsFinal();
 
         mSettings.writeUserRestrictionsLPw(pkgSetting, oldPkgSetting);
 
-        if ((scanFlags & SCAN_CHECK_ONLY) == 0 && realPkgName != null) {
-            mTransferedPackages.add(pkg.packageName);
+        if (realPkgName != null) {
+            mTransferredPackages.add(pkg.getPackageName());
         }
 
         if (reconciledPkg.collectedSharedLibraryInfos != null) {
@@ -10426,7 +10426,7 @@
 
         final KeySetManagerService ksms = mSettings.mKeySetManagerService;
         if (reconciledPkg.removeAppKeySetData) {
-            ksms.removeAppKeySetDataLPw(pkg.packageName);
+            ksms.removeAppKeySetDataLPw(pkg.getPackageName());
         }
         if (reconciledPkg.sharedUserSignaturesChanged) {
             pkgSetting.sharedUser.signaturesChanged = Boolean.TRUE;
@@ -10434,17 +10434,17 @@
         }
         pkgSetting.signatures.mSigningDetails = reconciledPkg.signingDetails;
 
-        if ((scanFlags & SCAN_CHECK_ONLY) == 0 && pkg.mAdoptPermissions != null) {
+        if (pkg.getAdoptPermissions() != null) {
             // This package wants to adopt ownership of permissions from
             // another package.
-            for (int i = pkg.mAdoptPermissions.size() - 1; i >= 0; i--) {
-                final String origName = pkg.mAdoptPermissions.get(i);
+            for (int i = pkg.getAdoptPermissions().size() - 1; i >= 0; i--) {
+                final String origName = pkg.getAdoptPermissions().get(i);
                 final PackageSetting orig = mSettings.getPackageLPr(origName);
                 if (orig != null) {
                     if (verifyPackageUpdateLPr(orig, pkg)) {
                         Slog.i(TAG, "Adopting permissions from " + origName + " to "
-                                + pkg.packageName);
-                        mSettings.mPermissions.transferPermissions(origName, pkg.packageName);
+                                + pkg.getPackageName());
+                        mSettings.mPermissions.transferPermissions(origName, pkg.getPackageName());
                     }
                 }
             }
@@ -10461,21 +10461,15 @@
             }
         }
 
-        if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
-            if (oldPkgSetting != null) {
-                synchronized (mLock) {
-                    mSettings.mPackages.put(oldPkgSetting.name, oldPkgSetting);
-                }
-            }
-        } else {
-            final int userId = user == null ? 0 : user.getIdentifier();
-            // Modify state for the given package setting
-            commitPackageSettings(pkg, oldPkg, pkgSetting, scanFlags,
-                    (parseFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/, reconciledPkg);
-            if (pkgSetting.getInstantApp(userId)) {
-                mInstantAppRegistry.addInstantAppLPw(userId, pkgSetting.appId);
-            }
+        final int userId = user == null ? 0 : user.getIdentifier();
+        // Modify state for the given package setting
+        commitPackageSettings(pkg, oldPkg, pkgSetting, scanFlags,
+                (parseFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/, reconciledPkg);
+        if (pkgSetting.getInstantApp(userId)) {
+            mInstantAppRegistry.addInstantAppLPw(userId, pkgSetting.appId);
         }
+
+        return pkg;
     }
 
     /**
@@ -10483,18 +10477,19 @@
      * <p>This may differ from the package's actual name if the application has already
      * been installed under one of this package's original names.
      */
-    private static @Nullable String getRealPackageName(@NonNull PackageParser.Package pkg,
+    private static @Nullable String getRealPackageName(@NonNull AndroidPackage pkg,
             @Nullable String renamedPkgName) {
         if (isPackageRenamed(pkg, renamedPkgName)) {
-            return pkg.mRealPackage;
+            return pkg.getRealPackage();
         }
         return null;
     }
 
     /** Returns {@code true} if the package has been renamed. Otherwise, {@code false}. */
-    private static boolean isPackageRenamed(@NonNull PackageParser.Package pkg,
+    private static boolean isPackageRenamed(@NonNull AndroidPackage pkg,
             @Nullable String renamedPkgName) {
-        return pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(renamedPkgName);
+        return pkg.getOriginalPackages() != null
+                && pkg.getOriginalPackages().contains(renamedPkgName);
     }
 
     /**
@@ -10505,14 +10500,14 @@
      * shared user [if any].
      */
     @GuardedBy("mLock")
-    private @Nullable PackageSetting getOriginalPackageLocked(@NonNull PackageParser.Package pkg,
+    private @Nullable PackageSetting getOriginalPackageLocked(@NonNull AndroidPackage pkg,
             @Nullable String renamedPkgName) {
         if (!isPackageRenamed(pkg, renamedPkgName)) {
             return null;
         }
-        for (int i = pkg.mOriginalPackages.size() - 1; i >= 0; --i) {
+        for (int i = ArrayUtils.size(pkg.getOriginalPackages()) - 1; i >= 0; --i) {
             final PackageSetting originalPs =
-                    mSettings.getPackageLPr(pkg.mOriginalPackages.get(i));
+                    mSettings.getPackageLPr(pkg.getOriginalPackages().get(i));
             if (originalPs != null) {
                 // the package is already installed under its original name...
                 // but, should we use it?
@@ -10520,18 +10515,18 @@
                     // the new package is incompatible with the original
                     continue;
                 } else if (originalPs.sharedUser != null) {
-                    if (!originalPs.sharedUser.name.equals(pkg.mSharedUserId)) {
+                    if (!originalPs.sharedUser.name.equals(pkg.getSharedUserId())) {
                         // the shared user id is incompatible with the original
                         Slog.w(TAG, "Unable to migrate data from " + originalPs.name
-                                + " to " + pkg.packageName + ": old uid "
+                                + " to " + pkg.getPackageName() + ": old uid "
                                 + originalPs.sharedUser.name
-                                + " differs from " + pkg.mSharedUserId);
+                                + " differs from " + pkg.getSharedUserId());
                         continue;
                     }
                     // TODO: Add case when shared user id is added [b/28144775]
                 } else {
                     if (DEBUG_UPGRADE) Log.v(TAG, "Renaming new package "
-                            + pkg.packageName + " to old name " + originalPs.name);
+                            + pkg.getPackageName() + " to old name " + originalPs.name);
                 }
                 return originalPs;
             }
@@ -10544,19 +10539,19 @@
      * <p>When we've already installed the package under an original name, update
      * the new package so we can continue to have the old name.
      */
-    private static void ensurePackageRenamed(@NonNull PackageParser.Package pkg,
+    private static void ensurePackageRenamed(@NonNull ParsedPackage parsedPackage,
             @NonNull String renamedPackageName) {
-        if (pkg.mOriginalPackages == null
-                || !pkg.mOriginalPackages.contains(renamedPackageName)
-                || pkg.packageName.equals(renamedPackageName)) {
+        if (parsedPackage.getOriginalPackages() == null
+                || !parsedPackage.getOriginalPackages().contains(renamedPackageName)
+                || parsedPackage.getPackageName().equals(renamedPackageName)) {
             return;
         }
-        pkg.setPackageName(renamedPackageName);
+        parsedPackage.setPackageName(renamedPackageName);
     }
 
     /**
      * Applies the adjusted ABI calculated by
-     * {@link PackageAbiHelper#getAdjustedAbiForSharedUser(Set, PackageParser.Package)} to all
+     * {@link PackageAbiHelper#getAdjustedAbiForSharedUser(Set, AndroidPackage)} to all
      * relevant packages and settings.
      * @param sharedUserSetting The {@code SharedUserSetting} to adjust
      * @param scannedPackage the package being scanned or null
@@ -10564,22 +10559,20 @@
      * @return the list of code paths that belong to packages that had their ABIs adjusted.
      */
     private static List<String> applyAdjustedAbiToSharedUser(SharedUserSetting sharedUserSetting,
-            PackageParser.Package scannedPackage, String adjustedAbi) {
+            ParsedPackage scannedPackage, String adjustedAbi) {
         if (scannedPackage != null)  {
-            scannedPackage.applicationInfo.primaryCpuAbi = adjustedAbi;
+            scannedPackage.setPrimaryCpuAbi(adjustedAbi);
         }
         List<String> changedAbiCodePath = null;
         for (PackageSetting ps : sharedUserSetting.packages) {
-            if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
+            if (scannedPackage == null || !scannedPackage.getPackageName().equals(ps.name)) {
                 if (ps.primaryCpuAbiString != null) {
                     continue;
                 }
 
                 ps.primaryCpuAbiString = adjustedAbi;
-                if (ps.pkg != null && ps.pkg.applicationInfo != null
-                        && !TextUtils.equals(
-                        adjustedAbi, ps.pkg.applicationInfo.primaryCpuAbi)) {
-                    ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
+                if (ps.pkg != null && !TextUtils.equals(adjustedAbi, ps.pkg.getPrimaryCpuAbi())) {
+                    ps.pkg.mutate().setPrimaryCpuAbi(adjustedAbi);
                     if (DEBUG_ABI_SELECTION) {
                         Slog.i(TAG,
                                 "Adjusting ABI for " + ps.name + " to " + adjustedAbi
@@ -10601,42 +10594,42 @@
      * Sets the enabled state of components configured through {@link SystemConfig}.
      * This modifies the {@link PackageSetting} object.
      **/
-    static void configurePackageComponents(PackageParser.Package pkg) {
+    static void configurePackageComponents(AndroidPackage pkg) {
         final ArrayMap<String, Boolean> componentsEnabledStates = SystemConfig.getInstance()
-                .getComponentsEnabledStates(pkg.packageName);
+                .getComponentsEnabledStates(pkg.getPackageName());
         if (componentsEnabledStates == null) {
             return;
         }
 
-        for (int i = pkg.activities.size() - 1; i >= 0; i--) {
-            final PackageParser.Activity component = pkg.activities.get(i);
+        for (int i = ArrayUtils.size(pkg.getActivities()) - 1; i >= 0; i--) {
+            final ParsedActivity component = pkg.getActivities().get(i);
             final Boolean enabled = componentsEnabledStates.get(component.className);
             if (enabled != null) {
-                component.info.enabled = enabled;
+                component.setEnabled(enabled);
             }
         }
 
-        for (int i = pkg.receivers.size() - 1; i >= 0; i--) {
-            final PackageParser.Activity component = pkg.receivers.get(i);
+        for (int i = ArrayUtils.size(pkg.getReceivers()) - 1; i >= 0; i--) {
+            final ParsedActivity component = pkg.getReceivers().get(i);
             final Boolean enabled = componentsEnabledStates.get(component.className);
             if (enabled != null) {
-                component.info.enabled = enabled;
+                component.setEnabled(enabled);
             }
         }
 
-        for (int i = pkg.providers.size() - 1; i >= 0; i--) {
-            final PackageParser.Provider component = pkg.providers.get(i);
+        for (int i = ArrayUtils.size(pkg.getProviders()) - 1; i >= 0; i--) {
+            final ParsedProvider component = pkg.getProviders().get(i);
             final Boolean enabled = componentsEnabledStates.get(component.className);
             if (enabled != null) {
-                component.info.enabled = enabled;
+                component.setEnabled(enabled);
             }
         }
 
-        for (int i = pkg.services.size() - 1; i >= 0; i--) {
-            final PackageParser.Service component = pkg.services.get(i);
+        for (int i = ArrayUtils.size(pkg.getServices()) - 1; i >= 0; i--) {
+            final ParsedService component = pkg.getServices().get(i);
             final Boolean enabled = componentsEnabledStates.get(component.className);
             if (enabled != null) {
-                component.info.enabled = enabled;
+                component.setEnabled(enabled);
             }
         }
     }
@@ -10663,7 +10656,7 @@
             throws PackageManagerException {
         final PackageAbiHelper packageAbiHelper = injector.getAbiHelper();
         final UserManagerInternal userManager = injector.getUserManagerInternal();
-        final PackageParser.Package pkg = request.pkg;
+        ParsedPackage parsedPackage = request.parsedPackage;
         PackageSetting pkgSetting = request.pkgSetting;
         final PackageSetting disabledPkgSetting = request.disabledPkgSetting;
         final PackageSetting originalPkgSetting = request.originalPkgSetting;
@@ -10678,13 +10671,12 @@
 
         if (DEBUG_PACKAGE_SCANNING) {
             if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
-                Log.d(TAG, "Scanning package " + pkg.packageName);
+                Log.d(TAG, "Scanning package " + parsedPackage.getPackageName());
         }
 
         // Initialize package source and resource directories
-        final File scanFile = new File(pkg.codePath);
-        final File destCodeFile = new File(pkg.applicationInfo.getCodePath());
-        final File destResourceFile = new File(pkg.applicationInfo.getResourcePath());
+        final File destCodeFile = new File(parsedPackage.getAppInfoCodePath());
+        final File destResourceFile = new File(parsedPackage.getAppInfoResourcePath());
 
         // We keep references to the derived CPU Abis from settings in oder to reuse
         // them in the case where we're not upgrading or booting for the first time.
@@ -10703,7 +10695,7 @@
 
         if (pkgSetting != null && pkgSetting.sharedUser != sharedUserSetting) {
             PackageManagerService.reportSettingsProblem(Log.WARN,
-                    "Package " + pkg.packageName + " shared user changed from "
+                    "Package " + parsedPackage.getPackageName() + " shared user changed from "
                             + (pkgSetting.sharedUser != null
                             ? pkgSetting.sharedUser.name : "<nothing>")
                             + " to "
@@ -10713,30 +10705,28 @@
         }
 
         String[] usesStaticLibraries = null;
-        if (pkg.usesStaticLibraries != null) {
-            usesStaticLibraries = new String[pkg.usesStaticLibraries.size()];
-            pkg.usesStaticLibraries.toArray(usesStaticLibraries);
+        if (parsedPackage.getUsesStaticLibraries() != null) {
+            usesStaticLibraries = new String[parsedPackage.getUsesStaticLibraries().size()];
+            parsedPackage.getUsesStaticLibraries().toArray(usesStaticLibraries);
         }
         final boolean createNewPackage = (pkgSetting == null);
         if (createNewPackage) {
-            final String parentPackageName = (pkg.parentPackage != null)
-                    ? pkg.parentPackage.packageName : null;
             final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
             final boolean virtualPreload = (scanFlags & SCAN_AS_VIRTUAL_PRELOAD) != 0;
             // REMOVE SharedUserSetting from method; update in a separate call
-            pkgSetting = Settings.createNewSetting(pkg.packageName, originalPkgSetting,
-                    disabledPkgSetting, realPkgName, sharedUserSetting, destCodeFile,
-                    destResourceFile, pkg.applicationInfo.nativeLibraryRootDir,
-                    pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi,
-                    pkg.mVersionCode, pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,
-                    user, true /*allowInstall*/, instantApp, virtualPreload,
-                    parentPackageName, pkg.getChildPackageNames(),
-                    UserManagerService.getInstance(), usesStaticLibraries,
-                    pkg.usesStaticLibrariesVersions);
+            pkgSetting = Settings.createNewSetting(parsedPackage.getPackageName(),
+                    originalPkgSetting, disabledPkgSetting, realPkgName, sharedUserSetting,
+                    destCodeFile, destResourceFile, parsedPackage.getNativeLibraryRootDir(),
+                    parsedPackage.getPrimaryCpuAbi(), parsedPackage.getSecondaryCpuAbi(),
+                    parsedPackage.getVersionCode(), parsedPackage.getFlags(),
+                    parsedPackage.getPrivateFlags(), user, true /*allowInstall*/, instantApp,
+                    virtualPreload, UserManagerService.getInstance(), usesStaticLibraries,
+                    parsedPackage.getUsesStaticLibrariesVersions());
         } else {
             // make a deep copy to avoid modifying any existing system state.
             pkgSetting = new PackageSetting(pkgSetting);
-            pkgSetting.pkg = pkg;
+            // TODO(b/135203078): Remove entirely. Set package directly.
+            parsedPackage.setPackageSettingCallback(pkgSetting);
 
             // REMOVE SharedUserSetting from method; update in a separate call.
             //
@@ -10744,18 +10734,18 @@
             // secondaryCpuAbi are not known at this point so we always update them
             // to null here, only to reset them at a later point.
             Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, sharedUserSetting,
-                    destCodeFile, destResourceFile, pkg.applicationInfo.nativeLibraryDir,
-                    pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi,
-                    pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,
-                    pkg.getChildPackageNames(), UserManagerService.getInstance(),
-                    usesStaticLibraries, pkg.usesStaticLibrariesVersions);
+                    destCodeFile, destResourceFile, parsedPackage.getNativeLibraryDir(),
+                    parsedPackage.getPrimaryCpuAbi(), parsedPackage.getSecondaryCpuAbi(),
+                    parsedPackage.getFlags(), parsedPackage.getPrivateFlags(),
+                    UserManagerService.getInstance(),
+                    usesStaticLibraries, parsedPackage.getUsesStaticLibrariesVersions());
         }
         if (createNewPackage && originalPkgSetting != null) {
             // This is the initial transition from the original package, so,
             // fix up the new package's name now. We must do this after looking
             // up the package under its new name, so getPackageLP takes care of
             // fiddling things correctly.
-            pkg.setPackageName(originalPkgSetting.name);
+            parsedPackage.setPackageName(originalPkgSetting.name);
 
             // File a report about this.
             String msg = "New package " + pkgSetting.realName
@@ -10774,84 +10764,69 @@
         if (disabledPkgSetting != null
                 || (0 != (scanFlags & SCAN_NEW_INSTALL)
                 && pkgSetting != null && pkgSetting.isSystem())) {
-            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+            parsedPackage.mutate().setUpdatedSystemApp(true);
         }
 
-        // Apps which share a sharedUserId must be placed in the same selinux domain. If this
-        // package is the first app installed as this shared user, set seInfoTargetSdkVersion to its
-        // targetSdkVersion. These are later adjusted in PackageManagerService's constructor to be
-        // the lowest targetSdkVersion of all apps within the shared user, which corresponds to the
-        // least restrictive selinux domain.
-        // NOTE: As new packages are installed / updated, the shared user's seinfoTargetSdkVersion
-        // will NOT be modified until next boot, even if a lower targetSdkVersion is used. This
-        // ensures that all packages continue to run in the same selinux domain.
-        final int targetSdkVersion =
-            ((sharedUserSetting != null) && (sharedUserSetting.packages.size() != 0)) ?
-            sharedUserSetting.seInfoTargetSdkVersion : pkg.applicationInfo.targetSdkVersion;
-        // TODO(b/71593002): isPrivileged for sharedUser and appInfo should never be out of sync.
-        // They currently can be if the sharedUser apps are signed with the platform key.
-        final boolean isPrivileged = (sharedUserSetting != null) ?
-            sharedUserSetting.isPrivileged() | pkg.isPrivileged() : pkg.isPrivileged();
-
-        pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, isPrivileged,
-                targetSdkVersion);
-        pkg.applicationInfo.seInfoUser = SELinuxUtil.assignSeinfoUser(pkgSetting.readUserState(
-                userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId));
-
-        pkg.mExtras = pkgSetting;
-        pkg.applicationInfo.processName = fixProcessName(
-                pkg.applicationInfo.packageName,
-                pkg.applicationInfo.processName);
+        parsedPackage
+                .setSeInfo(SELinuxMMAC.getSeInfo(parsedPackage, sharedUserSetting,
+                        injector.getCompatibility()))
+                .setSeInfoUser(SELinuxUtil.assignSeinfoUser(pkgSetting.readUserState(
+                        userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId)))
+                .setProcessName(fixProcessName(parsedPackage.getPackageName(),
+                        parsedPackage.getProcessName()));
 
         if (!isPlatformPackage) {
             // Get all of our default paths setup
-            pkg.applicationInfo.initForUser(UserHandle.USER_SYSTEM);
+            parsedPackage.initForUser(UserHandle.USER_SYSTEM);
         }
 
-        if (pkg.isSystem()) {
-            configurePackageComponents(pkg);
+        if (parsedPackage.isSystem()) {
+            configurePackageComponents(parsedPackage);
         }
 
-        final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, pkgSetting);
+        final String cpuAbiOverride = deriveAbiOverride(parsedPackage.getCpuAbiOverride(),
+                pkgSetting);
 
         if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
             if (needToDeriveAbi) {
                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
-                final boolean extractNativeLibs = !pkg.isLibrary();
+                final boolean extractNativeLibs = !parsedPackage.isLibrary();
                 final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi =
-                        packageAbiHelper.derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs);
-                derivedAbi.first.applyTo(pkg);
-                derivedAbi.second.applyTo(pkg);
+                        packageAbiHelper.derivePackageAbi(parsedPackage, cpuAbiOverride,
+                                extractNativeLibs);
+                derivedAbi.first.applyTo(parsedPackage);
+                derivedAbi.second.applyTo(parsedPackage);
                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
 
                 // Some system apps still use directory structure for native libraries
                 // in which case we might end up not detecting abi solely based on apk
                 // structure. Try to detect abi based on directory structure.
-                if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&
-                        pkg.applicationInfo.primaryCpuAbi == null) {
+                if (isSystemApp(parsedPackage) && !parsedPackage.isUpdatedSystemApp() &&
+                        parsedPackage.getPrimaryCpuAbi() == null) {
                     final PackageAbiHelper.Abis abis = packageAbiHelper.getBundledAppAbis(
-                            pkg);
-                    abis.applyTo(pkg);
+                            parsedPackage);
+                    abis.applyTo(parsedPackage);
                     abis.applyTo(pkgSetting);
                     final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
-                            packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
-                    nativeLibraryPaths.applyTo(pkg);
+                            packageAbiHelper.getNativeLibraryPaths(parsedPackage,
+                                    sAppLib32InstallDir);
+                    nativeLibraryPaths.applyTo(parsedPackage);
                 }
             } else {
                 // This is not a first boot or an upgrade, don't bother deriving the
                 // ABI during the scan. Instead, trust the value that was stored in the
                 // package setting.
-                pkg.applicationInfo.primaryCpuAbi = primaryCpuAbiFromSettings;
-                pkg.applicationInfo.secondaryCpuAbi = secondaryCpuAbiFromSettings;
+                parsedPackage.setPrimaryCpuAbi(primaryCpuAbiFromSettings)
+                        .setSecondaryCpuAbi(secondaryCpuAbiFromSettings);
 
                 final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
-                        packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
-                nativeLibraryPaths.applyTo(pkg);
+                        packageAbiHelper.getNativeLibraryPaths(parsedPackage, sAppLib32InstallDir);
+                nativeLibraryPaths.applyTo(parsedPackage);
 
                 if (DEBUG_ABI_SELECTION) {
                     Slog.i(TAG, "Using ABIS and native lib paths from settings : " +
-                            pkg.packageName + " " + pkg.applicationInfo.primaryCpuAbi + ", " +
-                            pkg.applicationInfo.secondaryCpuAbi);
+                            parsedPackage.getPackageName() + " " + parsedPackage.getPrimaryCpuAbi()
+                            + ", " + parsedPackage.getSecondaryCpuAbi());
                 }
             }
         } else {
@@ -10859,8 +10834,8 @@
                 // We haven't run dex-opt for this move (since we've moved the compiled output too)
                 // but we already have this packages package info in the PackageSetting. We just
                 // use that and derive the native library path based on the new codepath.
-                pkg.applicationInfo.primaryCpuAbi = pkgSetting.primaryCpuAbiString;
-                pkg.applicationInfo.secondaryCpuAbi = pkgSetting.secondaryCpuAbiString;
+                parsedPackage.setPrimaryCpuAbi(pkgSetting.primaryCpuAbiString)
+                        .setSecondaryCpuAbi(pkgSetting.secondaryCpuAbiString);
             }
 
             // Set native library paths again. For moves, the path will be updated based on the
@@ -10868,8 +10843,8 @@
             // ABIs we determined during compilation, but the path will depend on the final
             // package path (after the rename away from the stage path).
             final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
-                    packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
-            nativeLibraryPaths.applyTo(pkg);
+                    packageAbiHelper.getNativeLibraryPaths(parsedPackage, sAppLib32InstallDir);
+            nativeLibraryPaths.applyTo(parsedPackage);
         }
 
         // This is a special case for the "system" package, where the ABI is
@@ -10877,8 +10852,8 @@
         // of this ABI so that we can deal with "normal" applications that run under
         // the same UID correctly.
         if (isPlatformPackage) {
-            pkg.applicationInfo.primaryCpuAbi = VMRuntime.getRuntime().is64Bit() ?
-                    Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0];
+            parsedPackage.setPrimaryCpuAbi(VMRuntime.getRuntime().is64Bit() ?
+                    Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0]);
         }
 
         // If there's a mismatch between the abi-override in the package setting
@@ -10886,34 +10861,34 @@
         // would've already compiled the app without taking the package setting into
         // account.
         if ((scanFlags & SCAN_NO_DEX) == 0 && (scanFlags & SCAN_NEW_INSTALL) != 0) {
-            if (cpuAbiOverride == null && pkg.packageName != null) {
+            if (cpuAbiOverride == null && parsedPackage.getPackageName() != null) {
                 Slog.w(TAG, "Ignoring persisted ABI override " + cpuAbiOverride +
-                        " for package " + pkg.packageName);
+                        " for package " + parsedPackage.getPackageName());
             }
         }
 
-        pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
-        pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
+        pkgSetting.primaryCpuAbiString = parsedPackage.getPrimaryCpuAbi();
+        pkgSetting.secondaryCpuAbiString = parsedPackage.getSecondaryCpuAbi();
         pkgSetting.cpuAbiOverrideString = cpuAbiOverride;
 
         // Copy the derived override back to the parsed package, so that we can
         // update the package settings accordingly.
-        pkg.cpuAbiOverride = cpuAbiOverride;
+        parsedPackage.setCpuAbiOverride(cpuAbiOverride);
 
         if (DEBUG_ABI_SELECTION) {
-            Slog.d(TAG, "Resolved nativeLibraryRoot for " + pkg.packageName
-                    + " to root=" + pkg.applicationInfo.nativeLibraryRootDir + ", isa="
-                    + pkg.applicationInfo.nativeLibraryRootRequiresIsa);
+            Slog.d(TAG, "Resolved nativeLibraryRoot for " + parsedPackage.getPackageName()
+                    + " to root=" + parsedPackage.getNativeLibraryRootDir() + ", isa="
+                    + parsedPackage.isNativeLibraryRootRequiresIsa());
         }
 
         // Push the derived path down into PackageSettings so we know what to
         // clean up at uninstall time.
-        pkgSetting.legacyNativeLibraryPathString = pkg.applicationInfo.nativeLibraryRootDir;
+        pkgSetting.legacyNativeLibraryPathString = parsedPackage.getNativeLibraryRootDir();
 
         if (DEBUG_ABI_SELECTION) {
-            Log.d(TAG, "Abis for package[" + pkg.packageName + "] are" +
-                    " primary=" + pkg.applicationInfo.primaryCpuAbi +
-                    " secondary=" + pkg.applicationInfo.secondaryCpuAbi);
+            Log.d(TAG, "Abis for package[" + parsedPackage.getPackageName() + "] are" +
+                    " primary=" + parsedPackage.getPrimaryCpuAbi() +
+                    " secondary=" + parsedPackage.getSecondaryCpuAbi());
         }
 
         if ((scanFlags & SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) {
@@ -10923,22 +10898,20 @@
             // We also do this *before* we perform dexopt on this package, so that
             // we can avoid redundant dexopts, and also to make sure we've got the
             // code and package path correct.
-            changedAbiCodePath = applyAdjustedAbiToSharedUser(pkgSetting.sharedUser, pkg,
+            changedAbiCodePath = applyAdjustedAbiToSharedUser(pkgSetting.sharedUser, parsedPackage,
                     packageAbiHelper.getAdjustedAbiForSharedUser(
-                            pkgSetting.sharedUser.packages, pkg));
+                            pkgSetting.sharedUser.packages, parsedPackage));
         }
 
-        if (isUnderFactoryTest && pkg.requestedPermissions.contains(
-                android.Manifest.permission.FACTORY_TEST)) {
-            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
-        }
+        parsedPackage.setFactoryTest(isUnderFactoryTest && parsedPackage.getRequestedPermissions()
+                .contains(android.Manifest.permission.FACTORY_TEST));
 
-        if (isSystemApp(pkg)) {
+        if (parsedPackage.isSystem()) {
             pkgSetting.setIsOrphaned(true);
         }
 
         // Take care of first install / last update times.
-        final long scanFileTime = getLastModifiedTime(pkg);
+        final long scanFileTime = getLastModifiedTime(parsedPackage);
         if (currentTime != 0) {
             if (pkgSetting.firstInstallTime == 0) {
                 pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = currentTime;
@@ -10956,32 +10929,33 @@
             }
         }
         pkgSetting.setTimeStamp(scanFileTime);
-
-        pkgSetting.pkg = pkg;
-        pkgSetting.pkgFlags = pkg.applicationInfo.flags;
-        if (pkg.getLongVersionCode() != pkgSetting.versionCode) {
-            pkgSetting.versionCode = pkg.getLongVersionCode();
+        // TODO(b/135203078): Remove, move to constructor
+        parsedPackage.setPackageSettingCallback(pkgSetting);
+        pkgSetting.pkgFlags = parsedPackage.getFlags();
+        if (parsedPackage.getLongVersionCode() != pkgSetting.versionCode) {
+            pkgSetting.versionCode = parsedPackage.getLongVersionCode();
         }
         // Update volume if needed
-        final String volumeUuid = pkg.applicationInfo.volumeUuid;
+        final String volumeUuid = parsedPackage.getApplicationInfoVolumeUuid();
         if (!Objects.equals(volumeUuid, pkgSetting.volumeUuid)) {
             Slog.i(PackageManagerService.TAG,
                     "Update" + (pkgSetting.isSystem() ? " system" : "")
-                    + " package " + pkg.packageName
+                    + " package " + parsedPackage.getPackageName()
                     + " volume from " + pkgSetting.volumeUuid
                     + " to " + volumeUuid);
             pkgSetting.volumeUuid = volumeUuid;
         }
 
         SharedLibraryInfo staticSharedLibraryInfo = null;
-        if (!TextUtils.isEmpty(pkg.staticSharedLibName)) {
-            staticSharedLibraryInfo = SharedLibraryInfo.createForStatic(pkg);
+        if (!TextUtils.isEmpty(parsedPackage.getStaticSharedLibName())) {
+            staticSharedLibraryInfo = SharedLibraryInfo.createForStatic(parsedPackage);
         }
         List<SharedLibraryInfo> dynamicSharedLibraryInfos = null;
-        if (!ArrayUtils.isEmpty(pkg.libraryNames)) {
-            dynamicSharedLibraryInfos = new ArrayList<>(pkg.libraryNames.size());
-            for (String name : pkg.libraryNames) {
-                dynamicSharedLibraryInfos.add(SharedLibraryInfo.createForDynamic(pkg, name));
+        if (!ArrayUtils.isEmpty(parsedPackage.getLibraryNames())) {
+            dynamicSharedLibraryInfos = new ArrayList<>(parsedPackage.getLibraryNames().size());
+            for (String name : parsedPackage.getLibraryNames()) {
+                dynamicSharedLibraryInfos.add(
+                        SharedLibraryInfo.createForDynamic(parsedPackage, name));
             }
         }
 
@@ -11017,22 +10991,21 @@
      *
      * @throws PackageManagerException If bytecode could not be found when it should exist
      */
-    private static void assertCodePolicy(PackageParser.Package pkg)
+    private static void assertCodePolicy(AndroidPackage pkg)
             throws PackageManagerException {
-        final boolean shouldHaveCode =
-                (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0;
-        if (shouldHaveCode && !apkHasCode(pkg.baseCodePath)) {
+        final boolean shouldHaveCode = (pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) != 0;
+        if (shouldHaveCode && !apkHasCode(pkg.getBaseCodePath())) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
-                    "Package " + pkg.baseCodePath + " code is missing");
+                    "Package " + pkg.getBaseCodePath() + " code is missing");
         }
 
-        if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
-            for (int i = 0; i < pkg.splitCodePaths.length; i++) {
+        if (!ArrayUtils.isEmpty(pkg.getSplitCodePaths())) {
+            for (int i = 0; i < pkg.getSplitCodePaths().length; i++) {
                 final boolean splitShouldHaveCode =
-                        (pkg.splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0;
-                if (splitShouldHaveCode && !apkHasCode(pkg.splitCodePaths[i])) {
+                        (pkg.getSplitFlags()[i] & ApplicationInfo.FLAG_HAS_CODE) != 0;
+                if (splitShouldHaveCode && !apkHasCode(pkg.getSplitCodePaths()[i])) {
                     throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
-                            "Package " + pkg.splitCodePaths[i] + " code is missing");
+                            "Package " + pkg.getSplitCodePaths()[i] + " code is missing");
                 }
             }
         }
@@ -11045,118 +11018,59 @@
      * Implementation detail: This method must NOT have any side effect. It would
      * ideally be static, but, it requires locks to read system state.
      */
-    private static void applyPolicy(PackageParser.Package pkg, final @ParseFlags int parseFlags,
-            final @ScanFlags int scanFlags, PackageParser.Package platformPkg) {
+    private static void applyPolicy(ParsedPackage parsedPackage, final @ParseFlags int parseFlags,
+            final @ScanFlags int scanFlags, AndroidPackage platformPkg) {
         if ((scanFlags & SCAN_AS_SYSTEM) != 0) {
-            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
-            if (pkg.applicationInfo.isDirectBootAware()) {
-                // we're direct boot aware; set for all components
-                for (PackageParser.Service s : pkg.services) {
-                    s.info.directBootAware = true;
-                }
-                for (PackageParser.Provider p : pkg.providers) {
-                    p.info.directBootAware = true;
-                }
-                for (PackageParser.Activity a : pkg.activities) {
-                    a.info.directBootAware = true;
-                }
-                for (PackageParser.Activity r : pkg.receivers) {
-                    r.info.directBootAware = true;
-                }
+            parsedPackage.setSystem(true);
+            // TODO(b/135203078): Can this be done in PackageParser? Or just inferred when the flag
+            //  is set during parse.
+            if (parsedPackage.isDirectBootAware()) {
+                parsedPackage.setAllComponentsDirectBootAware(true);
             }
-            if (compressedFileExists(pkg.codePath)) {
-                pkg.isStub = true;
+            if (compressedFileExists(parsedPackage.getCodePath())) {
+                parsedPackage.setIsStub(true);
             }
         } else {
-            // non system apps can't be flagged as core
-            pkg.coreApp = false;
-            // clear flags not applicable to regular apps
-            pkg.applicationInfo.flags &=
-                    ~ApplicationInfo.FLAG_PERSISTENT;
-            pkg.applicationInfo.privateFlags &=
-                    ~ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
-            pkg.applicationInfo.privateFlags &=
-                    ~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
-            // cap permission priorities
-            if (pkg.permissionGroups != null && pkg.permissionGroups.size() > 0) {
-                for (int i = pkg.permissionGroups.size() - 1; i >= 0; --i) {
-                    pkg.permissionGroups.get(i).info.priority = 0;
-                }
-            }
+            parsedPackage
+                    // non system apps can't be flagged as core
+                    .setCoreApp(false)
+                    // clear flags not applicable to regular apps
+                    .setPersistent(false)
+                    .setDefaultToDeviceProtectedStorage(false)
+                    .setDirectBootAware(false)
+                    // non system apps can't have permission priority
+                    .capPermissionPriorities();
         }
         if ((scanFlags & SCAN_AS_PRIVILEGED) == 0) {
-            // clear protected broadcasts
-            pkg.protectedBroadcasts = null;
-            // ignore export request for single user receivers
-            if (pkg.receivers != null) {
-                for (int i = pkg.receivers.size() - 1; i >= 0; --i) {
-                    final PackageParser.Activity receiver = pkg.receivers.get(i);
-                    if ((receiver.info.flags & ActivityInfo.FLAG_SINGLE_USER) != 0) {
-                        receiver.info.exported = false;
-                    }
-                }
-            }
-            // ignore export request for single user services
-            if (pkg.services != null) {
-                for (int i = pkg.services.size() - 1; i >= 0; --i) {
-                    final PackageParser.Service service = pkg.services.get(i);
-                    if ((service.info.flags & ServiceInfo.FLAG_SINGLE_USER) != 0) {
-                        service.info.exported = false;
-                    }
-                }
-            }
-            // ignore export request for single user providers
-            if (pkg.providers != null) {
-                for (int i = pkg.providers.size() - 1; i >= 0; --i) {
-                    final PackageParser.Provider provider = pkg.providers.get(i);
-                    if ((provider.info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0) {
-                        provider.info.exported = false;
-                    }
-                }
-            }
+            parsedPackage
+                    .clearProtectedBroadcasts()
+                    .markNotActivitiesAsNotExportedIfSingleUser();
         }
 
-        if ((scanFlags & SCAN_AS_PRIVILEGED) != 0) {
-            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
-        }
-
-        if ((scanFlags & SCAN_AS_OEM) != 0) {
-            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_OEM;
-        }
-
-        if ((scanFlags & SCAN_AS_VENDOR) != 0) {
-            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VENDOR;
-        }
-
-        if ((scanFlags & SCAN_AS_PRODUCT) != 0) {
-            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRODUCT;
-        }
-
-        if ((scanFlags & SCAN_AS_SYSTEM_EXT) != 0) {
-            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT;
-        }
-
-        if ((scanFlags & SCAN_AS_ODM) != 0) {
-            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ODM;
-        }
+        parsedPackage.setPrivileged((scanFlags & SCAN_AS_PRIVILEGED) != 0)
+                .setOem((scanFlags & SCAN_AS_OEM) != 0)
+                .setVendor((scanFlags & SCAN_AS_VENDOR) != 0)
+                .setProduct((scanFlags & SCAN_AS_PRODUCT) != 0)
+                .setSystemExt((scanFlags & SCAN_AS_SYSTEM_EXT) != 0)
+                .setOdm((scanFlags & SCAN_AS_ODM) != 0);
 
         // Check if the package is signed with the same key as the platform package.
-        if (PLATFORM_PACKAGE_NAME.equals(pkg.packageName) ||
-                (platformPkg != null && compareSignatures(
-                        platformPkg.mSigningDetails.signatures,
-                        pkg.mSigningDetails.signatures) == PackageManager.SIGNATURE_MATCH)) {
-            pkg.applicationInfo.privateFlags |=
-                ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY;
-        }
+        parsedPackage.setSignedWithPlatformKey(
+                (PLATFORM_PACKAGE_NAME.equals(parsedPackage.getPackageName())
+                        || (platformPkg != null && compareSignatures(
+                        platformPkg.getSigningDetails().signatures,
+                        parsedPackage.getSigningDetails().signatures
+                ) == PackageManager.SIGNATURE_MATCH))
+        );
 
-        if (!isSystemApp(pkg)) {
+        if (!isSystemApp(parsedPackage)) {
             // Only system apps can use these features.
-            pkg.mOriginalPackages = null;
-            pkg.mRealPackage = null;
-            pkg.mAdoptPermissions = null;
+            parsedPackage.clearOriginalPackages()
+                    .setRealPackage(null)
+                    .clearAdoptPermissions();
         }
 
-        PackageBackwardCompatibility.modifySharedLibraries(pkg);
+        PackageBackwardCompatibility.modifySharedLibraries(parsedPackage);
     }
 
     private static @NonNull <T> T assertNotNull(@Nullable T object, String message)
@@ -11176,15 +11090,15 @@
      *
      * @throws PackageManagerException If the package fails any of the validation checks
      */
-    private void assertPackageIsValid(PackageParser.Package pkg, final @ParseFlags int parseFlags,
+    private void assertPackageIsValid(AndroidPackage pkg, final @ParseFlags int parseFlags,
             final @ScanFlags int scanFlags)
                     throws PackageManagerException {
         if ((parseFlags & PackageParser.PARSE_ENFORCE_CODE) != 0) {
             assertCodePolicy(pkg);
         }
 
-        if (pkg.applicationInfo.getCodePath() == null ||
-                pkg.applicationInfo.getResourcePath() == null) {
+        if (pkg.getAppInfoCodePath() == null ||
+                pkg.getAppInfoResourcePath() == null) {
             // Bail out. The resource and code paths haven't been set.
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                     "Code and resource paths haven't been set correctly");
@@ -11195,9 +11109,10 @@
         final boolean isUserInstall = (scanFlags & SCAN_BOOTING) == 0;
         final boolean isFirstBootOrUpgrade = (scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0;
         if ((isUserInstall || isFirstBootOrUpgrade)
-                && mApexManager.isApexPackage(pkg.packageName)) {
+                && mApexManager.isApexPackage(pkg.getPackageName())) {
             throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
-                    pkg.packageName + " is an APEX package and can't be installed as an APK.");
+                    pkg.getPackageName()
+                            + " is an APEX package and can't be installed as an APK.");
         }
 
         // Make sure we're not adding any bogus keyset info
@@ -11206,11 +11121,11 @@
 
         synchronized (mLock) {
             // The special "android" package can only be defined once
-            if (pkg.packageName.equals("android")) {
+            if (pkg.getPackageName().equals("android")) {
                 if (mAndroidApplication != null) {
                     Slog.w(TAG, "*************************************************");
                     Slog.w(TAG, "Core android package being redefined.  Skipping.");
-                    Slog.w(TAG, " codePath=" + pkg.codePath);
+                    Slog.w(TAG, " codePath=" + pkg.getCodePath());
                     Slog.w(TAG, "*************************************************");
                     throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
                             "Core android package being redefined.  Skipping.");
@@ -11218,23 +11133,24 @@
             }
 
             // A package name must be unique; don't allow duplicates
-            if ((scanFlags & SCAN_NEW_INSTALL) == 0 && mPackages.containsKey(pkg.packageName)) {
+            if ((scanFlags & SCAN_NEW_INSTALL) == 0
+                    && mPackages.containsKey(pkg.getPackageName())) {
                 throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
-                        "Application package " + pkg.packageName
+                        "Application package " + pkg.getPackageName()
                         + " already installed.  Skipping duplicate.");
             }
 
-            if (pkg.applicationInfo.isStaticSharedLibrary()) {
+            if (pkg.isStaticSharedLibrary()) {
                 // Static libs have a synthetic package name containing the version
                 // but we still want the base name to be unique.
                 if ((scanFlags & SCAN_NEW_INSTALL) == 0
-                        && mPackages.containsKey(pkg.manifestPackageName)) {
+                        && mPackages.containsKey(pkg.getManifestPackageName())) {
                     throw new PackageManagerException(
                             "Duplicate static shared lib provider package");
                 }
 
                 // Static shared libraries should have at least O target SDK
-                if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
+                if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.O) {
                     throw new PackageManagerException(
                             "Packages declaring static-shared libs must target O SDK or higher");
                 }
@@ -11247,73 +11163,67 @@
 
                 // Package declaring static a shared lib cannot be renamed since the package
                 // name is synthetic and apps can't code around package manager internals.
-                if (!ArrayUtils.isEmpty(pkg.mOriginalPackages)) {
+                if (!ArrayUtils.isEmpty(pkg.getOriginalPackages())) {
                     throw new PackageManagerException(
                             "Packages declaring static-shared libs cannot be renamed");
                 }
 
-                // Package declaring static a shared lib cannot declare child packages
-                if (!ArrayUtils.isEmpty(pkg.childPackages)) {
-                    throw new PackageManagerException(
-                            "Packages declaring static-shared libs cannot have child packages");
-                }
-
                 // Package declaring static a shared lib cannot declare dynamic libs
-                if (!ArrayUtils.isEmpty(pkg.libraryNames)) {
+                if (!ArrayUtils.isEmpty(pkg.getLibraryNames())) {
                     throw new PackageManagerException(
                             "Packages declaring static-shared libs cannot declare dynamic libs");
                 }
 
                 // Package declaring static a shared lib cannot declare shared users
-                if (pkg.mSharedUserId != null) {
+                if (pkg.getSharedUserId() != null) {
                     throw new PackageManagerException(
                             "Packages declaring static-shared libs cannot declare shared users");
                 }
 
                 // Static shared libs cannot declare activities
-                if (!pkg.activities.isEmpty()) {
+                if (pkg.getActivities() != null && !pkg.getActivities().isEmpty()) {
                     throw new PackageManagerException(
                             "Static shared libs cannot declare activities");
                 }
 
                 // Static shared libs cannot declare services
-                if (!pkg.services.isEmpty()) {
+                if (pkg.getServices() != null && !pkg.getServices().isEmpty()) {
                     throw new PackageManagerException(
                             "Static shared libs cannot declare services");
                 }
 
                 // Static shared libs cannot declare providers
-                if (!pkg.providers.isEmpty()) {
+                if (pkg.getProviders() != null && !pkg.getProviders().isEmpty()) {
                     throw new PackageManagerException(
                             "Static shared libs cannot declare content providers");
                 }
 
                 // Static shared libs cannot declare receivers
-                if (!pkg.receivers.isEmpty()) {
+                if (pkg.getReceivers() != null && !pkg.getReceivers().isEmpty()) {
                     throw new PackageManagerException(
                             "Static shared libs cannot declare broadcast receivers");
                 }
 
                 // Static shared libs cannot declare permission groups
-                if (!pkg.permissionGroups.isEmpty()) {
+                if (pkg.getPermissionGroups() != null && !pkg.getPermissionGroups().isEmpty()) {
                     throw new PackageManagerException(
                             "Static shared libs cannot declare permission groups");
                 }
 
                 // Static shared libs cannot declare permissions
-                if (!pkg.permissions.isEmpty()) {
+                if (pkg.getPermissions() != null && !pkg.getPermissions().isEmpty()) {
                     throw new PackageManagerException(
                             "Static shared libs cannot declare permissions");
                 }
 
                 // Static shared libs cannot declare protected broadcasts
-                if (pkg.protectedBroadcasts != null) {
+                if (pkg.getProtectedBroadcasts() != null) {
                     throw new PackageManagerException(
                             "Static shared libs cannot declare protected broadcasts");
                 }
 
                 // Static shared libs cannot be overlay targets
-                if (pkg.mOverlayTarget != null) {
+                if (pkg.getOverlayTarget() != null) {
                     throw new PackageManagerException(
                             "Static shared libs cannot be overlay targets");
                 }
@@ -11323,16 +11233,17 @@
                 long maxVersionCode = Long.MAX_VALUE;
 
                 LongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(
-                        pkg.staticSharedLibName);
+                        pkg.getStaticSharedLibName());
                 if (versionedLib != null) {
                     final int versionCount = versionedLib.size();
                     for (int i = 0; i < versionCount; i++) {
                         SharedLibraryInfo libInfo = versionedLib.valueAt(i);
                         final long libVersionCode = libInfo.getDeclaringPackage()
                                 .getLongVersionCode();
-                        if (libInfo.getLongVersion() <  pkg.staticSharedLibVersion) {
+                        if (libInfo.getLongVersion() < pkg.getStaticSharedLibVersion()) {
                             minVersionCode = Math.max(minVersionCode, libVersionCode + 1);
-                        } else if (libInfo.getLongVersion() >  pkg.staticSharedLibVersion) {
+                        } else if (libInfo.getLongVersion()
+                                > pkg.getStaticSharedLibVersion()) {
                             maxVersionCode = Math.min(maxVersionCode, libVersionCode - 1);
                         } else {
                             minVersionCode = maxVersionCode = libVersionCode;
@@ -11347,23 +11258,6 @@
                 }
             }
 
-            // Only privileged apps and updated privileged apps can add child packages.
-            if (pkg.childPackages != null && !pkg.childPackages.isEmpty()) {
-                if ((scanFlags & SCAN_AS_PRIVILEGED) == 0) {
-                    throw new PackageManagerException("Only privileged apps can add child "
-                            + "packages. Ignoring package " + pkg.packageName);
-                }
-                final int childCount = pkg.childPackages.size();
-                for (int i = 0; i < childCount; i++) {
-                    PackageParser.Package childPkg = pkg.childPackages.get(i);
-                    if (mSettings.hasOtherDisabledSystemPkgWithChildLPr(pkg.packageName,
-                            childPkg.packageName)) {
-                        throw new PackageManagerException("Can't override child of "
-                                + "another disabled app. Ignoring package " + pkg.packageName);
-                    }
-                }
-            }
-
             // If we're only installing presumed-existing packages, require that the
             // scanned APK is both already known and at the path previously established
             // for it.  Previously unknown packages we pick up normally, but if we have an
@@ -11373,29 +11267,30 @@
             // to the user-installed location. If we don't allow this change, any newer,
             // user-installed version of the application will be ignored.
             if ((scanFlags & SCAN_REQUIRE_KNOWN) != 0) {
-                if (mExpectingBetter.containsKey(pkg.packageName)) {
+                if (mExpectingBetter.containsKey(pkg.getPackageName())) {
                     logCriticalInfo(Log.WARN,
-                            "Relax SCAN_REQUIRE_KNOWN requirement for package " + pkg.packageName);
+                            "Relax SCAN_REQUIRE_KNOWN requirement for package "
+                                    + pkg.getPackageName());
                 } else {
-                    PackageSetting known = mSettings.getPackageLPr(pkg.packageName);
+                    PackageSetting known = mSettings.getPackageLPr(pkg.getPackageName());
                     if (known != null) {
                         if (DEBUG_PACKAGE_SCANNING) {
-                            Log.d(TAG, "Examining " + pkg.codePath
+                            Log.d(TAG, "Examining " + pkg.getCodePath()
                                     + " and requiring known paths " + known.codePathString
                                     + " & " + known.resourcePathString);
                         }
-                        if (!pkg.applicationInfo.getCodePath().equals(known.codePathString)
-                                || !pkg.applicationInfo.getResourcePath().equals(
+                        if (!pkg.getAppInfoCodePath().equals(known.codePathString)
+                                || !pkg.getAppInfoResourcePath().equals(
                                         known.resourcePathString)) {
                             throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
-                                    "Application package " + pkg.packageName
-                                    + " found at " + pkg.applicationInfo.getCodePath()
+                                    "Application package " + pkg.getPackageName()
+                                    + " found at " + pkg.getAppInfoCodePath()
                                     + " but expected at " + known.codePathString
                                     + "; ignoring.");
                         }
                     } else {
                         throw new PackageManagerException(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
-                                "Application package " + pkg.packageName
+                                "Application package " + pkg.getPackageName()
                                 + " not found; ignoring.");
                     }
                 }
@@ -11410,11 +11305,13 @@
             }
 
             // Verify that packages sharing a user with a privileged app are marked as privileged.
-            if (!pkg.isPrivileged() && (pkg.mSharedUserId != null)) {
+            if (!pkg.isPrivileged() && (pkg.getSharedUserId() != null)) {
                 SharedUserSetting sharedUserSetting = null;
                 try {
-                    sharedUserSetting = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, 0, false);
-                } catch (PackageManagerException ignore) {}
+                    sharedUserSetting = mSettings.getSharedUserLPw(pkg.getSharedUserId(),
+                            0, 0, false);
+                } catch (PackageManagerException ignore) {
+                }
                 if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) {
                     // Exempt SharedUsers signed with the platform key.
                     PackageSetting platformPkgSetting = mSettings.mPackages.get("android");
@@ -11422,18 +11319,18 @@
                             != PackageParser.SigningDetails.UNKNOWN)
                             && (compareSignatures(
                                     platformPkgSetting.signatures.mSigningDetails.signatures,
-                                    pkg.mSigningDetails.signatures)
+                            pkg.getSigningDetails().signatures)
                                             != PackageManager.SIGNATURE_MATCH)) {
                         throw new PackageManagerException("Apps that share a user with a " +
                                 "privileged app must themselves be marked as privileged. " +
-                                pkg.packageName + " shares privileged user " +
-                                pkg.mSharedUserId + ".");
+                                pkg.getPackageName() + " shares privileged user " +
+                                pkg.getSharedUserId() + ".");
                     }
                 }
             }
 
             // Apply policies specific for runtime resource overlays (RROs).
-            if (pkg.mOverlayTarget != null) {
+            if (pkg.getOverlayTarget() != null) {
                 // System overlays have some restrictions on their use of the 'static' state.
                 if ((scanFlags & SCAN_AS_SYSTEM) != 0) {
                     // We are scanning a system overlay. This can be the first scan of the
@@ -11441,54 +11338,62 @@
                     if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
                         // This must be an update to a system overlay.
                         final PackageSetting previousPkg = assertNotNull(
-                                mSettings.getPackageLPr(pkg.packageName),
+                                mSettings.getPackageLPr(pkg.getPackageName()),
                                 "previous package state not present");
 
                         // previousPkg.pkg may be null: the package will be not be scanned if the
                         // package manager knows there is a newer version on /data.
                         // TODO[b/79435695]: Find a better way to keep track of the "static"
                         // property for RROs instead of having to parse packages on /system
-                        PackageParser.Package ppkg = previousPkg.pkg;
+                        AndroidPackage ppkg = previousPkg.pkg;
                         if (ppkg == null) {
                             try {
                                 final PackageParser pp = new PackageParser();
-                                ppkg = pp.parsePackage(previousPkg.codePath,
-                                        parseFlags | PackageParser.PARSE_IS_SYSTEM_DIR);
+                                // TODO(b/135203078): Do we really need to parse here? Maybe use
+                                //  a shortened path?
+                                ppkg = pp.parseParsedPackage(previousPkg.codePath,
+                                        parseFlags | PackageParser.PARSE_IS_SYSTEM_DIR,
+                                        false)
+                                        .hideAsFinal();
                             } catch (PackageParserException e) {
                                 Slog.w(TAG, "failed to parse " + previousPkg.codePath, e);
                             }
                         }
 
                         // Static overlays cannot be updated.
-                        if (ppkg != null && ppkg.mOverlayIsStatic) {
-                            throw new PackageManagerException("Overlay " + pkg.packageName +
-                                    " is static and cannot be upgraded.");
+                        if (ppkg != null && ppkg.isOverlayIsStatic()) {
+                            throw new PackageManagerException("Overlay "
+                                    + pkg.getPackageName()
+                                    + " is static and cannot be upgraded.");
                         // Non-static overlays cannot be converted to static overlays.
-                        } else if (pkg.mOverlayIsStatic) {
-                            throw new PackageManagerException("Overlay " + pkg.packageName +
-                                    " cannot be upgraded into a static overlay.");
+                        } else if (pkg.isOverlayIsStatic()) {
+                            throw new PackageManagerException("Overlay "
+                                    + pkg.getPackageName()
+                                    + " cannot be upgraded into a static overlay.");
                         }
                     }
                 } else {
                     // The overlay is a non-system overlay. Non-system overlays cannot be static.
-                    if (pkg.mOverlayIsStatic) {
-                        throw new PackageManagerException("Overlay " + pkg.packageName +
-                                " is static but not pre-installed.");
+                    if (pkg.isOverlayIsStatic()) {
+                        throw new PackageManagerException("Overlay "
+                                + pkg.getPackageName()
+                                + " is static but not pre-installed.");
                     }
 
                     // A non-preloaded overlay packages must have targetSdkVersion >= Q, or be
                     // signed with the platform certificate. Check this in increasing order of
                     // computational cost.
-                    if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q) {
+                    if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.Q) {
                         final PackageSetting platformPkgSetting =
                                 mSettings.getPackageLPr("android");
                         if ((platformPkgSetting.signatures.mSigningDetails
                                     != PackageParser.SigningDetails.UNKNOWN)
                                 && (compareSignatures(
                                         platformPkgSetting.signatures.mSigningDetails.signatures,
-                                        pkg.mSigningDetails.signatures)
+                                pkg.getSigningDetails().signatures)
                                     != PackageManager.SIGNATURE_MATCH)) {
-                            throw new PackageManagerException("Overlay " + pkg.packageName
+                            throw new PackageManagerException("Overlay "
+                                    + pkg.getPackageName()
                                     + " must target Q or later, "
                                     + "or be signed with the platform certificate");
                         }
@@ -11498,18 +11403,19 @@
                     // only be used if it is signed with the same certificate as its target. If the
                     // target is already installed, check this here to augment the last line of
                     // defence which is OMS.
-                    if (pkg.mOverlayTargetName == null) {
+                    if (pkg.getOverlayTargetName() == null) {
                         final PackageSetting targetPkgSetting =
-                                mSettings.getPackageLPr(pkg.mOverlayTarget);
+                                mSettings.getPackageLPr(pkg.getOverlayTarget());
                         if (targetPkgSetting != null) {
                             if ((targetPkgSetting.signatures.mSigningDetails
                                         != PackageParser.SigningDetails.UNKNOWN)
                                     && (compareSignatures(
                                             targetPkgSetting.signatures.mSigningDetails.signatures,
-                                            pkg.mSigningDetails.signatures)
+                                    pkg.getSigningDetails().signatures)
                                         != PackageManager.SIGNATURE_MATCH)) {
-                                throw new PackageManagerException("Overlay " + pkg.packageName
-                                        + " and target " + pkg.mOverlayTarget + " signed with"
+                                throw new PackageManagerException("Overlay "
+                                        + pkg.getPackageName() + " and target "
+                                        + pkg.getOverlayTarget() + " signed with"
                                         + " different certificates, and the overlay lacks"
                                         + " <overlay android:targetName>");
                             }
@@ -11589,71 +11495,67 @@
      * Adds a scanned package to the system. When this method is finished, the package will
      * be available for query, resolution, etc...
      */
-    private void commitPackageSettings(PackageParser.Package pkg,
-            @Nullable PackageParser.Package oldPkg, PackageSetting pkgSetting,
+    private void commitPackageSettings(AndroidPackage pkg,
+            @Nullable AndroidPackage oldPkg, PackageSetting pkgSetting,
             final @ScanFlags int scanFlags, boolean chatty, ReconciledPackage reconciledPkg) {
-        final String pkgName = pkg.packageName;
+        final String pkgName = pkg.getPackageName();
         if (mCustomResolverComponentName != null &&
-                mCustomResolverComponentName.getPackageName().equals(pkg.packageName)) {
+                mCustomResolverComponentName.getPackageName().equals(pkg.getPackageName())) {
             setUpCustomResolverActivity(pkg);
         }
 
-        if (pkg.packageName.equals("android")) {
+        if (pkg.getPackageName().equals("android")) {
             synchronized (mLock) {
-                if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
-                    // Set up information for our fall-back user intent resolution activity.
-                    mPlatformPackage = pkg;
-                    pkg.mVersionCode = mSdkVersion;
-                    pkg.mVersionCodeMajor = 0;
-                    mAndroidApplication = pkg.applicationInfo;
-                    if (!mResolverReplaced) {
-                        mResolveActivity.applicationInfo = mAndroidApplication;
-                        mResolveActivity.name = ResolverActivity.class.getName();
-                        mResolveActivity.packageName = mAndroidApplication.packageName;
-                        mResolveActivity.processName = "system:ui";
-                        mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
-                        mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
-                        mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
-                        mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert;
-                        mResolveActivity.exported = true;
-                        mResolveActivity.enabled = true;
-                        mResolveActivity.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
-                        mResolveActivity.configChanges = ActivityInfo.CONFIG_SCREEN_SIZE
-                                | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE
-                                | ActivityInfo.CONFIG_SCREEN_LAYOUT
-                                | ActivityInfo.CONFIG_ORIENTATION
-                                | ActivityInfo.CONFIG_KEYBOARD
-                                | ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
-                        mResolveInfo.activityInfo = mResolveActivity;
-                        mResolveInfo.priority = 0;
-                        mResolveInfo.preferredOrder = 0;
-                        mResolveInfo.match = 0;
-                        mResolveComponentName = new ComponentName(
-                                mAndroidApplication.packageName, mResolveActivity.name);
-                    }
+                // Set up information for our fall-back user intent resolution activity.
+                mPlatformPackage = pkg;
+                mAndroidApplication = pkg.toAppInfoWithoutState();
+                if (!mResolverReplaced) {
+                    mResolveActivity.applicationInfo = mAndroidApplication;
+                    mResolveActivity.name = ResolverActivity.class.getName();
+                    mResolveActivity.packageName = mAndroidApplication.packageName;
+                    mResolveActivity.processName = "system:ui";
+                    mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+                    mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
+                    mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
+                    mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert;
+                    mResolveActivity.exported = true;
+                    mResolveActivity.enabled = true;
+                    mResolveActivity.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
+                    mResolveActivity.configChanges = ActivityInfo.CONFIG_SCREEN_SIZE
+                            | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE
+                            | ActivityInfo.CONFIG_SCREEN_LAYOUT
+                            | ActivityInfo.CONFIG_ORIENTATION
+                            | ActivityInfo.CONFIG_KEYBOARD
+                            | ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
+                    mResolveInfo.activityInfo = mResolveActivity;
+                    mResolveInfo.priority = 0;
+                    mResolveInfo.preferredOrder = 0;
+                    mResolveInfo.match = 0;
+                    mResolveComponentName = new ComponentName(
+                            mAndroidApplication.packageName, mResolveActivity.name);
                 }
             }
         }
 
-        ArrayList<PackageParser.Package> clientLibPkgs = null;
+        ArrayList<AndroidPackage> clientLibPkgs = null;
         // writer
         synchronized (mLock) {
             if (!ArrayUtils.isEmpty(reconciledPkg.allowedSharedLibraryInfos)) {
                 for (SharedLibraryInfo info : reconciledPkg.allowedSharedLibraryInfos) {
                     commitSharedLibraryInfoLocked(info);
                 }
-                final Map<String, PackageParser.Package> combinedPackages =
-                        reconciledPkg.getCombinedPackages();
+                final Map<String, AndroidPackage> combinedSigningDetails =
+                        reconciledPkg.getCombinedAvailablePackages();
                 try {
                     // Shared libraries for the package need to be updated.
-                    updateSharedLibrariesLocked(pkg, null, combinedPackages);
+                    updateSharedLibrariesLocked(pkg, null, combinedSigningDetails);
                 } catch (PackageManagerException e) {
                     Slog.e(TAG, "updateSharedLibrariesLPr failed: ", e);
                 }
                 // Update all applications that use this library. Skip when booting
                 // since this will be done after all packages are scaned.
                 if ((scanFlags & SCAN_BOOTING) == 0) {
-                    clientLibPkgs = updateAllSharedLibrariesLocked(pkg, combinedPackages);
+                    clientLibPkgs = updateAllSharedLibrariesLocked(pkg, combinedSigningDetails);
                 }
             }
         }
@@ -11677,9 +11579,9 @@
         // Also need to kill any apps that are dependent on the library.
         if (clientLibPkgs != null) {
             for (int i=0; i<clientLibPkgs.size(); i++) {
-                PackageParser.Package clientPkg = clientLibPkgs.get(i);
-                killApplication(clientPkg.applicationInfo.packageName,
-                        clientPkg.applicationInfo.uid, "update lib");
+                AndroidPackage clientPkg = clientLibPkgs.get(i);
+                killApplication(clientPkg.getAppInfoPackageName(),
+                        clientPkg.getUid(), "update lib");
             }
         }
 
@@ -11692,7 +11594,7 @@
             // Add the new setting to mSettings
             mSettings.insertPackageSettingLPw(pkgSetting, pkg);
             // Add the new setting to mPackages
-            mPackages.put(pkg.applicationInfo.packageName, pkg);
+            mPackages.put(pkg.getAppInfoPackageName(), pkg);
 
             // Add the package's KeySets to the global KeySetManagerService
             KeySetManagerService ksms = mSettings.mKeySetManagerService;
@@ -11703,7 +11605,7 @@
 
             // Don't allow ephemeral applications to define new permissions groups.
             if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
-                Slog.w(TAG, "Permission groups from package " + pkg.packageName
+                Slog.w(TAG, "Permission groups from package " + pkg.getPackageName()
                         + " ignored: instant apps cannot define new permission groups.");
             } else {
                 mPermissionManager.addAllPermissionGroups(pkg, chatty);
@@ -11711,31 +11613,18 @@
 
             // Don't allow ephemeral applications to define new permissions.
             if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
-                Slog.w(TAG, "Permissions from package " + pkg.packageName
+                Slog.w(TAG, "Permissions from package " + pkg.getPackageName()
                         + " ignored: instant apps cannot define new permissions.");
             } else {
                 mPermissionManager.addAllPermissions(pkg, chatty);
             }
 
-            int collectionSize = pkg.instrumentation.size();
+            int collectionSize = ArrayUtils.size(pkg.getInstrumentations());
             StringBuilder r = null;
             int i;
             for (i = 0; i < collectionSize; i++) {
-                PackageParser.Instrumentation a = pkg.instrumentation.get(i);
-                a.info.packageName = pkg.applicationInfo.packageName;
-                a.info.sourceDir = pkg.applicationInfo.sourceDir;
-                a.info.publicSourceDir = pkg.applicationInfo.publicSourceDir;
-                a.info.splitNames = pkg.splitNames;
-                a.info.splitSourceDirs = pkg.applicationInfo.splitSourceDirs;
-                a.info.splitPublicSourceDirs = pkg.applicationInfo.splitPublicSourceDirs;
-                a.info.splitDependencies = pkg.applicationInfo.splitDependencies;
-                a.info.dataDir = pkg.applicationInfo.dataDir;
-                a.info.deviceProtectedDataDir = pkg.applicationInfo.deviceProtectedDataDir;
-                a.info.credentialProtectedDataDir = pkg.applicationInfo.credentialProtectedDataDir;
-                a.info.primaryCpuAbi = pkg.applicationInfo.primaryCpuAbi;
-                a.info.secondaryCpuAbi = pkg.applicationInfo.secondaryCpuAbi;
-                a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir;
-                a.info.secondaryNativeLibraryDir = pkg.applicationInfo.secondaryNativeLibraryDir;
+                ParsedInstrumentation a = pkg.getInstrumentations().get(i);
+                a.setPackageName(pkg.getPackageName());
                 mInstrumentation.put(a.getComponentName(), a);
                 if (chatty) {
                     if (r == null) {
@@ -11743,19 +11632,16 @@
                     } else {
                         r.append(' ');
                     }
-                    r.append(a.info.name);
+                    r.append(a.getName());
                 }
             }
             if (r != null) {
                 if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Instrumentation: " + r);
             }
 
-            if (pkg.protectedBroadcasts != null) {
-                collectionSize = pkg.protectedBroadcasts.size();
+            if (pkg.getProtectedBroadcasts() != null) {
                 synchronized (mProtectedBroadcasts) {
-                    for (i = 0; i < collectionSize; i++) {
-                        mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i));
-                    }
+                    mProtectedBroadcasts.addAll(pkg.getProtectedBroadcasts());
                 }
             }
 
@@ -11779,14 +11665,14 @@
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
     }
 
-    private void setUpCustomResolverActivity(PackageParser.Package pkg) {
+    private void setUpCustomResolverActivity(AndroidPackage pkg) {
         synchronized (mLock) {
             mResolverReplaced = true;
             // Set up information for custom user intent resolution activity.
-            mResolveActivity.applicationInfo = pkg.applicationInfo;
+            mResolveActivity.applicationInfo = pkg.toAppInfoWithoutState();
             mResolveActivity.name = mCustomResolverComponentName.getClassName();
-            mResolveActivity.packageName = pkg.applicationInfo.packageName;
-            mResolveActivity.processName = pkg.applicationInfo.packageName;
+            mResolveActivity.packageName = pkg.getAppInfoPackageName();
+            mResolveActivity.processName = pkg.getAppInfoProcessName();
             mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
             mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS |
                     ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
@@ -11853,22 +11739,13 @@
         }
     }
 
-    private void removePackageLI(PackageParser.Package pkg, boolean chatty) {
+    private void removePackageLI(AndroidPackage pkg, boolean chatty) {
         // Remove the parent package setting
-        PackageSetting ps = (PackageSetting) pkg.mExtras;
+        PackageSetting ps = getPackageSetting(pkg.getPackageName());
         if (ps != null) {
             removePackageLI(ps.name, chatty);
         } else if (DEBUG_REMOVE && chatty) {
-            Log.d(TAG, "Not removing package " + pkg.packageName + "; mExtras == null");
-        }
-        // Remove the child package setting
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            PackageParser.Package childPkg = pkg.childPackages.get(i);
-            ps = (PackageSetting) childPkg.mExtras;
-            if (ps != null) {
-                removePackageLI(ps.name, chatty);
-            }
+            Log.d(TAG, "Not removing package " + pkg.getPackageName() + "; mExtras == null");
         }
     }
 
@@ -11880,24 +11757,24 @@
 
         // writer
         synchronized (mLock) {
-            final PackageParser.Package removedPackage = mPackages.remove(packageName);
+            final AndroidPackage removedPackage = mPackages.remove(packageName);
             if (removedPackage != null) {
                 cleanPackageDataStructuresLILPw(removedPackage, chatty);
             }
         }
     }
 
-    void cleanPackageDataStructuresLILPw(PackageParser.Package pkg, boolean chatty) {
+    void cleanPackageDataStructuresLILPw(AndroidPackage pkg, boolean chatty) {
         mComponentResolver.removeAllComponents(pkg, chatty);
-        mAppsFilter.removePackage((PackageSetting) pkg.mExtras,
+        mAppsFilter.removePackage(getPackageSetting(pkg.getPackageName()),
                 mInjector.getUserManagerInternal().getUserIds(), mSettings.mPackages);
         mPermissionManager.removeAllPermissions(pkg, chatty);
 
-        final int instrumentationSize = pkg.instrumentation.size();
+        final int instrumentationSize = ArrayUtils.size(pkg.getInstrumentations());
         StringBuilder r = null;
         int i;
         for (i = 0; i < instrumentationSize; i++) {
-            PackageParser.Instrumentation a = pkg.instrumentation.get(i);
+            ParsedInstrumentation a = pkg.getInstrumentations().get(i);
             mInstrumentation.remove(a.getComponentName());
             if (DEBUG_REMOVE && chatty) {
                 if (r == null) {
@@ -11905,7 +11782,7 @@
                 } else {
                     r.append(' ');
                 }
-                r.append(a.info.name);
+                r.append(a.getName());
             }
         }
         if (r != null) {
@@ -11913,12 +11790,12 @@
         }
 
         r = null;
-        if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
+        if ((pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0) {
             // Only system apps can hold shared libraries.
-            if (pkg.libraryNames != null) {
-                final int libraryNamesSize = pkg.libraryNames.size();
+            if (pkg.getLibraryNames() != null) {
+                final int libraryNamesSize = pkg.getLibraryNames().size();
                 for (i = 0; i < libraryNamesSize; i++) {
-                    String name = pkg.libraryNames.get(i);
+                    String name = pkg.getLibraryNames().get(i);
                     if (removeSharedLibraryLPw(name, 0)) {
                         if (DEBUG_REMOVE && chatty) {
                             if (r == null) {
@@ -11936,15 +11813,16 @@
         r = null;
 
         // Any package can hold static shared libraries.
-        if (pkg.staticSharedLibName != null) {
-            if (removeSharedLibraryLPw(pkg.staticSharedLibName, pkg.staticSharedLibVersion)) {
+        if (pkg.getStaticSharedLibName() != null) {
+            if (removeSharedLibraryLPw(pkg.getStaticSharedLibName(),
+                    pkg.getStaticSharedLibVersion())) {
                 if (DEBUG_REMOVE && chatty) {
                     if (r == null) {
                         r = new StringBuilder(256);
                     } else {
                         r.append(' ');
                     }
-                    r.append(pkg.staticSharedLibName);
+                    r.append(pkg.getStaticSharedLibName());
                 }
             }
         }
@@ -12285,11 +12163,11 @@
                 // Cannot hide static shared libs as they are considered
                 // a part of the using app (emulating static linking). Also
                 // static libs are installed always on internal storage.
-                PackageParser.Package pkg = mPackages.get(packageName);
-                if (pkg != null && pkg.staticSharedLibName != null) {
+                AndroidPackage pkg = mPackages.get(packageName);
+                if (pkg != null && pkg.getStaticSharedLibName() != null) {
                     Slog.w(TAG, "Cannot hide package: " + packageName
                             + " providing static shared library: "
-                            + pkg.staticSharedLibName);
+                            + pkg.getStaticSharedLibName());
                     return false;
                 }
                 // Only allow protected packages to hide themselves.
@@ -12335,17 +12213,17 @@
             if (pkgSetting == null || !pkgSetting.isSystem()) {
                 return;
             }
-            PackageParser.Package pkg = pkgSetting.pkg;
-            if (pkg != null && pkg.applicationInfo != null) {
-                pkg.applicationInfo.hiddenUntilInstalled = hidden;
+            AndroidPackage pkg = pkgSetting.pkg;
+            if (pkg != null) {
+                pkg.mutate().setHiddenUntilInstalled(hidden);
             }
             final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(packageName);
             if (disabledPs == null) {
                 return;
             }
             pkg = disabledPs.pkg;
-            if (pkg != null && pkg.applicationInfo != null) {
-                pkg.applicationInfo.hiddenUntilInstalled = hidden;
+            if (pkg != null) {
+                pkg.mutate().setHiddenUntilInstalled(hidden);
             }
         }
     }
@@ -12537,7 +12415,7 @@
             if (installed) {
                 if ((installFlags & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS)
                         != 0 && pkgSetting.pkg != null) {
-                    whiteListedPermissions = pkgSetting.pkg.requestedPermissions;
+                    whiteListedPermissions = pkgSetting.pkg.getRequestedPermissions();
                 }
                 mPermissionManager.setWhitelistedRestrictedPermissions(packageName,
                         whiteListedPermissions, FLAG_PERMISSION_WHITELIST_INSTALLER, userId);
@@ -12967,11 +12845,11 @@
                     // Cannot suspend static shared libs as they are considered
                     // a part of the using app (emulating static linking). Also
                     // static libs are installed always on internal storage.
-                    PackageParser.Package pkg = mPackages.get(packageName);
-                    if (pkg != null && pkg.applicationInfo.isStaticSharedLibrary()) {
+                    AndroidPackage pkg = mPackages.get(packageName);
+                    if (pkg != null && pkg.isStaticSharedLibrary()) {
                         Slog.w(TAG, "Cannot suspend package: " + packageName
                                 + " providing static shared library: "
-                                + pkg.staticSharedLibName);
+                                + pkg.getStaticSharedLibName());
                         continue;
                     }
                 }
@@ -13116,10 +12994,10 @@
 
     private int getUidForVerifier(VerifierInfo verifierInfo) {
         synchronized (mLock) {
-            final PackageParser.Package pkg = mPackages.get(verifierInfo.packageName);
+            final AndroidPackage pkg = mPackages.get(verifierInfo.packageName);
             if (pkg == null) {
                 return -1;
-            } else if (pkg.mSigningDetails.signatures.length != 1) {
+            } else if (pkg.getSigningDetails().signatures.length != 1) {
                 Slog.i(TAG, "Verifier package " + verifierInfo.packageName
                         + " has more than one signature; ignoring");
                 return -1;
@@ -13133,7 +13011,7 @@
 
             final byte[] expectedPublicKey;
             try {
-                final Signature verifierSig = pkg.mSigningDetails.signatures[0];
+                final Signature verifierSig = pkg.getSigningDetails().signatures[0];
                 final PublicKey publicKey = verifierSig.getPublicKey();
                 expectedPublicKey = publicKey.getEncoded();
             } catch (CertificateException e) {
@@ -13148,7 +13026,7 @@
                 return -1;
             }
 
-            return pkg.applicationInfo.uid;
+            return pkg.getUid();
         }
     }
 
@@ -13324,26 +13202,33 @@
         final int callingUid = Binder.getCallingUid();
         final int callingUserId = UserHandle.getUserId(callingUid);
         synchronized (mLock) {
-            PackageParser.Package pkg = mPackages.get(packageName);
-            if (pkg == null || pkg.activities == null) {
+            AndroidPackage pkg = mPackages.get(packageName);
+            if (pkg == null || ArrayUtils.isEmpty(pkg.getActivities())) {
                 return ParceledListSlice.emptyList();
             }
-            if (pkg.mExtras == null) {
+            final PackageSetting ps = getPackageSetting(pkg.getPackageName());
+            if (ps == null) {
                 return ParceledListSlice.emptyList();
             }
-            final PackageSetting ps = (PackageSetting) pkg.mExtras;
             if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
                 return ParceledListSlice.emptyList();
             }
-            final int count = pkg.activities.size();
+            final int count = ArrayUtils.size(pkg.getActivities());
             ArrayList<IntentFilter> result = new ArrayList<>();
             for (int n=0; n<count; n++) {
-                PackageParser.Activity activity = pkg.activities.get(n);
+                ParsedActivity activity = pkg.getActivities().get(n);
                 if (activity.intents != null && activity.intents.size() > 0) {
                     result.addAll(activity.intents);
                 }
             }
-            return new ParceledListSlice<>(result);
+            return new ParceledListSlice<IntentFilter>(result) {
+                @Override
+                protected void writeElement(IntentFilter parcelable, Parcel dest, int callFlags) {
+                    // IntentFilter has final Parcelable methods, so redirect to the subclass
+                    ((ParsedActivityIntentInfo) parcelable).writeIntentInfoToParcel(dest,
+                            callFlags);
+                }
+            };
         }
     }
 
@@ -13526,7 +13411,7 @@
         // package has not opted out of backup participation.
         final boolean update = res.removedInfo != null
                 && res.removedInfo.removedPackage != null;
-        final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;
+        final int flags = (res.pkg == null) ? 0 : res.pkg.getFlags();
         boolean doRestore = !update
                 && ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);
 
@@ -13564,7 +13449,7 @@
                 try {
                     if (bm.isBackupServiceActive(userId)) {
                         bm.restoreAtInstallForUser(
-                                userId, res.pkg.applicationInfo.packageName, token);
+                                userId, res.pkg.getAppInfoPackageName(), token);
                     } else {
                         doRestore = false;
                     }
@@ -13589,8 +13474,8 @@
             IRollbackManager rm = IRollbackManager.Stub.asInterface(
                     ServiceManager.getService(Context.ROLLBACK_SERVICE));
 
-            final String packageName = res.pkg.applicationInfo.packageName;
-            final String seInfo = res.pkg.applicationInfo.seInfo;
+            final String packageName = res.pkg.getAppInfoPackageName();
+            final String seInfo = res.pkg.getSeInfo();
             final int[] allUsers = mUserManager.getUserIds();
             final int[] installedUsers;
 
@@ -13659,7 +13544,7 @@
                 if (data.res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
                     continue;
                 }
-                if (packageName.equals(data.res.pkg.applicationInfo.packageName)) {
+                if (packageName.equals(data.res.pkg.getAppInfoPackageName())) {
                     // right package; but is it for the right user?
                     for (int uIndex = 0; uIndex < data.res.newUsers.length; uIndex++) {
                         if (userId == data.res.newUsers[uIndex]) {
@@ -14002,12 +13887,12 @@
             synchronized (mLock) {
                 // Currently installed package which the new package is attempting to replace or
                 // null if no such package is installed.
-                PackageParser.Package installedPkg = mPackages.get(packageName);
+                AndroidPackage installedPkg = mPackages.get(packageName);
                 // Package which currently owns the data which the new package will own if installed.
                 // If an app is unstalled while keeping data (e.g., adb uninstall -k), installedPkg
                 // will be null whereas dataOwnerPkg will contain information about the package
                 // which was uninstalled while keeping its data.
-                PackageParser.Package dataOwnerPkg = installedPkg;
+                AndroidPackage dataOwnerPkg = installedPkg;
                 if (dataOwnerPkg  == null) {
                     PackageSetting ps = mSettings.mPackages.get(packageName);
                     if (ps != null) {
@@ -14034,7 +13919,7 @@
 
                 if (dataOwnerPkg != null) {
                     if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags,
-                            dataOwnerPkg.applicationInfo.flags)) {
+                            dataOwnerPkg.getFlags())) {
                         try {
                             checkDowngrade(dataOwnerPkg, pkgLite);
                         } catch (PackageManagerException e) {
@@ -14047,7 +13932,7 @@
                 if (installedPkg != null) {
                     if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
                         // Check for updated system application.
-                        if ((installedPkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                        if ((installedPkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0) {
                             return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
                         } else {
                             // If current upgrade specifies particular preference
@@ -14520,7 +14405,7 @@
          * Rename package into final resting place. All paths on the given
          * scanned package should be updated to reflect the rename.
          */
-        abstract boolean doRename(int status, PackageParser.Package pkg);
+        abstract boolean doRename(int status, ParsedPackage parsedPackage);
         abstract int doPostInstall(int status, int uid);
 
         /** @see PackageSettingBase#codePathString */
@@ -14664,7 +14549,8 @@
             return status;
         }
 
-        boolean doRename(int status, PackageParser.Package pkg) {
+        @Override
+        boolean doRename(int status, ParsedPackage parsedPackage) {
             if (status != PackageManager.INSTALL_SUCCEEDED) {
                 cleanUp();
                 return false;
@@ -14672,12 +14558,19 @@
 
             final File targetDir = codeFile.getParentFile();
             final File beforeCodeFile = codeFile;
-            final File afterCodeFile = getNextCodePath(targetDir, pkg.packageName);
+            final File afterCodeFile = getNextCodePath(targetDir, parsedPackage.getPackageName());
 
             if (DEBUG_INSTALL) Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);
+            final boolean onIncremental = mIncrementalManager != null
+                    && isIncrementalPath(beforeCodeFile.getAbsolutePath());
             try {
-                Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());
-            } catch (ErrnoException e) {
+                if (onIncremental) {
+                    mIncrementalManager.rename(beforeCodeFile.getAbsolutePath(),
+                            afterCodeFile.getAbsolutePath());
+                } else {
+                    Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());
+                }
+            } catch (IOException | ErrnoException e) {
                 Slog.w(TAG, "Failed to rename", e);
                 return false;
             }
@@ -14693,24 +14586,23 @@
 
             // Reflect the rename in scanned details
             try {
-                pkg.setCodePath(afterCodeFile.getCanonicalPath());
+                parsedPackage.setCodePath(afterCodeFile.getCanonicalPath());
             } catch (IOException e) {
                 Slog.e(TAG, "Failed to get path: " + afterCodeFile, e);
                 return false;
             }
-            pkg.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile,
-                    afterCodeFile, pkg.baseCodePath));
-            pkg.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
-                    afterCodeFile, pkg.splitCodePaths));
+            parsedPackage.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile,
+                    afterCodeFile, parsedPackage.getBaseCodePath()));
+            parsedPackage.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
+                    afterCodeFile, parsedPackage.getSplitCodePaths()));
 
             // Reflect the rename in app info
-            pkg.setApplicationVolumeUuid(pkg.volumeUuid);
-            pkg.setApplicationInfoCodePath(pkg.codePath);
-            pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath);
-            pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths);
-            pkg.setApplicationInfoResourcePath(pkg.codePath);
-            pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath);
-            pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);
+            // TODO(b/135203078): Remove all of these application info calls
+            parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid())
+                    .setApplicationInfoCodePath(parsedPackage.getCodePath())
+                    .setApplicationInfoResourcePath(parsedPackage.getCodePath())
+                    .setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath())
+                    .setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths());
 
             return true;
         }
@@ -14737,6 +14629,11 @@
                 return false;
             }
 
+            String codePath = codeFile.getAbsolutePath();
+            if (mIncrementalManager != null && isIncrementalPath(codePath)) {
+                mIncrementalManager.closeStorage(codePath);
+            }
+
             removeCodePathLI(codeFile);
 
             if (resourceFile != null && !FileUtils.contains(codeFile, resourceFile)) {
@@ -14808,20 +14705,20 @@
             return status;
         }
 
-        boolean doRename(int status, PackageParser.Package pkg) {
+        @Override
+        boolean doRename(int status, ParsedPackage parsedPackage) {
             if (status != PackageManager.INSTALL_SUCCEEDED) {
                 cleanUp(move.toUuid);
                 return false;
             }
 
             // Reflect the move in app info
-            pkg.setApplicationVolumeUuid(pkg.volumeUuid);
-            pkg.setApplicationInfoCodePath(pkg.codePath);
-            pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath);
-            pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths);
-            pkg.setApplicationInfoResourcePath(pkg.codePath);
-            pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath);
-            pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths);
+            // TODO(b/135203078): Remove all of these application info calls
+            parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid())
+                    .setApplicationInfoCodePath(parsedPackage.getCodePath())
+                    .setApplicationInfoResourcePath(parsedPackage.getCodePath())
+                    .setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath())
+                    .setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths());
 
             return true;
         }
@@ -14897,14 +14794,14 @@
         int[] origUsers;
         // The set of users that now have this package installed.
         int[] newUsers;
-        PackageParser.Package pkg;
+        AndroidPackage pkg;
         int returnCode;
         String returnMsg;
         String installerPackageName;
         PackageRemovedInfo removedInfo;
         ArrayMap<String, PackageInstalledInfo> addedChildPackages;
         // The set of packages consuming this shared library or null if no consumers exist.
-        ArrayList<PackageParser.Package> libraryConsumers;
+        ArrayList<AndroidPackage> libraryConsumers;
 
         public void setError(int code, String msg) {
             setReturnCode(code);
@@ -14960,107 +14857,37 @@
         }
     }
 
-    /**
-     * Checks whether the parent or any of the child packages have a change shared
-     * user. For a package to be a valid update the shred users of the parent and
-     * the children should match. We may later support changing child shared users.
-     * @param oldPkg The updated package.
-     * @param newPkg The update package.
-     * @return The shared user that change between the versions.
-     */
-    private String getParentOrChildPackageChangedSharedUser(PackageParser.Package oldPkg,
-            PackageParser.Package newPkg) {
-        // Check parent shared user
-        if (!Objects.equals(oldPkg.mSharedUserId, newPkg.mSharedUserId)) {
-            return newPkg.packageName;
-        }
-        // Check child shared users
-        final int oldChildCount = (oldPkg.childPackages != null) ? oldPkg.childPackages.size() : 0;
-        final int newChildCount = (newPkg.childPackages != null) ? newPkg.childPackages.size() : 0;
-        for (int i = 0; i < newChildCount; i++) {
-            PackageParser.Package newChildPkg = newPkg.childPackages.get(i);
-            // If this child was present, did it have the same shared user?
-            for (int j = 0; j < oldChildCount; j++) {
-                PackageParser.Package oldChildPkg = oldPkg.childPackages.get(j);
-                if (newChildPkg.packageName.equals(oldChildPkg.packageName)
-                        && !Objects.equals(newChildPkg.mSharedUserId, oldChildPkg.mSharedUserId)) {
-                    return newChildPkg.packageName;
-                }
-            }
-        }
-        return null;
-    }
-
     private void removeNativeBinariesLI(PackageSetting ps) {
-        // Remove the lib path for the parent package
         if (ps != null) {
             NativeLibraryHelper.removeNativeBinariesLI(ps.legacyNativeLibraryPathString);
-            // Remove the lib path for the child packages
-            final int childCount = (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0;
-            for (int i = 0; i < childCount; i++) {
-                PackageSetting childPs = null;
-                synchronized (mLock) {
-                    childPs = mSettings.getPackageLPr(ps.childPackageNames.get(i));
-                }
-                if (childPs != null) {
-                    NativeLibraryHelper.removeNativeBinariesLI(childPs
-                            .legacyNativeLibraryPathString);
-                }
-            }
         }
     }
 
     @GuardedBy("mLock")
-    private void enableSystemPackageLPw(PackageParser.Package pkg) {
-        // Enable the parent package
-        mSettings.enableSystemPackageLPw(pkg.packageName);
-        // Enable the child packages
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            PackageParser.Package childPkg = pkg.childPackages.get(i);
-            mSettings.enableSystemPackageLPw(childPkg.packageName);
-        }
+    private void enableSystemPackageLPw(AndroidPackage pkg) {
+        mSettings.enableSystemPackageLPw(pkg.getPackageName());
     }
 
     @GuardedBy("mLock")
-    private boolean disableSystemPackageLPw(PackageParser.Package oldPkg,
-            PackageParser.Package newPkg) {
-        // Disable the parent package (parent always replaced)
-        boolean disabled = mSettings.disableSystemPackageLPw(oldPkg.packageName, true);
-        // Disable the child packages
-        final int childCount = (oldPkg.childPackages != null) ? oldPkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            PackageParser.Package childPkg = oldPkg.childPackages.get(i);
-            final boolean replace = newPkg.hasChildPackage(childPkg.packageName);
-            disabled |= mSettings.disableSystemPackageLPw(childPkg.packageName, replace);
-        }
-        return disabled;
+    private boolean disableSystemPackageLPw(AndroidPackage oldPkg) {
+        return mSettings.disableSystemPackageLPw(oldPkg.getPackageName(), true);
     }
 
-    private void updateSettingsLI(PackageParser.Package newPackage,
-            InstallArgs installArgs, int[] allUsers, PackageInstalledInfo res) {
-        // Update the parent package setting
+    private void updateSettingsLI(AndroidPackage newPackage, InstallArgs installArgs,
+            int[] allUsers, PackageInstalledInfo res) {
         updateSettingsInternalLI(newPackage, installArgs, allUsers, res);
-        // Update the child packages setting
-        final int childCount = (newPackage.childPackages != null)
-                ? newPackage.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            PackageParser.Package childPackage = newPackage.childPackages.get(i);
-            PackageInstalledInfo childRes = res.addedChildPackages.get(childPackage.packageName);
-            updateSettingsInternalLI(childPackage, installArgs, allUsers, childRes);
-        }
     }
 
-    private void updateSettingsInternalLI(PackageParser.Package pkg,
-            InstallArgs installArgs, int[] allUsers, PackageInstalledInfo res) {
+    private void updateSettingsInternalLI(AndroidPackage pkg, InstallArgs installArgs,
+            int[] allUsers, PackageInstalledInfo res) {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
 
-        final String pkgName = pkg.packageName;
+        final String pkgName = pkg.getPackageName();
         final String installerPackageName = installArgs.installSource.installerPackageName;
         final int[] installedForUsers = res.origUsers;
         final int installReason = installArgs.installReason;
 
-        if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.codePath);
+        if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.getCodePath());
         synchronized (mLock) {
 // NOTE: This changes slightly to include UPDATE_PERMISSIONS_ALL regardless of the size of pkg.permissions
             mPermissionManager.updatePermissions(pkgName, pkg);
@@ -15133,7 +14960,7 @@
                 mSettings.writeKernelMappingLPr(ps);
             }
             res.name = pkgName;
-            res.uid = pkg.applicationInfo.uid;
+            res.uid = pkg.getUid();
             res.pkg = pkg;
             mSettings.setInstallerPackageName(pkgName, installerPackageName);
             res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
@@ -15191,7 +15018,7 @@
     private static class ReconcileRequest {
         public final Map<String, ScanResult> scannedPackages;
 
-        public final Map<String, PackageParser.Package> allPackages;
+        public final Map<String, AndroidPackage> allPackages;
         public final Map<String, LongSparseArray<SharedLibraryInfo>> sharedLibrarySource;
         public final Map<String, InstallArgs> installArgs;
         public final Map<String, PackageInstalledInfo> installResults;
@@ -15204,7 +15031,7 @@
                 Map<String, PackageInstalledInfo> installResults,
                 Map<String, PrepareResult> preparedPackages,
                 Map<String, LongSparseArray<SharedLibraryInfo>> sharedLibrarySource,
-                Map<String, PackageParser.Package> allPackages,
+                Map<String, AndroidPackage> allPackages,
                 Map<String, VersionInfo> versionInfos,
                 Map<String, PackageSetting> lastStaticSharedLibSettings) {
             this.scannedPackages = scannedPackages;
@@ -15219,7 +15046,7 @@
 
         private ReconcileRequest(Map<String, ScanResult> scannedPackages,
                 Map<String, LongSparseArray<SharedLibraryInfo>> sharedLibrarySource,
-                Map<String, PackageParser.Package> allPackages,
+                Map<String, AndroidPackage> allPackages,
                 Map<String, VersionInfo> versionInfos,
                 Map<String, PackageSetting> lastStaticSharedLibSettings) {
             this(scannedPackages, Collections.emptyMap(), Collections.emptyMap(),
@@ -15287,15 +15114,17 @@
          * with the package(s) currently being installed. The to-be installed packages take
          * precedence and may shadow already installed packages.
          */
-        private Map<String, PackageParser.Package> getCombinedPackages() {
-            final ArrayMap<String, PackageParser.Package> combinedPackages =
+        private Map<String, AndroidPackage> getCombinedAvailablePackages() {
+            final ArrayMap<String, AndroidPackage> combined =
                     new ArrayMap<>(request.allPackages.size() + request.scannedPackages.size());
 
-            combinedPackages.putAll(request.allPackages);
+            combined.putAll(request.allPackages);
+
             for (ScanResult scanResult : request.scannedPackages.values()) {
-                combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.pkg);
+                combined.put(scanResult.pkgSetting.name, scanResult.request.parsedPackage);
             }
-            return combinedPackages;
+
+            return combined;
         }
     }
 
@@ -15308,8 +15137,9 @@
         final Map<String, ReconciledPackage> result = new ArrayMap<>(scannedPackages.size());
 
         // make a copy of the existing set of packages so we can combine them with incoming packages
-        final ArrayMap<String, PackageParser.Package> combinedPackages =
+        final ArrayMap<String, AndroidPackage> combinedPackages =
                 new ArrayMap<>(request.allPackages.size() + scannedPackages.size());
+
         combinedPackages.putAll(request.allPackages);
 
         final Map<String, LongSparseArray<SharedLibraryInfo>> incomingSharedLibraries =
@@ -15319,7 +15149,7 @@
             final ScanResult scanResult = scannedPackages.get(installPackageName);
 
             // add / replace existing with incoming packages
-            combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.pkg);
+            combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.parsedPackage);
 
             // in the first pass, we'll build up the set of incoming shared libraries
             final List<SharedLibraryInfo> allowedSharedLibInfos =
@@ -15352,7 +15182,7 @@
                         | (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP);
                 deletePackageAction = mayDeletePackageLocked(res.removedInfo,
                         prepareResult.originalPs, prepareResult.disabledPs,
-                        prepareResult.childPackageSettings, deleteFlags, null /* all users */);
+                        deleteFlags, null /* all users */);
                 if (deletePackageAction == null) {
                     throw new ReconcileFailure(
                             PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE,
@@ -15364,7 +15194,7 @@
 
             final int scanFlags = scanResult.request.scanFlags;
             final int parseFlags = scanResult.request.parseFlags;
-            final PackageParser.Package pkg = scanResult.request.pkg;
+            final ParsedPackage parsedPackage = scanResult.request.parsedPackage;
 
             final PackageSetting disabledPkgSetting = scanResult.request.disabledPkgSetting;
             final PackageSetting lastStaticSharedLibSetting =
@@ -15377,35 +15207,37 @@
             boolean sharedUserSignaturesChanged = false;
             SigningDetails signingDetails = null;
             if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
-                if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
+                if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) {
                     // We just determined the app is signed correctly, so bring
                     // over the latest parsed certs.
                 } else {
                     if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
                         throw new ReconcileFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
-                                "Package " + pkg.packageName + " upgrade keys do not match the "
-                                        + "previously installed version");
+                                "Package " + parsedPackage.getPackageName()
+                                        + " upgrade keys do not match the previously installed"
+                                        + " version");
                     } else {
-                        String msg = "System package " + pkg.packageName
+                        String msg = "System package " + parsedPackage.getPackageName()
                                 + " signature changed; retaining data.";
                         reportSettingsProblem(Log.WARN, msg);
                     }
                 }
-                signingDetails = pkg.mSigningDetails;
+                signingDetails = parsedPackage.getSigningDetails();
             } else {
                 try {
                     final VersionInfo versionInfo = request.versionInfos.get(installPackageName);
                     final boolean compareCompat = isCompatSignatureUpdateNeeded(versionInfo);
                     final boolean compareRecover = isRecoverSignatureUpdateNeeded(versionInfo);
                     final boolean compatMatch = verifySignatures(signatureCheckPs,
-                            disabledPkgSetting, pkg.mSigningDetails, compareCompat, compareRecover);
+                            disabledPkgSetting, parsedPackage.getSigningDetails(), compareCompat,
+                            compareRecover);
                     // The new KeySets will be re-added later in the scanning process.
                     if (compatMatch) {
                         removeAppKeySetData = true;
                     }
                     // We just determined the app is signed correctly, so bring
                     // over the latest parsed certs.
-                    signingDetails = pkg.mSigningDetails;
+                    signingDetails = parsedPackage.getSigningDetails();
 
 
                     // if this is is a sharedUser, check to see if the new package is signed by a
@@ -15413,10 +15245,10 @@
                     // signing certificate than the existing one, and if so, copy over the new
                     // details
                     if (signatureCheckPs.sharedUser != null) {
-                        if (pkg.mSigningDetails.hasAncestor(
+                        if (parsedPackage.getSigningDetails().hasAncestor(
                                 signatureCheckPs.sharedUser.signatures.mSigningDetails)) {
                             signatureCheckPs.sharedUser.signatures.mSigningDetails =
-                                    pkg.mSigningDetails;
+                                    parsedPackage.getSigningDetails();
                         }
                         if (signatureCheckPs.sharedUser.signaturesChanged == null) {
                             signatureCheckPs.sharedUser.signaturesChanged = Boolean.FALSE;
@@ -15426,7 +15258,7 @@
                     if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
                         throw new ReconcileFailure(e);
                     }
-                    signingDetails = pkg.mSigningDetails;
+                    signingDetails = parsedPackage.getSigningDetails();
 
                     // If the system app is part of a shared user we allow that shared user to
                     // change
@@ -15441,7 +15273,7 @@
                                 signatureCheckPs.sharedUser.signatures.mSigningDetails.signatures;
                         if (signatureCheckPs.sharedUser.signaturesChanged != null
                                 && compareSignatures(sharedUserSignatures,
-                                        pkg.mSigningDetails.signatures)
+                                parsedPackage.getSigningDetails().signatures)
                                         != PackageManager.SIGNATURE_MATCH) {
                             if (SystemProperties.getInt("ro.product.first_api_level", 0) <= 29) {
                                 // Mismatched signatures is an error and silently skipping system
@@ -15461,18 +15293,19 @@
                                 // whichever package happened to be scanned later.
                                 throw new IllegalStateException(
                                         "Signature mismatch on system package "
-                                                + pkg.packageName + " for shared user "
+                                                + parsedPackage.getPackageName()
+                                                + " for shared user "
                                                 + scanResult.pkgSetting.sharedUser);
                             }
                         }
 
                         sharedUserSignaturesChanged = true;
                         signatureCheckPs.sharedUser.signatures.mSigningDetails =
-                                pkg.mSigningDetails;
+                                parsedPackage.getSigningDetails();
                         signatureCheckPs.sharedUser.signaturesChanged = Boolean.TRUE;
                     }
                     // File a report about this.
-                    String msg = "System package " + pkg.packageName
+                    String msg = "System package " + parsedPackage.getPackageName()
                             + " signature changed; retaining data.";
                     reportSettingsProblem(Log.WARN, msg);
                 } catch (IllegalArgumentException e) {
@@ -15506,8 +15339,9 @@
             }
             try {
                 result.get(installPackageName).collectedSharedLibraryInfos =
-                        collectSharedLibraryInfos(scanResult.request.pkg, combinedPackages,
-                                request.sharedLibrarySource, incomingSharedLibraries);
+                        collectSharedLibraryInfos(scanResult.request.parsedPackage,
+                                combinedPackages, request.sharedLibrarySource,
+                                incomingSharedLibraries);
 
             } catch (PackageManagerException e) {
                 throw new ReconcileFailure(e.error, e.getMessage());
@@ -15525,7 +15359,7 @@
             ScanResult scanResult,
             Map<String, LongSparseArray<SharedLibraryInfo>> existingSharedLibraries) {
         // Let's used the parsed package as scanResult.pkgSetting may be null
-        final PackageParser.Package pkg = scanResult.request.pkg;
+        final ParsedPackage parsedPackage = scanResult.request.parsedPackage;
         if (scanResult.staticSharedLibraryInfo == null
                 && scanResult.dynamicSharedLibraryInfos == null) {
             return null;
@@ -15536,12 +15370,12 @@
             return Collections.singletonList(scanResult.staticSharedLibraryInfo);
         }
         final boolean hasDynamicLibraries =
-                (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
+                (parsedPackage.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0
                         && scanResult.dynamicSharedLibraryInfos != null;
         if (!hasDynamicLibraries) {
             return null;
         }
-        final boolean isUpdatedSystemApp = pkg.isUpdatedSystemApp();
+        final boolean isUpdatedSystemApp = parsedPackage.isUpdatedSystemApp();
         // We may not yet have disabled the updated package yet, so be sure to grab the
         // current setting if that's the case.
         final PackageSetting updatedSystemPs = isUpdatedSystemApp
@@ -15550,9 +15384,9 @@
                         : scanResult.request.disabledPkgSetting
                 : null;
         if (isUpdatedSystemApp && (updatedSystemPs.pkg == null
-                || updatedSystemPs.pkg.libraryNames == null)) {
-            Slog.w(TAG, "Package " + pkg.packageName + " declares libraries that are not "
-                    + "declared on the system image; skipping");
+                || updatedSystemPs.pkg.getLibraryNames() == null)) {
+            Slog.w(TAG, "Package " + parsedPackage.getPackageName()
+                    + " declares libraries that are not declared on the system image; skipping");
             return null;
         }
         final ArrayList<SharedLibraryInfo> infos =
@@ -15570,16 +15404,17 @@
                 // with it.  Better to just have the restriction here, be
                 // conservative, and create many fewer cases that can negatively
                 // impact the user experience.
-                if (!updatedSystemPs.pkg.libraryNames.contains(name)) {
-                    Slog.w(TAG, "Package " + pkg.packageName + " declares library " + name
+                if (!updatedSystemPs.pkg.getLibraryNames().contains(name)) {
+                    Slog.w(TAG, "Package " + parsedPackage.getPackageName()
+                            + " declares library " + name
                             + " that is not declared on system image; skipping");
                     continue;
                 }
             }
             if (sharedLibExists(
                     name, SharedLibraryInfo.VERSION_UNDEFINED, existingSharedLibraries)) {
-                Slog.w(TAG, "Package " + pkg.packageName + " declares library " + name
-                        + " that already exists; skipping");
+                Slog.w(TAG, "Package " + parsedPackage.getPackageName() + " declares library "
+                        + name + " that already exists; skipping");
                 continue;
             }
             infos.add(info);
@@ -15617,68 +15452,38 @@
         for (ReconciledPackage reconciledPkg : request.reconciledPackages.values()) {
             final ScanResult scanResult = reconciledPkg.scanResult;
             final ScanRequest scanRequest = scanResult.request;
-            final PackageParser.Package pkg = scanRequest.pkg;
-            final String packageName = pkg.packageName;
+            final ParsedPackage parsedPackage = scanRequest.parsedPackage;
+            final String packageName = parsedPackage.getPackageName();
             final PackageInstalledInfo res = reconciledPkg.installResult;
 
             if (reconciledPkg.prepareResult.replace) {
-                PackageParser.Package oldPackage = mPackages.get(packageName);
+                AndroidPackage oldPackage = mPackages.get(packageName);
 
                 // Set the update and install times
-                PackageSetting deletedPkgSetting = (PackageSetting) oldPackage.mExtras;
-                setInstallAndUpdateTime(pkg, deletedPkgSetting.firstInstallTime,
-                        System.currentTimeMillis());
+                PackageSetting deletedPkgSetting = getPackageSetting(oldPackage.getPackageName());
+                reconciledPkg.pkgSetting.firstInstallTime = deletedPkgSetting.firstInstallTime;
+                reconciledPkg.pkgSetting.lastUpdateTime = System.currentTimeMillis();
 
                 if (reconciledPkg.prepareResult.system) {
                     // Remove existing system package
                     removePackageLI(oldPackage, true);
-                    if (!disableSystemPackageLPw(oldPackage, pkg)) {
+                    if (!disableSystemPackageLPw(oldPackage)) {
                         // We didn't need to disable the .apk as a current system package,
                         // which means we are replacing another update that is already
                         // installed.  We need to make sure to delete the older one's .apk.
                         res.removedInfo.args = createInstallArgsForExisting(
-                                oldPackage.applicationInfo.getCodePath(),
-                                oldPackage.applicationInfo.getResourcePath(),
-                                getAppDexInstructionSets(oldPackage.applicationInfo));
+                                oldPackage.getAppInfoCodePath(),
+                                oldPackage.getAppInfoResourcePath(),
+                                getAppDexInstructionSets(oldPackage.getPrimaryCpuAbi(),
+                                        oldPackage.getSecondaryCpuAbi()));
                     } else {
                         res.removedInfo.args = null;
                     }
-
-                    // Update the package dynamic state if succeeded
-                    // Now that the install succeeded make sure we remove data
-                    // directories for any child package the update removed.
-                    final int deletedChildCount = (oldPackage.childPackages != null)
-                            ? oldPackage.childPackages.size() : 0;
-                    final int newChildCount = (pkg.childPackages != null)
-                            ? pkg.childPackages.size() : 0;
-                    for (int i = 0; i < deletedChildCount; i++) {
-                        PackageParser.Package deletedChildPkg = oldPackage.childPackages.get(i);
-                        boolean childPackageDeleted = true;
-                        for (int j = 0; j < newChildCount; j++) {
-                            PackageParser.Package newChildPkg = pkg.childPackages.get(j);
-                            if (deletedChildPkg.packageName.equals(newChildPkg.packageName)) {
-                                childPackageDeleted = false;
-                                break;
-                            }
-                        }
-                        if (childPackageDeleted) {
-                            PackageSetting ps1 = mSettings.getDisabledSystemPkgLPr(
-                                    deletedChildPkg.packageName);
-                            if (ps1 != null && res.removedInfo.removedChildPackages != null) {
-                                PackageRemovedInfo removedChildRes = res.removedInfo
-                                        .removedChildPackages.get(deletedChildPkg.packageName);
-                                removePackageDataLIF(ps1, request.mAllUsers, removedChildRes, 0,
-                                        false);
-                                removedChildRes.removedForAllUsers = mPackages.get(ps1.name)
-                                        == null;
-                            }
-                        }
-                    }
                 } else {
                     try {
                         // Settings will be written during the call to updateSettingsLI().
                         executeDeletePackageLIF(reconciledPkg.deletePackageAction, packageName,
-                                true, request.mAllUsers, false, pkg);
+                                true, request.mAllUsers, false, parsedPackage);
                     } catch (SystemDeleteException e) {
                         if (Build.IS_ENG) {
                             throw new RuntimeException("Unexpected failure", e);
@@ -15694,62 +15499,40 @@
                             Slog.i(TAG, "upgrading pkg " + oldPackage
                                     + " is ASEC-hosted -> UNAVAILABLE");
                         }
-                        final int[] uidArray = new int[]{oldPackage.applicationInfo.uid};
+                        final int[] uidArray = new int[]{oldPackage.getUid()};
                         final ArrayList<String> pkgList = new ArrayList<>(1);
-                        pkgList.add(oldPackage.applicationInfo.packageName);
+                        pkgList.add(oldPackage.getAppInfoPackageName());
                         sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
                     }
 
                     // Update the in-memory copy of the previous code paths.
                     PackageSetting ps1 = mSettings.mPackages.get(
-                            reconciledPkg.prepareResult.existingPackage.packageName);
+                            reconciledPkg.prepareResult.existingPackage.getPackageName());
                     if ((reconciledPkg.installArgs.installFlags & PackageManager.DONT_KILL_APP)
                             == 0) {
                         if (ps1.mOldCodePaths == null) {
                             ps1.mOldCodePaths = new ArraySet<>();
                         }
-                        Collections.addAll(ps1.mOldCodePaths, oldPackage.baseCodePath);
-                        if (oldPackage.splitCodePaths != null) {
-                            Collections.addAll(ps1.mOldCodePaths, oldPackage.splitCodePaths);
+                        Collections.addAll(ps1.mOldCodePaths, oldPackage.getBaseCodePath());
+                        if (oldPackage.getSplitCodePaths() != null) {
+                            Collections.addAll(ps1.mOldCodePaths, oldPackage.getSplitCodePaths());
                         }
                     } else {
                         ps1.mOldCodePaths = null;
                     }
-                    if (ps1.childPackageNames != null) {
-                        for (int i = ps1.childPackageNames.size() - 1; i >= 0; --i) {
-                            final String childPkgName = ps1.childPackageNames.get(i);
-                            final PackageSetting childPs = mSettings.mPackages.get(childPkgName);
-                            childPs.mOldCodePaths = ps1.mOldCodePaths;
-                        }
-                    }
 
                     if (reconciledPkg.installResult.returnCode
                             == PackageManager.INSTALL_SUCCEEDED) {
-                        PackageSetting ps2 = mSettings.getPackageLPr(pkg.packageName);
+                        PackageSetting ps2 = mSettings.getPackageLPr(
+                                parsedPackage.getPackageName());
                         if (ps2 != null) {
                             res.removedInfo.removedForAllUsers = mPackages.get(ps2.name) == null;
-                            if (res.removedInfo.removedChildPackages != null) {
-                                final int childCount1 = res.removedInfo.removedChildPackages.size();
-                                // Iterate in reverse as we may modify the collection
-                                for (int i = childCount1 - 1; i >= 0; i--) {
-                                    String childPackageName =
-                                            res.removedInfo.removedChildPackages.keyAt(i);
-                                    if (res.addedChildPackages.containsKey(childPackageName)) {
-                                        res.removedInfo.removedChildPackages.removeAt(i);
-                                    } else {
-                                        PackageRemovedInfo childInfo = res.removedInfo
-                                                .removedChildPackages.valueAt(i);
-                                        childInfo.removedForAllUsers = mPackages.get(
-                                                childInfo.removedPackage) == null;
-                                    }
-                                }
-                            }
                         }
                     }
                 }
             }
 
-            commitReconciledScanResultLocked(reconciledPkg);
+            AndroidPackage pkg = commitReconciledScanResultLocked(reconciledPkg);
             updateSettingsLI(pkg, reconciledPkg.installArgs, request.mAllUsers, res);
 
             final PackageSetting ps = mSettings.mPackages.get(packageName);
@@ -15757,16 +15540,6 @@
                 res.newUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
                 ps.setUpdateAvailable(false /*updateAvailable*/);
             }
-            final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-            for (int i = 0; i < childCount; i++) {
-                PackageParser.Package childPkg = pkg.childPackages.get(i);
-                PackageInstalledInfo childRes = res.addedChildPackages.get(childPkg.packageName);
-                PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
-                if (childPs != null) {
-                    childRes.newUsers = childPs.queryInstalledUsers(
-                            mUserManager.getUserIds(), true);
-                }
-            }
             if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                 updateSequenceNumberLP(ps, res.newUsers);
                 updateInstantAppInstallerLocked(packageName);
@@ -15827,33 +15600,31 @@
                 request.installResult.installerPackageName =
                         request.args.installSource.installerPackageName;
 
-                final String packageName = prepareResult.packageToScan.packageName;
+                final String packageName = prepareResult.packageToScan.getPackageName();
                 prepareResults.put(packageName, prepareResult);
                 installResults.put(packageName, request.installResult);
                 installArgs.put(packageName, request.args);
                 try {
-                    final List<ScanResult> scanResults = scanPackageTracedLI(
+                    final ScanResult result = scanPackageTracedLI(
                             prepareResult.packageToScan, prepareResult.parseFlags,
                             prepareResult.scanFlags, System.currentTimeMillis(),
                             request.args.user);
-                    for (ScanResult result : scanResults) {
-                        if (null != preparedScans.put(result.pkgSetting.pkg.packageName, result)) {
-                            request.installResult.setError(
-                                    PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
-                                    "Duplicate package " + result.pkgSetting.pkg.packageName
-                                            + " in multi-package install request.");
-                            return;
-                        }
-                        createdAppId.put(packageName, optimisticallyRegisterAppId(result));
-                        versionInfos.put(result.pkgSetting.pkg.packageName,
-                                getSettingsVersionForPackage(result.pkgSetting.pkg));
-                        if (result.staticSharedLibraryInfo != null) {
-                            final PackageSetting sharedLibLatestVersionSetting =
-                                    getSharedLibLatestVersionSetting(result);
-                            if (sharedLibLatestVersionSetting != null) {
-                                lastStaticSharedLibSettings.put(result.pkgSetting.pkg.packageName,
-                                        sharedLibLatestVersionSetting);
-                            }
+                    if (null != preparedScans.put(result.pkgSetting.pkg.getPackageName(), result)) {
+                        request.installResult.setError(
+                                PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
+                                "Duplicate package " + result.pkgSetting.pkg.getPackageName()
+                                        + " in multi-package install request.");
+                        return;
+                    }
+                    createdAppId.put(packageName, optimisticallyRegisterAppId(result));
+                    versionInfos.put(result.pkgSetting.pkg.getPackageName(),
+                            getSettingsVersionForPackage(result.pkgSetting.pkg));
+                    if (result.staticSharedLibraryInfo != null) {
+                        final PackageSetting sharedLibLatestVersionSetting =
+                                getSharedLibLatestVersionSetting(result);
+                        if (sharedLibLatestVersionSetting != null) {
+                            lastStaticSharedLibSettings.put(result.pkgSetting.pkg.getPackageName(),
+                                    sharedLibLatestVersionSetting);
                         }
                     }
                 } catch (PackageManagerException e) {
@@ -15896,7 +15667,8 @@
         } finally {
             if (!success) {
                 for (ScanResult result : preparedScans.values()) {
-                    if (createdAppId.getOrDefault(result.request.pkg.packageName, false)) {
+                    if (createdAppId.getOrDefault(result.request.parsedPackage.getPackageName(),
+                            false)) {
                         cleanUpAppIdCreation(result);
                     }
                 }
@@ -15926,16 +15698,18 @@
         for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
             final boolean instantApp = ((reconciledPkg.scanResult.request.scanFlags
                             & PackageManagerService.SCAN_AS_INSTANT_APP) != 0);
-            final PackageParser.Package pkg = reconciledPkg.pkgSetting.pkg;
-            final String packageName = pkg.packageName;
+            final AndroidPackage pkg = reconciledPkg.pkgSetting.pkg;
+            final String packageName = pkg.getPackageName();
+            final boolean onIncremental = mIncrementalManager != null
+                    && isIncrementalPath(pkg.getCodePath());
             prepareAppDataAfterInstallLIF(pkg);
             if (reconciledPkg.prepareResult.clearCodeCache) {
                 clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
                         | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
             }
             if (reconciledPkg.prepareResult.replace) {
-                mDexManager.notifyPackageUpdated(pkg.packageName,
-                        pkg.baseCodePath, pkg.splitCodePaths);
+                mDexManager.notifyPackageUpdated(pkg.getPackageName(),
+                        pkg.getBaseCodePath(), pkg.getSplitCodePaths());
             }
 
             // Prepare the application profiles for the new code paths.
@@ -15949,7 +15723,7 @@
             // Check whether we need to dexopt the app.
             //
             // NOTE: it is IMPORTANT to call dexopt:
-            //   - after doRename which will sync the package data from PackageParser.Package and
+            //   - after doRename which will sync the package data from AndroidPackage and
             //     its corresponding ApplicationInfo.
             //   - after installNewPackageLIF or replacePackageLIF which will update result with the
             //     uid of the application (pkg.applicationInfo.uid).
@@ -15958,6 +15732,7 @@
             // We only need to dexopt if the package meets ALL of the following conditions:
             //   1) it is not an instant app or if it is then dexopt is enabled via gservices.
             //   2) it is not debuggable.
+            //   3) it is not on Incremental File System.
             //
             // Note that we do not dexopt instant apps by default. dexopt can take some time to
             // complete, so we skip this step during installation. Instead, we'll take extra time
@@ -15968,7 +15743,8 @@
             final boolean performDexopt =
                     (!instantApp || Global.getInt(mContext.getContentResolver(),
                     Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
-                    && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);
+                    && ((pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) == 0)
+                    && (!onIncremental);
 
             if (performDexopt) {
                 // Compile the layout resources.
@@ -16012,20 +15788,19 @@
         public final int scanFlags;
         public final int parseFlags;
         @Nullable /* The original Package if it is being replaced, otherwise {@code null} */
-        public final PackageParser.Package existingPackage;
-        public final PackageParser.Package packageToScan;
+        public final AndroidPackage existingPackage;
+        public final ParsedPackage packageToScan;
         public final boolean clearCodeCache;
         public final boolean system;
         public final PackageFreezer freezer;
         public final PackageSetting originalPs;
         public final PackageSetting disabledPs;
-        public final PackageSetting[] childPackageSettings;
 
         private PrepareResult(boolean replace, int scanFlags,
-                int parseFlags, PackageParser.Package existingPackage,
-                PackageParser.Package packageToScan, boolean clearCodeCache, boolean system,
+                int parseFlags, AndroidPackage existingPackage,
+                ParsedPackage packageToScan, boolean clearCodeCache, boolean system,
                 PackageFreezer freezer, PackageSetting originalPs,
-                PackageSetting disabledPs, PackageSetting[] childPackageSettings) {
+                PackageSetting disabledPs) {
             this.replace = replace;
             this.scanFlags = scanFlags;
             this.parseFlags = parseFlags;
@@ -16036,7 +15811,6 @@
             this.freezer = freezer;
             this.originalPs = originalPs;
             this.disabledPs = disabledPs;
-            this.childPackageSettings = childPackageSettings;
         }
     }
 
@@ -16115,10 +15889,10 @@
         pp.setCallback(mPackageParserCallback);
 
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
-        final PackageParser.Package pkg;
+        ParsedPackage parsedPackage;
         try {
-            pkg = pp.parsePackage(tmpPackageFile, parseFlags);
-            DexMetadataHelper.validatePackageDexMetadata(pkg);
+            parsedPackage = pp.parseParsedPackage(tmpPackageFile, parseFlags, false);
+            DexMetadataHelper.validatePackageDexMetadata(parsedPackage);
         } catch (PackageParserException e) {
             throw new PrepareFailure("Failed parse during installPackageLI", e);
         } finally {
@@ -16127,23 +15901,23 @@
 
         // Instant apps have several additional install-time checks.
         if (instantApp) {
-            if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
-                Slog.w(TAG,
-                        "Instant app package " + pkg.packageName + " does not target at least O");
+            if (parsedPackage.getTargetSdkVersion() < Build.VERSION_CODES.O) {
+                Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName()
+                                + " does not target at least O");
                 throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                         "Instant app package must target at least O");
             }
-            if (pkg.mSharedUserId != null) {
-                Slog.w(TAG, "Instant app package " + pkg.packageName
+            if (parsedPackage.getSharedUserId() != null) {
+                Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName()
                         + " may not declare sharedUserId.");
                 throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                         "Instant app package may not declare a sharedUserId");
             }
         }
 
-        if (pkg.applicationInfo.isStaticSharedLibrary()) {
+        if (parsedPackage.isStaticSharedLibrary()) {
             // Static shared libraries have synthetic package names
-            renameStaticSharedLibraryPackage(pkg);
+            renameStaticSharedLibraryPackage(parsedPackage);
 
             // No static shared libs on external storage
             if (onExternal) {
@@ -16153,43 +15927,16 @@
             }
         }
 
-        // If we are installing a clustered package add results for the children
-        if (pkg.childPackages != null) {
-            synchronized (mLock) {
-                final int childCount = pkg.childPackages.size();
-                for (int i = 0; i < childCount; i++) {
-                    PackageParser.Package childPkg = pkg.childPackages.get(i);
-                    PackageInstalledInfo childRes = new PackageInstalledInfo();
-                    childRes.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
-                    childRes.pkg = childPkg;
-                    childRes.name = childPkg.packageName;
-                    PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
-                    if (childPs != null) {
-                        childRes.origUsers = childPs.queryInstalledUsers(
-                                mUserManager.getUserIds(), true);
-                    }
-                    if ((mPackages.containsKey(childPkg.packageName))) {
-                        childRes.removedInfo = new PackageRemovedInfo(this);
-                        childRes.removedInfo.removedPackage = childPkg.packageName;
-                        childRes.removedInfo.installerPackageName =
-                                childPs.installSource.installerPackageName;
-                    }
-                    if (res.addedChildPackages == null) {
-                        res.addedChildPackages = new ArrayMap<>();
-                    }
-                    res.addedChildPackages.put(childPkg.packageName, childRes);
-                }
-            }
-        }
-
         // If package doesn't declare API override, mark that we have an install
         // time CPU ABI override.
-        if (TextUtils.isEmpty(pkg.cpuAbiOverride)) {
-            pkg.cpuAbiOverride = args.abiOverride;
+        // TODO(b/135203078): Isn't this always true because cpuAbiOverride isn't assigned during
+        //  parsing?
+        if (TextUtils.isEmpty(parsedPackage.getCpuAbiOverride())) {
+            parsedPackage.setCpuAbiOverride(args.abiOverride);
         }
 
-        String pkgName = res.name = pkg.packageName;
-        if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0) {
+        String pkgName = res.name = parsedPackage.getPackageName();
+        if ((parsedPackage.getFlags() & ApplicationInfo.FLAG_TEST_ONLY) != 0) {
             if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) {
                 throw new PrepareFailure(INSTALL_FAILED_TEST_ONLY, "installPackageLI");
             }
@@ -16198,17 +15945,18 @@
         try {
             // either use what we've been given or parse directly from the APK
             if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) {
-                pkg.setSigningDetails(args.signingDetails);
+                parsedPackage.setSigningDetails(args.signingDetails);
             } else {
-                PackageParser.collectCertificates(pkg, false /* skipVerify */);
+                // TODO(b/136132412): skip for Incremental installation
+                ApkParseUtils.collectCertificates(parsedPackage, false /* skipVerify */);
             }
         } catch (PackageParserException e) {
             throw new PrepareFailure("Failed collect during installPackageLI", e);
         }
 
-        if (instantApp && pkg.mSigningDetails.signatureSchemeVersion
+        if (instantApp && parsedPackage.getSigningDetails().signatureSchemeVersion
                 < SignatureSchemeVersion.SIGNING_BLOCK_V2) {
-            Slog.w(TAG, "Instant app package " + pkg.packageName
+            Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName()
                     + " is not signed with at least APK Signature Scheme v2");
             throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID,
                     "Instant app package must be signed with APK Signature Scheme v2 or greater");
@@ -16222,15 +15970,15 @@
             // Check if installing already existing package
             if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
                 String oldName = mSettings.getRenamedPackageLPr(pkgName);
-                if (pkg.mOriginalPackages != null
-                        && pkg.mOriginalPackages.contains(oldName)
+                if (parsedPackage.getOriginalPackages() != null
+                        && parsedPackage.getOriginalPackages().contains(oldName)
                         && mPackages.containsKey(oldName)) {
                     // This package is derived from an original package,
                     // and this device has been updating from that original
                     // name.  We must continue using the original name, so
                     // rename the new package here.
-                    pkg.setPackageName(oldName);
-                    pkgName = pkg.packageName;
+                    parsedPackage.setPackageName(oldName);
+                    pkgName = parsedPackage.getPackageName();
                     replace = true;
                     if (DEBUG_INSTALL) {
                         Slog.d(TAG, "Replacing existing renamed package: oldName="
@@ -16243,43 +15991,27 @@
                     if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);
                 }
 
-                // Child packages are installed through the parent package
-                if (pkg.parentPackage != null) {
-                    throw new PrepareFailure(
-                            PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
-                            "Package " + pkg.packageName + " is child of package "
-                                    + pkg.parentPackage.parentPackage + ". Child packages "
-                                    + "can be updated only through the parent package.");
-                }
-
                 if (replace) {
                     // Prevent apps opting out from runtime permissions
-                    PackageParser.Package oldPackage = mPackages.get(pkgName);
-                    final int oldTargetSdk = oldPackage.applicationInfo.targetSdkVersion;
-                    final int newTargetSdk = pkg.applicationInfo.targetSdkVersion;
+                    AndroidPackage oldPackage = mPackages.get(pkgName);
+                    final int oldTargetSdk = oldPackage.getTargetSdkVersion();
+                    final int newTargetSdk = parsedPackage.getTargetSdkVersion();
                     if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1
                             && newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) {
                         throw new PrepareFailure(
                                 PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,
-                                "Package " + pkg.packageName + " new target SDK " + newTargetSdk
+                                "Package " + parsedPackage.getPackageName()
+                                        + " new target SDK " + newTargetSdk
                                         + " doesn't support runtime permissions but the old"
                                         + " target SDK " + oldTargetSdk + " does.");
                     }
                     // Prevent persistent apps from being updated
-                    if (((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0)
+                    if (((oldPackage.getFlags() & ApplicationInfo.FLAG_PERSISTENT) != 0)
                             && ((installFlags & PackageManager.INSTALL_STAGED) == 0)) {
                         throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK,
-                                "Package " + oldPackage.packageName + " is a persistent app. "
+                                "Package " + oldPackage.getPackageName() + " is a persistent app. "
                                         + "Persistent apps are not updateable.");
                     }
-                    // Prevent installing of child packages
-                    if (oldPackage.parentPackage != null) {
-                        throw new PrepareFailure(
-                                PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
-                                "Package " + pkg.packageName + " is child of package "
-                                        + oldPackage.parentPackage + ". Child packages "
-                                        + "can be updated only through the parent package.");
-                    }
                 }
             }
 
@@ -16292,8 +16024,8 @@
                 // of the same package, therefore we need to compare signatures against
                 // the package setting for the latest library version.
                 PackageSetting signatureCheckPs = ps;
-                if (pkg.applicationInfo.isStaticSharedLibrary()) {
-                    SharedLibraryInfo libraryInfo = getLatestSharedLibraVersionLPr(pkg);
+                if (parsedPackage.isStaticSharedLibrary()) {
+                    SharedLibraryInfo libraryInfo = getLatestSharedLibraVersionLPr(parsedPackage);
                     if (libraryInfo != null) {
                         signatureCheckPs = mSettings.getPackageLPr(libraryInfo.getPackageName());
                     }
@@ -16304,23 +16036,23 @@
                 // bail early here before tripping over redefined permissions.
                 final KeySetManagerService ksms = mSettings.mKeySetManagerService;
                 if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
-                    if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
+                    if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) {
                         throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
-                                + pkg.packageName + " upgrade keys do not match the "
+                                + parsedPackage.getPackageName() + " upgrade keys do not match the "
                                 + "previously installed version");
                     }
                 } else {
                     try {
-                        final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg);
-                        final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg);
+                        final boolean compareCompat = isCompatSignatureUpdateNeeded(parsedPackage);
+                        final boolean compareRecover = isRecoverSignatureUpdateNeeded(
+                                parsedPackage);
                         // We don't care about disabledPkgSetting on install for now.
-                        final boolean compatMatch = verifySignatures(
-                                signatureCheckPs, null, pkg.mSigningDetails, compareCompat,
-                                compareRecover);
+                        final boolean compatMatch = verifySignatures(signatureCheckPs, null,
+                                parsedPackage.getSigningDetails(), compareCompat, compareRecover);
                         // The new KeySets will be re-added later in the scanning process.
                         if (compatMatch) {
                             synchronized (mLock) {
-                                ksms.removeAppKeySetDataLPw(pkg.packageName);
+                                ksms.removeAppKeySetDataLPw(parsedPackage.getPackageName());
                             }
                         }
                     } catch (PackageManagerException e) {
@@ -16328,27 +16060,25 @@
                     }
                 }
 
-                if (ps.pkg != null && ps.pkg.applicationInfo != null) {
-                    systemApp = (ps.pkg.applicationInfo.flags &
-                            ApplicationInfo.FLAG_SYSTEM) != 0;
+                if (ps.pkg != null) {
+                    systemApp = (ps.pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0;
                 }
                 res.origUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
             }
 
 
-            int N = pkg.permissions.size();
+            int N = ArrayUtils.size(parsedPackage.getPermissions());
             for (int i = N - 1; i >= 0; i--) {
-                final PackageParser.Permission perm = pkg.permissions.get(i);
-                final BasePermission bp =
-                        (BasePermission) mPermissionManager.getPermissionTEMP(perm.info.name);
+                final ParsedPermission perm = parsedPackage.getPermissions().get(i);
+                final BasePermission bp = mPermissionManager.getPermissionTEMP(perm.getName());
 
                 // Don't allow anyone but the system to define ephemeral permissions.
-                if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
+                if ((perm.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
                         && !systemApp) {
-                    Slog.w(TAG, "Non-System package " + pkg.packageName
+                    Slog.w(TAG, "Non-System package " + parsedPackage.getPackageName()
                             + " attempting to delcare ephemeral permission "
-                            + perm.info.name + "; Removing ephemeral.");
-                    perm.info.protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_INSTANT;
+                            + perm.getName() + "; Removing ephemeral.");
+                    perm.protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_INSTANT;
                 }
 
                 // Check whether the newly-scanned package wants to define an already-defined perm
@@ -16360,26 +16090,27 @@
                     final String sourcePackageName = bp.getSourcePackageName();
                     final PackageSettingBase sourcePackageSetting = bp.getSourcePackageSetting();
                     final KeySetManagerService ksms = mSettings.mKeySetManagerService;
-                    if (sourcePackageName.equals(pkg.packageName)
+                    if (sourcePackageName.equals(parsedPackage.getPackageName())
                             && (ksms.shouldCheckUpgradeKeySetLocked(
                             sourcePackageSetting, scanFlags))) {
-                        sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg);
+                        sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, parsedPackage);
                     } else {
 
                         // in the event of signing certificate rotation, we need to see if the
                         // package's certificate has rotated from the current one, or if it is an
                         // older certificate with which the current is ok with sharing permissions
                         if (sourcePackageSetting.signatures.mSigningDetails.checkCapability(
-                                pkg.mSigningDetails,
+                                parsedPackage.getSigningDetails(),
                                 PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
                             sigsOk = true;
-                        } else if (pkg.mSigningDetails.checkCapability(
+                        } else if (parsedPackage.getSigningDetails().checkCapability(
                                 sourcePackageSetting.signatures.mSigningDetails,
                                 PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
 
                             // the scanned package checks out, has signing certificate rotation
                             // history, and is newer; bring it over
-                            sourcePackageSetting.signatures.mSigningDetails = pkg.mSigningDetails;
+                            sourcePackageSetting.signatures.mSigningDetails =
+                                    parsedPackage.getSigningDetails();
                             sigsOk = true;
                         } else {
                             sigsOk = false;
@@ -16391,30 +16122,31 @@
                         // redefinitions.
                         if (!sourcePackageName.equals("android")) {
                             throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
-                                    + pkg.packageName
+                                    + parsedPackage.getPackageName()
                                     + " attempting to redeclare permission "
-                                    + perm.info.name + " already owned by "
+                                    + perm.getName() + " already owned by "
                                     + sourcePackageName)
-                                    .conflictsWithExistingPermission(perm.info.name,
+                                    .conflictsWithExistingPermission(perm.getName(),
                                             sourcePackageName);
                         } else {
-                            Slog.w(TAG, "Package " + pkg.packageName
+                            Slog.w(TAG, "Package " + parsedPackage.getPackageName()
                                     + " attempting to redeclare system permission "
-                                    + perm.info.name + "; ignoring new declaration");
-                            pkg.permissions.remove(i);
+                                    + perm.getName() + "; ignoring new declaration");
+                            parsedPackage.removePermission(i);
                         }
-                    } else if (!PLATFORM_PACKAGE_NAME.equals(pkg.packageName)) {
+                    } else if (!PLATFORM_PACKAGE_NAME.equals(parsedPackage.getPackageName())) {
                         // Prevent apps to change protection level to dangerous from any other
                         // type as this would allow a privilege escalation where an app adds a
                         // normal/signature permission in other app's group and later redefines
                         // it as dangerous leading to the group auto-grant.
-                        if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
+                        if ((perm.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
                                 == PermissionInfo.PROTECTION_DANGEROUS) {
                             if (bp != null && !bp.isRuntime()) {
-                                Slog.w(TAG, "Package " + pkg.packageName + " trying to change a "
-                                        + "non-runtime permission " + perm.info.name
+                                Slog.w(TAG, "Package " + parsedPackage.getPackageName()
+                                        + " trying to change a non-runtime permission "
+                                        + perm.getName()
                                         + " to runtime; keeping old protection level");
-                                perm.info.protectionLevel = bp.getProtectionLevel();
+                                perm.protectionLevel = bp.getProtectionLevel();
                             }
                         }
                     }
@@ -16448,8 +16180,8 @@
 
                 // We moved the entire application as-is, so bring over the
                 // previously derived ABI information.
-                pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;
-                pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString;
+                parsedPackage.setPrimaryCpuAbi(ps.primaryCpuAbiString)
+                        .setSecondaryCpuAbi(ps.secondaryCpuAbiString);
             }
 
         } else {
@@ -16457,14 +16189,14 @@
             scanFlags |= SCAN_NO_DEX;
 
             try {
-                String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
-                        args.abiOverride : pkg.cpuAbiOverride);
-                final boolean extractNativeLibs = !pkg.isLibrary();
+                String abiOverride = (TextUtils.isEmpty(parsedPackage.getCpuAbiOverride())
+                        ? args.abiOverride : parsedPackage.getCpuAbiOverride());
+                final boolean extractNativeLibs = !parsedPackage.isLibrary();
                 final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
                         derivedAbi = mInjector.getAbiHelper().derivePackageAbi(
-                                pkg, abiOverride, extractNativeLibs);
-                derivedAbi.first.applyTo(pkg);
-                derivedAbi.second.applyTo(pkg);
+                                parsedPackage, abiOverride, extractNativeLibs);
+                derivedAbi.first.applyTo(parsedPackage);
+                derivedAbi.second.applyTo(parsedPackage);
             } catch (PackageManagerException pme) {
                 Slog.e(TAG, "Error deriving application ABI", pme);
                 throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
@@ -16472,19 +16204,19 @@
             }
         }
 
-        if (!args.doRename(res.returnCode, pkg)) {
+        if (!args.doRename(res.returnCode, parsedPackage)) {
             throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
         }
 
         try {
-            setUpFsVerityIfPossible(pkg);
+            setUpFsVerityIfPossible(parsedPackage);
         } catch (InstallerException | IOException | DigestException | NoSuchAlgorithmException e) {
             throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
                     "Failed to set up verity: " + e);
         }
 
         if (!instantApp) {
-            startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
+            startIntentFilterVerifications(args.user.getIdentifier(), replace, parsedPackage);
         } else {
             if (DEBUG_DOMAIN_VERIFICATION) {
                 Slog.d(TAG, "Not verifying instant app install for app links: " + pkgName);
@@ -16494,7 +16226,7 @@
                 freezePackageForInstall(pkgName, installFlags, "installPackageLI");
         boolean shouldCloseFreezerBeforeReturn = true;
         try {
-            final PackageParser.Package existingPackage;
+            final AndroidPackage existingPackage;
             String renamedPackage = null;
             boolean sysPkg = false;
             int targetScanFlags = scanFlags;
@@ -16503,14 +16235,15 @@
             final PackageSetting disabledPs;
             final PackageSetting[] childPackages;
             if (replace) {
-                if (pkg.applicationInfo.isStaticSharedLibrary()) {
+                if (parsedPackage.isStaticSharedLibrary()) {
                     // Static libs have a synthetic package name containing the version
                     // and cannot be updated as an update would get a new package name,
                     // unless this is the exact same version code which is useful for
                     // development.
-                    PackageParser.Package existingPkg = mPackages.get(pkg.packageName);
+                    AndroidPackage existingPkg = mPackages.get(parsedPackage.getPackageName());
                     if (existingPkg != null
-                            && existingPkg.getLongVersionCode() != pkg.getLongVersionCode()) {
+                            && existingPkg.getLongVersionCode()
+                            != parsedPackage.getLongVersionCode()) {
                         throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PACKAGE,
                                 "Packages declaring "
                                         + "static-shared libs cannot be updated");
@@ -16519,8 +16252,8 @@
 
                 final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
 
-                final PackageParser.Package oldPackage;
-                final String pkgName11 = pkg.packageName;
+                final AndroidPackage oldPackage;
+                final String pkgName11 = parsedPackage.getPackageName();
                 final int[] allUsers;
                 final int[] installedUsers;
 
@@ -16528,8 +16261,9 @@
                     oldPackage = mPackages.get(pkgName11);
                     existingPackage = oldPackage;
                     if (DEBUG_INSTALL) {
+                        // TODO(b/135203078): PackageImpl.toString()
                         Slog.d(TAG,
-                                "replacePackageLI: new=" + pkg + ", old=" + oldPackage);
+                                "replacePackageLI: new=" + parsedPackage + ", old=" + oldPackage);
                     }
 
                     ps = mSettings.mPackages.get(pkgName11);
@@ -16538,17 +16272,18 @@
                     // verify signatures are valid
                     final KeySetManagerService ksms = mSettings.mKeySetManagerService;
                     if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) {
-                        if (!ksms.checkUpgradeKeySetLocked(ps, pkg)) {
+                        if (!ksms.checkUpgradeKeySetLocked(ps, parsedPackage)) {
                             throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
                                     "New package not signed by keys specified by upgrade-keysets: "
                                             + pkgName11);
                         }
                     } else {
                         // default to original signature matching
-                        if (!pkg.mSigningDetails.checkCapability(oldPackage.mSigningDetails,
+                        if (!parsedPackage.getSigningDetails().checkCapability(
+                                oldPackage.getSigningDetails(),
                                 SigningDetails.CertCapabilities.INSTALLED_DATA)
-                                && !oldPackage.mSigningDetails.checkCapability(
-                                pkg.mSigningDetails,
+                                && !oldPackage.getSigningDetails().checkCapability(
+                                parsedPackage.getSigningDetails(),
                                 SigningDetails.CertCapabilities.ROLLBACK)) {
                             throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
                                     "New package has a different signature: " + pkgName11);
@@ -16556,13 +16291,13 @@
                     }
 
                     // don't allow a system upgrade unless the upgrade hash matches
-                    if (oldPackage.restrictUpdateHash != null && oldPackage.isSystem()) {
+                    if (oldPackage.getRestrictUpdateHash() != null && oldPackage.isSystem()) {
                         final byte[] digestBytes;
                         try {
                             final MessageDigest digest = MessageDigest.getInstance("SHA-512");
-                            updateDigest(digest, new File(pkg.baseCodePath));
-                            if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
-                                for (String path : pkg.splitCodePaths) {
+                            updateDigest(digest, new File(parsedPackage.getBaseCodePath()));
+                            if (!ArrayUtils.isEmpty(parsedPackage.getSplitCodePaths())) {
+                                for (String path : parsedPackage.getSplitCodePaths()) {
                                     updateDigest(digest, new File(path));
                                 }
                             }
@@ -16571,21 +16306,25 @@
                             throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
                                     "Could not compute hash: " + pkgName11);
                         }
-                        if (!Arrays.equals(oldPackage.restrictUpdateHash, digestBytes)) {
+                        if (!Arrays.equals(oldPackage.getRestrictUpdateHash(), digestBytes)) {
                             throw new PrepareFailure(INSTALL_FAILED_INVALID_APK,
                                     "New package fails restrict-update check: " + pkgName11);
                         }
                         // retain upgrade restriction
-                        pkg.restrictUpdateHash = oldPackage.restrictUpdateHash;
+                        parsedPackage.setRestrictUpdateHash(oldPackage.getRestrictUpdateHash());
                     }
 
                     // Check for shared user id changes
-                    String invalidPackageName =
-                            getParentOrChildPackageChangedSharedUser(oldPackage, pkg);
+                    String invalidPackageName = null;
+                    if (!Objects.equals(oldPackage.getSharedUserId(),
+                            parsedPackage.getSharedUserId())) {
+                        invalidPackageName = parsedPackage.getPackageName();
+                    }
+
                     if (invalidPackageName != null) {
                         throw new PrepareFailure(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
                                 "Package " + invalidPackageName + " tried to change user "
-                                        + oldPackage.mSharedUserId);
+                                        + oldPackage.getSharedUserId());
                     }
 
                     // In case of rollback, remember per-user/profile install state
@@ -16618,10 +16357,10 @@
 
                 // Update what is removed
                 res.removedInfo = new PackageRemovedInfo(this);
-                res.removedInfo.uid = oldPackage.applicationInfo.uid;
-                res.removedInfo.removedPackage = oldPackage.packageName;
+                res.removedInfo.uid = oldPackage.getUid();
+                res.removedInfo.removedPackage = oldPackage.getPackageName();
                 res.removedInfo.installerPackageName = ps.installSource.installerPackageName;
-                res.removedInfo.isStaticSharedLib = pkg.staticSharedLibName != null;
+                res.removedInfo.isStaticSharedLib = parsedPackage.getStaticSharedLibName() != null;
                 res.removedInfo.isUpdate = true;
                 res.removedInfo.origUsers = installedUsers;
                 res.removedInfo.installReasons = new SparseArray<>(installedUsers.length);
@@ -16630,53 +16369,6 @@
                     res.removedInfo.installReasons.put(userId, ps.getInstallReason(userId));
                 }
 
-                childPackages = mSettings.getChildSettingsLPr(ps);
-                if (childPackages != null) {
-                    for (PackageSetting childPs : childPackages) {
-                        boolean childPackageUpdated = false;
-                        PackageParser.Package childPkg = (childPs == null) ? null : childPs.pkg;
-                        if (res.addedChildPackages != null) {
-                            PackageInstalledInfo childRes = res.addedChildPackages.get(
-                                    childPkg.packageName);
-                            if (childRes != null) {
-                                childRes.removedInfo.uid = childPkg.applicationInfo.uid;
-                                childRes.removedInfo.removedPackage = childPkg.packageName;
-                                if (childPs != null) {
-                                    childRes.removedInfo.installerPackageName =
-                                            childPs.installSource.installerPackageName;
-                                }
-                                childRes.removedInfo.isUpdate = true;
-                                childRes.removedInfo.installReasons =
-                                        res.removedInfo.installReasons;
-                                childPackageUpdated = true;
-                            }
-                        }
-                        if (!childPackageUpdated) {
-                            PackageRemovedInfo childRemovedRes = new PackageRemovedInfo(this);
-                            childRemovedRes.removedPackage = childPkg.packageName;
-                            if (childPs != null) {
-                                childRemovedRes.installerPackageName =
-                                        childPs.installSource.installerPackageName;
-                            }
-                            childRemovedRes.isUpdate = false;
-                            childRemovedRes.dataRemoved = true;
-                            synchronized (mLock) {
-                                if (childPs != null) {
-                                    childRemovedRes.origUsers = childPs.queryInstalledUsers(
-                                            allUsers,
-                                            true);
-                                }
-                            }
-                            if (res.removedInfo.removedChildPackages == null) {
-                                res.removedInfo.removedChildPackages = new ArrayMap<>();
-                            }
-                            res.removedInfo.removedChildPackages.put(childPkg.packageName,
-                                    childRemovedRes);
-                        }
-                    }
-                }
-
-
                 sysPkg = (isSystemApp(oldPackage));
                 if (sysPkg) {
                     // Set the system/privileged/oem/vendor/product flags as needed
@@ -16695,41 +16387,30 @@
                             | (odm ? SCAN_AS_ODM : 0);
 
                     if (DEBUG_INSTALL) {
-                        Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
+                        Slog.d(TAG, "replaceSystemPackageLI: new=" + parsedPackage
                                 + ", old=" + oldPackage);
                     }
                     res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
-                    pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP,
-                            ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
+                    parsedPackage.setUpdatedSystemApp(true);
                     targetParseFlags = systemParseFlags;
                     targetScanFlags = systemScanFlags;
                 } else { // non system replace
                     replace = true;
                     if (DEBUG_INSTALL) {
                         Slog.d(TAG,
-                                "replaceNonSystemPackageLI: new=" + pkg + ", old="
+                                "replaceNonSystemPackageLI: new=" + parsedPackage + ", old="
                                         + oldPackage);
                     }
-
-                    String pkgName1 = oldPackage.packageName;
-                    boolean deletedPkg = true;
-                    boolean addedPkg = false;
-                    boolean updatedSettings = false;
-
-                    final long origUpdateTime = (pkg.mExtras != null)
-                            ? ((PackageSetting) pkg.mExtras).lastUpdateTime : 0;
-
                 }
             } else { // new package install
                 ps = null;
-                childPackages = null;
                 disabledPs = null;
                 replace = false;
                 existingPackage = null;
                 // Remember this for later, in case we need to rollback this install
-                String pkgName1 = pkg.packageName;
+                String pkgName1 = parsedPackage.getPackageName();
 
-                if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
+                if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + parsedPackage);
 
                 // TODO(patb): MOVE TO RECONCILE
                 synchronized (mLock) {
@@ -16756,8 +16437,8 @@
             shouldCloseFreezerBeforeReturn = false;
 
             return new PrepareResult(replace, targetScanFlags, targetParseFlags,
-                    existingPackage, pkg, replace /* clearCodeCache */, sysPkg, freezer,
-                    ps, disabledPs, childPackages);
+                    existingPackage, parsedPackage, replace /* clearCodeCache */, sysPkg, freezer,
+                    ps, disabledPs);
         } finally {
             if (shouldCloseFreezerBeforeReturn) {
                 freezer.close();
@@ -16772,7 +16453,7 @@
      * <p>When the feature flag is set to legacy mode, only APK is supported (with some experimental
      * kernel patches). In normal mode, all file format can be supported.
      */
-    private void setUpFsVerityIfPossible(PackageParser.Package pkg) throws InstallerException,
+    private void setUpFsVerityIfPossible(AndroidPackage pkg) throws InstallerException,
             PrepareFailure, IOException, DigestException, NoSuchAlgorithmException {
         final boolean standardMode = PackageManagerServiceUtils.isApkVerityEnabled();
         final boolean legacyMode = PackageManagerServiceUtils.isLegacyApkVerityEnabled();
@@ -16784,11 +16465,11 @@
         ArrayMap<String, String> fsverityCandidates = new ArrayMap<>();
         if (legacyMode) {
             synchronized (mLock) {
-                final PackageSetting ps = mSettings.mPackages.get(pkg.packageName);
+                final PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName());
                 if (ps != null && ps.isPrivileged()) {
-                    fsverityCandidates.put(pkg.baseCodePath, null);
-                    if (pkg.splitCodePaths != null) {
-                        for (String splitPath : pkg.splitCodePaths) {
+                    fsverityCandidates.put(pkg.getBaseCodePath(), null);
+                    if (pkg.getSplitCodePaths() != null) {
+                        for (String splitPath : pkg.getSplitCodePaths()) {
                             fsverityCandidates.put(splitPath, null);
                         }
                     }
@@ -16797,16 +16478,17 @@
         } else {
             // NB: These files will become only accessible if the signing key is loaded in kernel's
             // .fs-verity keyring.
-            fsverityCandidates.put(pkg.baseCodePath,
-                    VerityUtils.getFsveritySignatureFilePath(pkg.baseCodePath));
+            fsverityCandidates.put(pkg.getBaseCodePath(),
+                    VerityUtils.getFsveritySignatureFilePath(pkg.getBaseCodePath()));
 
-            final String dmPath = DexMetadataHelper.buildDexMetadataPathForApk(pkg.baseCodePath);
+            final String dmPath = DexMetadataHelper.buildDexMetadataPathForApk(
+                    pkg.getBaseCodePath());
             if (new File(dmPath).exists()) {
                 fsverityCandidates.put(dmPath, VerityUtils.getFsveritySignatureFilePath(dmPath));
             }
 
-            if (pkg.splitCodePaths != null) {
-                for (String path : pkg.splitCodePaths) {
+            if (pkg.getSplitCodePaths() != null) {
+                for (String path : pkg.getSplitCodePaths()) {
                     fsverityCandidates.put(path, VerityUtils.getFsveritySignatureFilePath(path));
 
                     final String splitDmPath = DexMetadataHelper.buildDexMetadataPathForApk(path);
@@ -16860,8 +16542,7 @@
         }
     }
 
-    private void startIntentFilterVerifications(int userId, boolean replacing,
-            PackageParser.Package pkg) {
+    private void startIntentFilterVerifications(int userId, boolean replacing, AndroidPackage pkg) {
         if (mIntentFilterVerifierComponent == null) {
             Slog.w(TAG, "No IntentFilter verification will not be done as "
                     + "there is no IntentFilterVerifier available!");
@@ -16874,29 +16555,29 @@
                 (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
 
         Message msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS);
-        msg.obj = new IFVerificationParams(pkg, replacing, userId, verifierUid);
+        msg.obj = new IFVerificationParams(
+                pkg.getPackageName(),
+                hasDomainURLs(pkg),
+                pkg.getActivities(),
+                replacing,
+                userId,
+                verifierUid
+        );
         mHandler.sendMessage(msg);
-
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            PackageParser.Package childPkg = pkg.childPackages.get(i);
-            msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS);
-            msg.obj = new IFVerificationParams(childPkg, replacing, userId, verifierUid);
-            mHandler.sendMessage(msg);
-        }
     }
 
     private void verifyIntentFiltersIfNeeded(int userId, int verifierUid, boolean replacing,
-            PackageParser.Package pkg) {
-        int size = pkg.activities.size();
+            String packageName,
+            boolean hasDomainUrls,
+            List<ParsedActivity> activities) {
+        int size = activities.size();
         if (size == 0) {
             if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
                     "No activity, so no need to verify any IntentFilter!");
             return;
         }
 
-        final boolean hasDomainURLs = hasDomainURLs(pkg);
-        if (!hasDomainURLs) {
+        if (!hasDomainUrls) {
             if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
                     "No domain URLs, so no need to verify any IntentFilter!");
             return;
@@ -16907,7 +16588,6 @@
                 + " Activities needs verification ...");
 
         int count = 0;
-        final String packageName = pkg.packageName;
 
         synchronized (mLock) {
             // If this is a new install and we see that we've already run verification for this
@@ -16926,8 +16606,8 @@
 
             // If any filters need to be verified, then all need to be.
             boolean needToVerify = false;
-            for (PackageParser.Activity a : pkg.activities) {
-                for (ActivityIntentInfo filter : a.intents) {
+            for (ParsedActivity a : activities) {
+                for (ParsedActivityIntentInfo filter : a.intents) {
                     if (filter.needsVerification() && needsNetworkVerificationLPr(filter)) {
                         if (DEBUG_DOMAIN_VERIFICATION) {
                             Slog.d(TAG,
@@ -16941,8 +16621,8 @@
 
             if (needToVerify) {
                 final int verificationId = mIntentFilterVerificationToken++;
-                for (PackageParser.Activity a : pkg.activities) {
-                    for (ActivityIntentInfo filter : a.intents) {
+                for (ParsedActivity a : activities) {
+                    for (ParsedActivityIntentInfo filter : a.intents) {
                         if (filter.handlesWebUris(true) && needsNetworkVerificationLPr(filter)) {
                             if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
                                     "Verification needed for IntentFilter:" + filter.toString());
@@ -16968,9 +16648,8 @@
     }
 
     @GuardedBy("mLock")
-    private boolean needsNetworkVerificationLPr(ActivityIntentInfo filter) {
-        final ComponentName cn  = filter.activity.getComponentName();
-        final String packageName = cn.getPackageName();
+    private boolean needsNetworkVerificationLPr(ParsedActivityIntentInfo filter) {
+        final String packageName = filter.getPackageName();
 
         IntentFilterVerificationInfo ivi = mSettings.getIntentFilterVerificationLPr(
                 packageName);
@@ -16990,45 +16669,45 @@
         }
     }
 
-    private static boolean isExternal(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
+    private static boolean isExternal(AndroidPackage pkg) {
+        return (pkg.getFlags() & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
     }
 
     private static boolean isExternal(PackageSetting ps) {
         return (ps.pkgFlags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
     }
 
-    static boolean isSystemApp(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+    static boolean isSystemApp(AndroidPackage pkg) {
+        return (pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0;
     }
 
-    private static boolean isPrivilegedApp(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
+    private static boolean isPrivilegedApp(AndroidPackage pkg) {
+        return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
     }
 
-    private static boolean isOemApp(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
+    private static boolean isOemApp(AndroidPackage pkg) {
+        return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
     }
 
-    private static boolean isVendorApp(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
+    private static boolean isVendorApp(AndroidPackage pkg) {
+        return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
     }
 
-    private static boolean isProductApp(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
+    private static boolean isProductApp(AndroidPackage pkg) {
+        return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
     }
 
-    private static boolean isSystemExtApp(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.privateFlags
+    private static boolean isSystemExtApp(AndroidPackage pkg) {
+        return (pkg.getPrivateFlags()
                 & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0;
     }
 
-    private static boolean isOdmApp(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_ODM) != 0;
+    private static boolean isOdmApp(AndroidPackage pkg) {
+        return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_ODM) != 0;
     }
 
-    private static boolean hasDomainURLs(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0;
+    private static boolean hasDomainURLs(AndroidPackage pkg) {
+        return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0;
     }
 
     private static boolean isSystemApp(PackageSetting ps) {
@@ -17039,12 +16718,12 @@
         return (ps.pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
     }
 
-    private VersionInfo getSettingsVersionForPackage(PackageParser.Package pkg) {
+    private VersionInfo getSettingsVersionForPackage(AndroidPackage pkg) {
         if (isExternal(pkg)) {
-            if (TextUtils.isEmpty(pkg.volumeUuid)) {
+            if (TextUtils.isEmpty(pkg.getVolumeUuid())) {
                 return mSettings.getExternalVersion();
             } else {
-                return mSettings.findOrCreateVersion(pkg.volumeUuid);
+                return mSettings.findOrCreateVersion(pkg.getVolumeUuid());
             }
         } else {
             return mSettings.getInternalVersion();
@@ -17052,6 +16731,7 @@
     }
 
     private void deleteTempPackageFiles() {
+        // TODO: Is this used?
         final FilenameFilter filter =
                 (dir, name) -> name.startsWith("vmdl") && name.endsWith(".tmp");
     }
@@ -17185,11 +16865,11 @@
         });
     }
 
-    private String resolveExternalPackageNameLPr(PackageParser.Package pkg) {
-        if (pkg.staticSharedLibName != null) {
-            return pkg.manifestPackageName;
+    private String resolveExternalPackageNameLPr(AndroidPackage pkg) {
+        if (pkg.getStaticSharedLibName() != null) {
+            return pkg.getManifestPackageName();
         }
-        return pkg.packageName;
+        return pkg.getPackageName();
     }
 
     @GuardedBy("mLock")
@@ -17396,7 +17076,7 @@
 
         final PackageSetting uninstalledPs;
         final PackageSetting disabledSystemPs;
-        final PackageParser.Package pkg;
+        final AndroidPackage pkg;
 
         // for the uninstall-updates case and restricted profiles, remember the per-
         // user handle installed state
@@ -17428,9 +17108,9 @@
 
             allUsers = mUserManager.getUserIds();
 
-            if (pkg != null && pkg.staticSharedLibName != null) {
-                SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(pkg.staticSharedLibName,
-                        pkg.staticSharedLibVersion);
+            if (pkg != null && pkg.getStaticSharedLibName() != null) {
+                SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(
+                        pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion());
                 if (libraryInfo != null) {
                     for (int currUserId : allUsers) {
                         if (removeUser != UserHandle.USER_ALL && removeUser != currUserId) {
@@ -17439,7 +17119,7 @@
                         List<VersionedPackage> libClientPackages = getPackagesUsingSharedLibraryLPr(
                                 libraryInfo, MATCH_KNOWN_PACKAGES, currUserId);
                         if (!ArrayUtils.isEmpty(libClientPackages)) {
-                            Slog.w(TAG, "Not removing package " + pkg.manifestPackageName
+                            Slog.w(TAG, "Not removing package " + pkg.getManifestPackageName()
                                     + " hosting lib " + libraryInfo.getName() + " version "
                                     + libraryInfo.getLongVersion() + " used by " + libClientPackages
                                     + " for user " + currUserId);
@@ -17494,13 +17174,13 @@
             if (info.args != null) {
                 info.args.doPostDeleteLI(true);
             }
-            final PackageParser.Package stubPkg =
+            final AndroidPackage stubPkg =
                     (disabledSystemPs == null) ? null : disabledSystemPs.pkg;
-            if (stubPkg != null && stubPkg.isStub) {
+            if (stubPkg != null && stubPkg.isStub()) {
                 synchronized (mLock) {
                     // restore the enabled state of the stub; the state is overwritten when
                     // the stub is uninstalled
-                    final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.packageName);
+                    final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.getPackageName());
                     if (stubPs != null) {
                         stubPs.setEnabled(origEnabledState, userId, "android");
                     }
@@ -17509,7 +17189,7 @@
                         || origEnabledState == COMPONENT_ENABLED_STATE_ENABLED) {
                     if (DEBUG_COMPRESSION) {
                         Slog.i(TAG, "Enabling system stub after removal; pkg: "
-                                + stubPkg.packageName);
+                                + stubPkg.getPackageName());
                     }
                     enableCompressedPackage(stubPkg);
                 }
@@ -17537,7 +17217,6 @@
         boolean isStaticSharedLib;
         // Clean up resources deleted packages.
         InstallArgs args = null;
-        ArrayMap<String, PackageRemovedInfo> removedChildPackages;
         ArrayMap<String, PackageInstalledInfo> appearedChildPackages;
 
         PackageRemovedInfo(PackageSender packageSender) {
@@ -17546,24 +17225,11 @@
 
         void sendPackageRemovedBroadcasts(boolean killApp) {
             sendPackageRemovedBroadcastInternal(killApp);
-            final int childCount = removedChildPackages != null ? removedChildPackages.size() : 0;
-            for (int i = 0; i < childCount; i++) {
-                PackageRemovedInfo childInfo = removedChildPackages.valueAt(i);
-                childInfo.sendPackageRemovedBroadcastInternal(killApp);
-            }
         }
 
         void sendSystemPackageUpdatedBroadcasts() {
             if (isRemovedPackageSystemUpdate) {
                 sendSystemPackageUpdatedBroadcastsInternal();
-                final int childCount = (removedChildPackages != null)
-                        ? removedChildPackages.size() : 0;
-                for (int i = 0; i < childCount; i++) {
-                    PackageRemovedInfo childInfo = removedChildPackages.valueAt(i);
-                    if (childInfo.isRemovedPackageSystemUpdate) {
-                        childInfo.sendSystemPackageUpdatedBroadcastsInternal();
-                    }
-                }
             }
         }
 
@@ -17675,12 +17341,12 @@
         String packageName = deletedPs.name;
         if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + deletedPs);
         // Retrieve object to delete permissions for shared user later on
-        final PackageParser.Package deletedPkg = deletedPs.pkg;
+        final AndroidPackage deletedPkg = deletedPs.pkg;
         if (outInfo != null) {
             outInfo.removedPackage = packageName;
             outInfo.installerPackageName = deletedPs.installSource.installerPackageName;
             outInfo.isStaticSharedLib = deletedPkg != null
-                    && deletedPkg.staticSharedLibName != null;
+                    && deletedPkg.getStaticSharedLibName() != null;
             outInfo.populateUsers(deletedPs == null ? null
                     : deletedPs.queryInstalledUsers(mUserManager.getUserIds(), true), deletedPs);
         }
@@ -17688,14 +17354,14 @@
         removePackageLI(deletedPs.name, (flags & PackageManager.DELETE_CHATTY) != 0);
 
         if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
-            final PackageParser.Package resolvedPkg;
+            final AndroidPackage resolvedPkg;
             if (deletedPkg != null) {
                 resolvedPkg = deletedPkg;
             } else {
                 // We don't have a parsed package when it lives on an ejected
                 // adopted storage device, so fake something together
-                resolvedPkg = new PackageParser.Package(deletedPs.name);
-                resolvedPkg.setVolumeUuid(deletedPs.volumeUuid);
+                resolvedPkg = PackageImpl.buildFakeForDeletion(deletedPs.name,
+                        deletedPs.volumeUuid);
             }
             destroyAppDataLIF(resolvedPkg, UserHandle.USER_ALL,
                     FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
@@ -17809,13 +17475,13 @@
             throws SystemDeleteException {
         final boolean applyUserRestrictions =
                 (allUserHandles != null) && outInfo != null && (outInfo.origUsers != null);
-        final PackageParser.Package deletedPkg = deletedPs.pkg;
+        final AndroidPackage deletedPkg = deletedPs.pkg;
         // Confirm if the system package has been updated
         // An updated system app can be deleted. This will also have to restore
         // the system pkg from system partition
         // reader
         final PackageSetting disabledPs = action.disabledPs;
-        if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.packageName
+        if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.getPackageName()
                 + " disabledPs=" + disabledPs);
         Slog.d(TAG, "Deleting system pkg from data partition");
 
@@ -17832,21 +17498,6 @@
         if (outInfo != null) {
             // Delete the updated package
             outInfo.isRemovedPackageSystemUpdate = true;
-            if (outInfo.removedChildPackages != null) {
-                final int childCount = (deletedPs.childPackageNames != null)
-                        ? deletedPs.childPackageNames.size() : 0;
-                for (int i = 0; i < childCount; i++) {
-                    String childPackageName = deletedPs.childPackageNames.get(i);
-                    if (disabledPs.childPackageNames != null && disabledPs.childPackageNames
-                            .contains(childPackageName)) {
-                        PackageRemovedInfo childInfo = outInfo.removedChildPackages.get(
-                                childPackageName);
-                        if (childInfo != null) {
-                            childInfo.isRemovedPackageSystemUpdate = true;
-                        }
-                    }
-                }
-            }
         }
 
         if (disabledPs.versionCode < deletedPs.versionCode) {
@@ -17858,7 +17509,7 @@
         }
 
         deleteInstalledPackageLIF(deletedPs, true, flags, allUserHandles,
-                outInfo, writeSettings, disabledPs.pkg);
+                outInfo, writeSettings);
 
         // writer
         synchronized (mLock) {
@@ -17879,16 +17530,16 @@
                     outInfo == null ? null : outInfo.origUsers, deletedPs.getPermissionsState(),
                     writeSettings);
         } catch (PackageManagerException e) {
-            Slog.w(TAG, "Failed to restore system package:" + deletedPkg.packageName + ": "
+            Slog.w(TAG, "Failed to restore system package:" + deletedPkg.getPackageName() + ": "
                     + e.getMessage());
             // TODO(patb): can we avoid this; throw would come from scan...
             throw new SystemDeleteException(e);
         } finally {
-            if (disabledPs.pkg.isStub) {
+            if (disabledPs.pkg.isStub()) {
                 // We've re-installed the stub; make sure it's disabled here. If package was
                 // originally enabled, we'll install the compressed version of the application
                 // and re-enable it afterward.
-                final PackageSetting stubPs = mSettings.mPackages.get(deletedPkg.packageName);
+                final PackageSetting stubPs = mSettings.mPackages.get(deletedPkg.getPackageName());
                 if (stubPs != null) {
                     stubPs.setEnabled(
                             COMPONENT_ENABLED_STATE_DISABLED, UserHandle.USER_SYSTEM, "android");
@@ -17900,7 +17551,7 @@
     /**
      * Installs a package that's already on the system partition.
      */
-    private PackageParser.Package installPackageFromSystemLIF(@NonNull String codePathString,
+    private AndroidPackage installPackageFromSystemLIF(@NonNull String codePathString,
             @Nullable int[] allUserHandles, @Nullable int[] origUserHandles,
             @Nullable PermissionsState origPermissionState, boolean writeSettings)
                     throws PackageManagerException {
@@ -17921,7 +17572,7 @@
         }
 
         final File codePath = new File(codePathString);
-        final PackageParser.Package pkg =
+        final AndroidPackage pkg =
                 scanPackageTracedLI(codePath, parseFlags, scanFlags, 0 /*currentTime*/, null);
 
         try {
@@ -17935,7 +17586,7 @@
 
         // writer
         synchronized (mLock) {
-            PackageSetting ps = mSettings.mPackages.get(pkg.packageName);
+            PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName());
 
             // Propagate the permissions state as we do not want to drop on the floor
             // runtime permissions. The update permissions method below will take
@@ -17943,7 +17594,7 @@
             if (origPermissionState != null) {
                 ps.getPermissionsState().copyFrom(origPermissionState);
             }
-            mPermissionManager.updatePermissions(pkg.packageName, pkg);
+            mPermissionManager.updatePermissions(pkg.getPackageName(), pkg);
 
             final boolean applyUserRestrictions
                     = (allUserHandles != null) && (origUserHandles != null);
@@ -17981,58 +17632,22 @@
 
     private void deleteInstalledPackageLIF(PackageSetting ps,
             boolean deleteCodeAndResources, int flags, int[] allUserHandles,
-            PackageRemovedInfo outInfo, boolean writeSettings,
-            PackageParser.Package replacingPackage) {
+            PackageRemovedInfo outInfo, boolean writeSettings) {
         synchronized (mLock) {
             if (outInfo != null) {
                 outInfo.uid = ps.appId;
             }
-
-            if (outInfo != null && outInfo.removedChildPackages != null) {
-                final int childCount = (ps.childPackageNames != null)
-                        ? ps.childPackageNames.size() : 0;
-                for (int i = 0; i < childCount; i++) {
-                    String childPackageName = ps.childPackageNames.get(i);
-                    PackageSetting childPs = mSettings.mPackages.get(childPackageName);
-                    PackageRemovedInfo childInfo = outInfo.removedChildPackages.get(
-                            childPackageName);
-                    if (childInfo != null) {
-                        childInfo.uid = childPs.appId;
-                    }
-                }
-            }
         }
 
         // Delete package data from internal structures and also remove data if flag is set
         removePackageDataLIF(ps, allUserHandles, outInfo, flags, writeSettings);
 
-        // Delete the child packages data
-        final int childCount = (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            PackageSetting childPs;
-            synchronized (mLock) {
-                childPs = mSettings.getPackageLPr(ps.childPackageNames.get(i));
-            }
-            if (childPs != null) {
-                PackageRemovedInfo childOutInfo = (outInfo != null
-                        && outInfo.removedChildPackages != null)
-                        ? outInfo.removedChildPackages.get(childPs.name) : null;
-                final int deleteFlags = (flags & DELETE_KEEP_DATA) != 0
-                        && (replacingPackage != null
-                        && !replacingPackage.hasChildPackage(childPs.name))
-                        ? flags & ~DELETE_KEEP_DATA : flags;
-                removePackageDataLIF(childPs, allUserHandles, childOutInfo,
-                        deleteFlags, writeSettings);
-            }
-        }
-
         // Delete application code and resources only for parent packages
-        if (ps.parentPackageName == null) {
-            if (deleteCodeAndResources && (outInfo != null)) {
-                outInfo.args = createInstallArgsForExisting(
-                        ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
-                if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
-            }
+        if (deleteCodeAndResources && (outInfo != null)) {
+            outInfo.args = createInstallArgsForExisting(
+                    ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(
+                            ps.primaryCpuAbiString, ps.secondaryCpuAbiString));
+            if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
         }
     }
 
@@ -18045,10 +17660,10 @@
             // Cannot block uninstall of static shared libs as they are
             // considered a part of the using app (emulating static linking).
             // Also static libs are installed always on internal storage.
-            PackageParser.Package pkg = mPackages.get(packageName);
-            if (pkg != null && pkg.staticSharedLibName != null) {
+            AndroidPackage pkg = mPackages.get(packageName);
+            if (pkg != null && pkg.getStaticSharedLibName() != null) {
                 Slog.w(TAG, "Cannot block uninstall of package: " + packageName
-                        + " providing static shared library: " + pkg.staticSharedLibName);
+                        + " providing static shared library: " + pkg.getStaticSharedLibName());
                 return false;
             }
             mSettings.setBlockUninstallLPw(userId, packageName, blockUninstall);
@@ -18112,40 +17727,22 @@
     @GuardedBy("mLock")
     private static DeletePackageAction mayDeletePackageLocked(
             PackageRemovedInfo outInfo, PackageSetting ps, @Nullable PackageSetting disabledPs,
-            @Nullable PackageSetting[] children, int flags, UserHandle user) {
+            int flags, UserHandle user) {
         if (ps == null) {
             return null;
         }
         if (isSystemApp(ps)) {
-            if (ps.parentPackageName != null) {
-                Slog.w(TAG, "Attempt to delete child system package " + ps.pkg.packageName);
-                return null;
-            }
-
             final boolean deleteSystem = (flags & PackageManager.DELETE_SYSTEM_APP) != 0;
             final boolean deleteAllUsers =
                     user == null || user.getIdentifier() == UserHandle.USER_ALL;
             if ((!deleteSystem || deleteAllUsers) && disabledPs == null) {
-                Slog.w(TAG, "Attempt to delete unknown system package " + ps.pkg.packageName);
+                Slog.w(TAG, "Attempt to delete unknown system package " + ps.pkg.getPackageName());
                 return null;
             }
             // Confirmed if the system package has been updated
             // An updated system app can be deleted. This will also have to restore
             // the system pkg from system partition reader
         }
-        final int parentReferenceCount =
-                (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0;
-        final int childCount = children != null ? children.length : 0;
-        if (childCount != parentReferenceCount) {
-            return null;
-        }
-        if (childCount != 0 && outInfo != null && outInfo.removedChildPackages != null) {
-            for (PackageSetting child : children) {
-                if (child == null || !ps.childPackageNames.contains(child.name)) {
-                    return null;
-                }
-            }
-        }
         return new DeletePackageAction(ps, disabledPs, outInfo, flags, user);
     }
 
@@ -18155,13 +17752,12 @@
     private boolean deletePackageLIF(@NonNull String packageName, UserHandle user,
             boolean deleteCodeAndResources, int[] allUserHandles, int flags,
             PackageRemovedInfo outInfo, boolean writeSettings,
-            PackageParser.Package replacingPackage) {
+            ParsedPackage replacingPackage) {
         final DeletePackageAction action;
         synchronized (mLock) {
             final PackageSetting ps = mSettings.mPackages.get(packageName);
             final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps);
-            PackageSetting[] children = mSettings.getChildSettingsLPr(ps);
-            action = mayDeletePackageLocked(outInfo, ps, disabledPs, children, flags, user);
+            action = mayDeletePackageLocked(outInfo, ps, disabledPs, flags, user);
         }
         if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: " + packageName + " user " + user);
         if (null == action) {
@@ -18192,30 +17788,13 @@
     private void executeDeletePackageLIF(DeletePackageAction action,
             String packageName, boolean deleteCodeAndResources,
             int[] allUserHandles, boolean writeSettings,
-            PackageParser.Package replacingPackage) throws SystemDeleteException {
+            ParsedPackage replacingPackage) throws SystemDeleteException {
         final PackageSetting ps = action.deletingPs;
         final PackageRemovedInfo outInfo = action.outInfo;
         final UserHandle user = action.user;
         final int flags = action.flags;
         final boolean systemApp = isSystemApp(ps);
 
-        if (ps.parentPackageName != null
-                && (!systemApp || (flags & PackageManager.DELETE_SYSTEM_APP) != 0)) {
-            if (DEBUG_REMOVE) {
-                Slog.d(TAG, "Uninstalled child package:" + packageName + " for user:"
-                        + ((user == null) ? UserHandle.USER_ALL : user));
-            }
-            final int removedUserId = (user != null) ? user.getIdentifier()
-                    : UserHandle.USER_ALL;
-
-            clearPackageStateForUserLIF(ps, removedUserId, outInfo, flags);
-            synchronized (mLock) {
-                markPackageUninstalledForUserLPw(ps, user);
-                scheduleWritePackageRestrictionsLocked(user);
-            }
-            return;
-        }
-
         final int userId = user == null ? UserHandle.USER_ALL : user.getIdentifier();
         if (ps.getPermissionsState().hasPermission(Manifest.permission.SUSPEND_APPS, userId)) {
             unsuspendForSuspendingPackage(packageName, userId);
@@ -18265,26 +17844,6 @@
             }
         }
 
-        // If we are deleting a composite package for all users, keep track
-        // of result for each child.
-        if (ps.childPackageNames != null && outInfo != null) {
-            synchronized (mLock) {
-                final int childCount = ps.childPackageNames.size();
-                outInfo.removedChildPackages = new ArrayMap<>(childCount);
-                for (int i = 0; i < childCount; i++) {
-                    String childPackageName = ps.childPackageNames.get(i);
-                    PackageRemovedInfo childInfo = new PackageRemovedInfo(this);
-                    childInfo.removedPackage = childPackageName;
-                    childInfo.installerPackageName = ps.installSource.installerPackageName;
-                    outInfo.removedChildPackages.put(childPackageName, childInfo);
-                    PackageSetting childPs = mSettings.getPackageLPr(childPackageName);
-                    if (childPs != null) {
-                        childInfo.origUsers = childPs.queryInstalledUsers(allUserHandles, true);
-                    }
-                }
-            }
-        }
-
         // TODO(b/109941548): break reasons for ret = false out into mayDelete method
         if (systemApp) {
             if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package: " + ps.name);
@@ -18294,53 +17853,12 @@
         } else {
             if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name);
             deleteInstalledPackageLIF(ps, deleteCodeAndResources, flags, allUserHandles,
-                    outInfo, writeSettings, replacingPackage);
+                    outInfo, writeSettings);
         }
 
         // Take a note whether we deleted the package for all users
         if (outInfo != null) {
             outInfo.removedForAllUsers = mPackages.get(ps.name) == null;
-            if (outInfo.removedChildPackages != null) {
-                synchronized (mLock) {
-                    final int childCount = outInfo.removedChildPackages.size();
-                    for (int i = 0; i < childCount; i++) {
-                        PackageRemovedInfo childInfo = outInfo.removedChildPackages.valueAt(i);
-                        if (childInfo != null) {
-                            childInfo.removedForAllUsers = mPackages.get(
-                                    childInfo.removedPackage) == null;
-                        }
-                    }
-                }
-            }
-            // If we uninstalled an update to a system app there may be some
-            // child packages that appeared as they are declared in the system
-            // app but were not declared in the update.
-            if (systemApp) {
-                synchronized (mLock) {
-                    PackageSetting updatedPs = mSettings.getPackageLPr(ps.name);
-                    final int childCount = (updatedPs.childPackageNames != null)
-                            ? updatedPs.childPackageNames.size() : 0;
-                    for (int i = 0; i < childCount; i++) {
-                        String childPackageName = updatedPs.childPackageNames.get(i);
-                        if (outInfo.removedChildPackages == null
-                                || outInfo.removedChildPackages.indexOfKey(childPackageName) < 0) {
-                            PackageSetting childPs = mSettings.getPackageLPr(childPackageName);
-                            if (childPs == null) {
-                                continue;
-                            }
-                            PackageInstalledInfo installRes = new PackageInstalledInfo();
-                            installRes.name = childPackageName;
-                            installRes.newUsers = childPs.queryInstalledUsers(allUserHandles, true);
-                            installRes.pkg = mPackages.get(childPackageName);
-                            installRes.uid = childPs.pkg.applicationInfo.uid;
-                            if (outInfo.appearedChildPackages == null) {
-                                outInfo.appearedChildPackages = new ArrayMap<>();
-                            }
-                            outInfo.appearedChildPackages.put(childPackageName, installRes);
-                        }
-                    }
-                }
-            }
         }
     }
 
@@ -18374,7 +17892,7 @@
 
     private void clearPackageStateForUserLIF(PackageSetting ps, int userId,
             PackageRemovedInfo outInfo, int flags) {
-        final PackageParser.Package pkg;
+        final AndroidPackage pkg;
         synchronized (mLock) {
             pkg = mPackages.get(ps.name);
         }
@@ -18416,7 +17934,7 @@
         if (outInfo != null) {
             outInfo.removedPackage = ps.name;
             outInfo.installerPackageName = ps.installSource.installerPackageName;
-            outInfo.isStaticSharedLib = pkg != null && pkg.staticSharedLibName != null;
+            outInfo.isStaticSharedLib = pkg != null && pkg.getStaticSharedLibName() != null;
             outInfo.removedAppId = ps.appId;
             outInfo.removedUsers = userIds;
             outInfo.broadcastUsers = userIds;
@@ -18427,7 +17945,7 @@
     public void clearApplicationProfileData(String packageName) {
         enforceSystemOrRoot("Only the system can clear all profile data");
 
-        final PackageParser.Package pkg;
+        final AndroidPackage pkg;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
         }
@@ -18505,7 +18023,7 @@
         }
 
         // Try finding details about the requested package
-        PackageParser.Package pkg;
+        AndroidPackage pkg;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
             if (pkg == null) {
@@ -18524,7 +18042,7 @@
         clearAppDataLIF(pkg, userId,
                 FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
 
-        final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
+        final int appId = UserHandle.getAppId(pkg.getUid());
         removeKeystoreDataIfNeeded(mInjector.getUserManagerInternal(), userId, appId);
 
         UserManagerInternal umInternal = mInjector.getUserManagerInternal();
@@ -18601,14 +18119,14 @@
         final int hasAccessInstantApps = mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.ACCESS_INSTANT_APPS);
 
-        final PackageParser.Package pkg;
+        final AndroidPackage pkg;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
         }
 
         // Queue up an async operation since the package deletion may take a little while.
         mHandler.post(() -> {
-            final PackageSetting ps = pkg == null ? null : (PackageSetting) pkg.mExtras;
+            final PackageSetting ps = pkg == null ? null : getPackageSetting(pkg.getPackageName());
             boolean doClearData = true;
             if (ps != null) {
                 final boolean targetIsInstantApp =
@@ -18688,7 +18206,7 @@
             while (it.hasNext()) {
                 final PackageSetting ps = it.next();
                 if (ps.pkg != null) {
-                    int v = ps.pkg.applicationInfo.targetSdkVersion;
+                    int v = ps.pkg.getTargetSdkVersion();
                     if (v < vers) vers = v;
                 }
             }
@@ -18696,7 +18214,7 @@
         } else if (obj instanceof PackageSetting) {
             final PackageSetting ps = (PackageSetting) obj;
             if (ps.pkg != null) {
-                return ps.pkg.applicationInfo.targetSdkVersion;
+                return ps.pkg.getTargetSdkVersion();
             }
         }
         return Build.VERSION_CODES.CUR_DEVELOPMENT;
@@ -18704,9 +18222,9 @@
 
     @GuardedBy("mLock")
     private int getPackageTargetSdkVersionLockedLPr(String packageName) {
-        final PackageParser.Package p = mPackages.get(packageName);
+        final AndroidPackage p = mPackages.get(packageName);
         if (p != null) {
-            return p.applicationInfo.targetSdkVersion;
+            return p.getTargetSdkVersion();
         }
         return Build.VERSION_CODES.CUR_DEVELOPMENT;
     }
@@ -18875,7 +18393,7 @@
         }
         // writer
         synchronized (mLock) {
-            PackageParser.Package pkg = mPackages.get(packageName);
+            AndroidPackage pkg = mPackages.get(packageName);
             if (pkg == null || !isCallerSameApp(packageName, callingUid)) {
                 if (mContext.checkCallingOrSelfPermission(
                         android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
@@ -18949,8 +18467,8 @@
     private void clearIntentFilterVerificationsLPw(int userId) {
         final int packageCount = mPackages.size();
         for (int i = 0; i < packageCount; i++) {
-            PackageParser.Package pkg = mPackages.valueAt(i);
-            clearIntentFilterVerificationsLPw(pkg.packageName, userId);
+            AndroidPackage pkg = mPackages.valueAt(i);
+            clearIntentFilterVerificationsLPw(pkg.getPackageName(), userId);
         }
     }
 
@@ -19898,8 +19416,8 @@
             // If we're enabling a system stub, there's a little more work to do.
             // Prior to enabling the package, we need to decompress the APK(s) to the
             // data partition and then replace the version on the system partition.
-            final PackageParser.Package deletedPkg = pkgSetting.pkg;
-            final boolean isSystemStub = deletedPkg.isStub
+            final AndroidPackage deletedPkg = pkgSetting.pkg;
+            final boolean isSystemStub = deletedPkg.isStub()
                     && deletedPkg.isSystem();
             if (isSystemStub
                     && (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
@@ -19920,10 +19438,10 @@
             synchronized (mLock) {
                 // We're dealing with a component level state change
                 // First, verify that this is a valid class name.
-                PackageParser.Package pkg = pkgSetting.pkg;
+                AndroidPackage pkg = pkgSetting.pkg;
                 if (pkg == null || !pkg.hasComponentClassName(className)) {
                     if (pkg != null &&
-                            pkg.applicationInfo.targetSdkVersion >=
+                            pkg.getTargetSdkVersion() >=
                                     Build.VERSION_CODES.JELLY_BEAN) {
                         throw new IllegalArgumentException("Component class " + className
                                 + " does not exist in " + packageName);
@@ -20089,19 +19607,95 @@
     public String getInstallerPackageName(String packageName) {
         final int callingUid = Binder.getCallingUid();
         synchronized (mLock) {
-            final PackageSetting ps = mSettings.mPackages.get(packageName);
-            if (shouldFilterApplicationLocked(
-                    ps, callingUid, UserHandle.getUserId(callingUid))) {
-                return null;
+            final InstallSource installSource = getInstallSourceLocked(packageName, callingUid);
+            if (installSource == null) {
+                throw new IllegalArgumentException("Unknown package: " + packageName);
             }
-            // InstallerPackageName for Apex is not stored in PackageManager
-            if (ps == null && mApexManager.isApexPackage(packageName)) {
-                return null;
+            String installerPackageName = installSource.installerPackageName;
+            if (installerPackageName != null) {
+                final PackageSetting ps = mSettings.mPackages.get(installerPackageName);
+                if (ps == null || shouldFilterApplicationLocked(ps, callingUid,
+                        UserHandle.getUserId(callingUid))) {
+                    installerPackageName = null;
+                }
             }
-            return mSettings.getInstallerPackageNameLPr(packageName);
+            return installerPackageName;
         }
     }
 
+    @Override
+    @Nullable
+    public InstallSourceInfo getInstallSourceInfo(String packageName) {
+        final int callingUid = Binder.getCallingUid();
+        final int userId = UserHandle.getUserId(callingUid);
+
+        String installerPackageName;
+        String initiatingPackageName;
+        String originatingPackageName;
+
+        synchronized (mLock) {
+            final InstallSource installSource = getInstallSourceLocked(packageName, callingUid);
+            if (installSource == null) {
+                return null;
+            }
+
+            installerPackageName = installSource.installerPackageName;
+            if (installerPackageName != null) {
+                final PackageSetting ps = mSettings.mPackages.get(installerPackageName);
+                if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
+                    installerPackageName = null;
+                }
+            }
+
+            // All installSource strings are interned, so == is ok here
+            if (installSource.initiatingPackageName == installSource.installerPackageName) {
+                // The installer and initiator will often be the same, and when they are
+                // we can skip doing the same check again.
+                initiatingPackageName = installerPackageName;
+            } else {
+                initiatingPackageName = installSource.initiatingPackageName;
+                final PackageSetting ps = mSettings.mPackages.get(initiatingPackageName);
+                if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
+                    initiatingPackageName = null;
+                }
+
+            }
+            originatingPackageName = installSource.originatingPackageName;
+            if (originatingPackageName != null) {
+                final PackageSetting ps = mSettings.mPackages.get(originatingPackageName);
+                if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
+                    originatingPackageName = null;
+                }
+            }
+        }
+
+        if (originatingPackageName != null && mContext.checkCallingOrSelfPermission(
+                Manifest.permission.INSTALL_PACKAGES) != PackageManager.PERMISSION_GRANTED) {
+            originatingPackageName = null;
+        }
+
+        return new InstallSourceInfo(initiatingPackageName, originatingPackageName,
+                installerPackageName);
+    }
+
+    @GuardedBy("mLock")
+    @Nullable
+    private InstallSource getInstallSourceLocked(String packageName, int callingUid) {
+        final PackageSetting ps = mSettings.mPackages.get(packageName);
+
+        // Installer info for Apex is not stored in PackageManager
+        if (ps == null && mApexManager.isApexPackage(packageName)) {
+            return InstallSource.EMPTY;
+        }
+
+        if (ps == null || shouldFilterApplicationLocked(ps, callingUid,
+                UserHandle.getUserId(callingUid))) {
+            return null;
+        }
+
+        return ps.installSource;
+    }
+
     public boolean isOrphaned(String packageName) {
         // reader
         synchronized (mLock) {
@@ -20255,7 +19849,7 @@
         storage.registerListener(mStorageListener);
 
         mInstallerService.systemReady();
-        mApexManager.systemReady();
+        mApexManager.systemReady(mContext);
         mPackageDexOptimizer.systemReady();
 
         mInjector.getStorageManagerInternal().addExternalStoragePolicy(
@@ -20312,14 +19906,14 @@
                 if (packageName == null) {
                     return;
                 }
-                PackageParser.Package pkg = mPackages.get(packageName);
+                AndroidPackage pkg = mPackages.get(packageName);
                 if (pkg == null) {
                     return;
                 }
-                sendPackageChangedBroadcast(pkg.packageName,
+                sendPackageChangedBroadcast(pkg.getPackageName(),
                         true /* dontKillApp */,
-                        new ArrayList<>(Collections.singletonList(pkg.packageName)),
-                        pkg.applicationInfo.uid,
+                        new ArrayList<>(Collections.singletonList(pkg.getPackageName())),
+                        pkg.getUid(),
                         Intent.ACTION_OVERLAY_CHANGED);
             }
         }, overlayFilter);
@@ -20908,7 +20502,7 @@
 
             if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS)
                     && packageName == null) {
-                mComponentResolver.dumpServicePermissions(pw, dumpState, packageName);
+                mComponentResolver.dumpServicePermissions(pw, dumpState);
             }
 
             if (!checkin && dumpState.isDumping(DumpState.DUMP_DEXOPT)) {
@@ -21011,7 +20605,7 @@
         synchronized (mAvailableFeatures) {
             final int count = mAvailableFeatures.size();
             for (int i = 0; i < count; i++) {
-                mAvailableFeatures.valueAt(i).writeToProto(proto, PackageServiceDumpProto.FEATURES);
+                mAvailableFeatures.valueAt(i).dumpDebug(proto, PackageServiceDumpProto.FEATURES);
             }
         }
     }
@@ -21051,9 +20645,9 @@
         ipw.println();
         ipw.println("Dexopt state:");
         ipw.increaseIndent();
-        Collection<PackageParser.Package> packages;
+        Collection<AndroidPackage> packages;
         if (packageName != null) {
-            PackageParser.Package targetPackage = mPackages.get(packageName);
+            AndroidPackage targetPackage = mPackages.get(packageName);
             if (targetPackage != null) {
                 packages = Collections.singletonList(targetPackage);
             } else {
@@ -21064,11 +20658,11 @@
             packages = mPackages.values();
         }
 
-        for (PackageParser.Package pkg : packages) {
-            ipw.println("[" + pkg.packageName + "]");
+        for (AndroidPackage pkg : packages) {
+            ipw.println("[" + pkg.getPackageName() + "]");
             ipw.increaseIndent();
             mPackageDexOptimizer.dumpDexoptState(ipw, pkg,
-                    mDexManager.getPackageUseInfoOrDefault(pkg.packageName));
+                    mDexManager.getPackageUseInfoOrDefault(pkg.getPackageName()));
             ipw.decreaseIndent();
         }
     }
@@ -21080,9 +20674,9 @@
         ipw.println();
         ipw.println("Compiler stats:");
         ipw.increaseIndent();
-        Collection<PackageParser.Package> packages;
+        Collection<AndroidPackage> packages;
         if (packageName != null) {
-            PackageParser.Package targetPackage = mPackages.get(packageName);
+            AndroidPackage targetPackage = mPackages.get(packageName);
             if (targetPackage != null) {
                 packages = Collections.singletonList(targetPackage);
             } else {
@@ -21093,11 +20687,11 @@
             packages = mPackages.values();
         }
 
-        for (PackageParser.Package pkg : packages) {
-            ipw.println("[" + pkg.packageName + "]");
+        for (AndroidPackage pkg : packages) {
+            ipw.println("[" + pkg.getPackageName() + "]");
             ipw.increaseIndent();
 
-            CompilerStats.PackageStats stats = getCompilerPackageStats(pkg.packageName);
+            CompilerStats.PackageStats stats = getCompilerPackageStats(pkg.getPackageName());
             if (stats == null) {
                 ipw.println("(No recorded stats)");
             } else {
@@ -21168,14 +20762,14 @@
     }
 
     private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
-            ArrayList<ApplicationInfo> infos, IIntentReceiver finishedReceiver) {
-        final int size = infos.size();
+            ArrayList<AndroidPackage> packages, IIntentReceiver finishedReceiver) {
+        final int size = packages.size();
         final String[] packageNames = new String[size];
         final int[] packageUids = new int[size];
         for (int i = 0; i < size; i++) {
-            final ApplicationInfo info = infos.get(i);
-            packageNames[i] = info.packageName;
-            packageUids[i] = info.uid;
+            final AndroidPackage pkg = packages.get(i);
+            packageNames[i] = pkg.getAppInfoPackageName();
+            packageUids[i] = pkg.getUid();
         }
         sendResourcesChangedBroadcast(mediaStatus, replacing, packageNames, packageUids,
                 finishedReceiver);
@@ -21218,7 +20812,7 @@
         }
 
         final ArrayList<PackageFreezer> freezers = new ArrayList<>();
-        final ArrayList<ApplicationInfo> loaded = new ArrayList<>();
+        final ArrayList<AndroidPackage> loaded = new ArrayList<>();
         final int parseFlags = mDefParseFlags | PackageParser.PARSE_EXTERNAL_STORAGE;
 
         final VersionInfo ver;
@@ -21231,10 +20825,10 @@
         for (PackageSetting ps : packages) {
             freezers.add(freezePackage(ps.name, "loadPrivatePackagesInner"));
             synchronized (mInstallLock) {
-                final PackageParser.Package pkg;
+                final AndroidPackage pkg;
                 try {
                     pkg = scanPackageTracedLI(ps.codePath, parseFlags, SCAN_INITIAL, 0, null);
-                    loaded.add(pkg.applicationInfo);
+                    loaded.add(pkg);
 
                 } catch (PackageManagerException e) {
                     Slog.w(TAG, "Failed to scan " + ps.codePath + ": " + e.getMessage());
@@ -21306,14 +20900,14 @@
             return;
         }
 
-        final ArrayList<ApplicationInfo> unloaded = new ArrayList<>();
+        final ArrayList<AndroidPackage> unloaded = new ArrayList<>();
         synchronized (mInstallLock) {
         synchronized (mLock) {
             final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(volumeUuid);
             for (PackageSetting ps : packages) {
                 if (ps.pkg == null) continue;
 
-                final ApplicationInfo info = ps.pkg.applicationInfo;
+                final AndroidPackage pkg = ps.pkg;
                 final int deleteFlags = PackageManager.DELETE_KEEP_DATA;
                 final PackageRemovedInfo outInfo = new PackageRemovedInfo(this);
 
@@ -21321,7 +20915,7 @@
                         "unloadPrivatePackagesInner")) {
                     if (deletePackageLIF(ps.name, null, false, null, deleteFlags, outInfo,
                             false, null)) {
-                        unloaded.add(info);
+                        unloaded.add(pkg);
                     } else {
                         Slog.w(TAG, "Failed to unload " + ps.codePath);
                     }
@@ -21536,7 +21130,7 @@
                 continue;
             }
             // Skip non-core apps if requested
-            if (onlyCoreApps && !ps.pkg.coreApp) {
+            if (onlyCoreApps && !ps.pkg.isCoreApp()) {
                 result.add(packageName);
                 continue;
             }
@@ -21563,10 +21157,10 @@
      * <p>
      * <em>Note: To avoid a deadlock, do not call this method with {@code mLock} lock held</em>
      */
-    private void prepareAppDataAfterInstallLIF(PackageParser.Package pkg) {
+    private void prepareAppDataAfterInstallLIF(AndroidPackage pkg) {
         final PackageSetting ps;
         synchronized (mLock) {
-            ps = mSettings.mPackages.get(pkg.packageName);
+            ps = mSettings.mPackages.get(pkg.getPackageName());
             mSettings.writeKernelMappingLPr(ps);
         }
 
@@ -21596,19 +21190,15 @@
      * will try recovering system apps by wiping data; third-party app data is
      * left intact.
      */
-    private void prepareAppDataLIF(PackageParser.Package pkg, int userId, int flags) {
+    private void prepareAppDataLIF(AndroidPackage pkg, int userId, int flags) {
         if (pkg == null) {
             Slog.wtf(TAG, "Package was null!", new Throwable());
             return;
         }
         prepareAppDataLeafLIF(pkg, userId, flags);
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            prepareAppDataLeafLIF(pkg.childPackages.get(i), userId, flags);
-        }
     }
 
-    private void prepareAppDataAndMigrateLIF(PackageParser.Package pkg, int userId, int flags,
+    private void prepareAppDataAndMigrateLIF(AndroidPackage pkg, int userId, int flags,
             boolean maybeMigrateAppData) {
         prepareAppDataLIF(pkg, userId, flags);
 
@@ -21619,43 +21209,37 @@
         }
     }
 
-    private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
+    private void prepareAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
         if (DEBUG_APP_DATA) {
-            Slog.v(TAG, "prepareAppData for " + pkg.packageName + " u" + userId + " 0x"
+            Slog.v(TAG, "prepareAppData for " + pkg.getPackageName() + " u" + userId + " 0x"
                     + Integer.toHexString(flags));
         }
 
         final PackageSetting ps;
         synchronized (mLock) {
-            ps = mSettings.mPackages.get(pkg.packageName);
+            ps = mSettings.mPackages.get(pkg.getPackageName());
         }
-        final String volumeUuid = pkg.volumeUuid;
-        final String packageName = pkg.packageName;
+        final String volumeUuid = pkg.getVolumeUuid();
+        final String packageName = pkg.getPackageName();
 
-        ApplicationInfo app = (ps == null)
-                ? pkg.applicationInfo
-                : PackageParser.generateApplicationInfo(pkg, 0, ps.readUserState(userId), userId);
-        if (app == null) {
-            app = pkg.applicationInfo;
-        }
+        final int appId = UserHandle.getAppId(pkg.getUid());
 
-        final int appId = UserHandle.getAppId(app.uid);
+        Preconditions.checkNotNull(pkg.getSeInfo());
 
-        Preconditions.checkNotNull(app.seInfo);
-
-        final String seInfo = app.seInfo + (app.seInfoUser != null ? app.seInfoUser : "");
+        final String seInfo =
+                pkg.getSeInfo() + (pkg.getSeInfoUser() != null ? pkg.getSeInfoUser() : "");
         long ceDataInode = -1;
         try {
             ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
-                    appId, seInfo, app.targetSdkVersion);
+                    appId, seInfo, pkg.getTargetSdkVersion());
         } catch (InstallerException e) {
-            if (app.isSystemApp()) {
+            if (pkg.isSystemApp()) {
                 logCriticalInfo(Log.ERROR, "Failed to create app data for " + packageName
                         + ", but trying to recover: " + e);
                 destroyAppDataLeafLIF(pkg, userId, flags);
                 try {
                     ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
-                            appId, seInfo, app.targetSdkVersion);
+                            appId, seInfo, pkg.getTargetSdkVersion());
                     logCriticalInfo(Log.DEBUG, "Recovery succeeded!");
                 } catch (InstallerException e2) {
                     logCriticalInfo(Log.DEBUG, "Recovery failed!");
@@ -21697,29 +21281,24 @@
         prepareAppDataContentsLeafLIF(pkg, userId, flags);
     }
 
-    private void prepareAppDataContentsLIF(PackageParser.Package pkg, int userId, int flags) {
+    private void prepareAppDataContentsLIF(AndroidPackage pkg, int userId, int flags) {
         if (pkg == null) {
             Slog.wtf(TAG, "Package was null!", new Throwable());
             return;
         }
         prepareAppDataContentsLeafLIF(pkg, userId, flags);
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            prepareAppDataContentsLeafLIF(pkg.childPackages.get(i), userId, flags);
-        }
     }
 
-    private void prepareAppDataContentsLeafLIF(PackageParser.Package pkg, int userId, int flags) {
-        final String volumeUuid = pkg.volumeUuid;
-        final String packageName = pkg.packageName;
-        final ApplicationInfo app = pkg.applicationInfo;
+    private void prepareAppDataContentsLeafLIF(AndroidPackage pkg, int userId, int flags) {
+        final String volumeUuid = pkg.getVolumeUuid();
+        final String packageName = pkg.getPackageName();
 
         if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
             // Create a native library symlink only if we have native libraries
             // and if the native libraries are 32 bit libraries. We do not provide
             // this symlink for 64 bit libraries.
-            if (app.primaryCpuAbi != null && !VMRuntime.is64BitAbi(app.primaryCpuAbi)) {
-                final String nativeLibPath = app.nativeLibraryDir;
+            if (pkg.getPrimaryCpuAbi() != null && !VMRuntime.is64BitAbi(pkg.getPrimaryCpuAbi())) {
+                final String nativeLibPath = pkg.getNativeLibraryDir();
                 try {
                     mInstaller.linkNativeLibraryDirectory(volumeUuid, packageName,
                             nativeLibPath, userId);
@@ -21735,17 +21314,17 @@
      * CE/DE data to match the {@code defaultToDeviceProtectedStorage} flag
      * requested by the app.
      */
-    private boolean maybeMigrateAppDataLIF(PackageParser.Package pkg, int userId) {
+    private boolean maybeMigrateAppDataLIF(AndroidPackage pkg, int userId) {
         if (pkg.isSystem() && !StorageManager.isFileEncryptedNativeOrEmulated()
                 && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
-            final int storageTarget = pkg.applicationInfo.isDefaultToDeviceProtectedStorage()
+            final int storageTarget = pkg.isDefaultToDeviceProtectedStorage()
                     ? StorageManager.FLAG_STORAGE_DE : StorageManager.FLAG_STORAGE_CE;
             try {
-                mInstaller.migrateAppData(pkg.volumeUuid, pkg.packageName, userId,
+                mInstaller.migrateAppData(pkg.getVolumeUuid(), pkg.getPackageName(), userId,
                         storageTarget);
             } catch (InstallerException e) {
                 logCriticalInfo(Log.WARN,
-                        "Failed to migrate " + pkg.packageName + ": " + e.getMessage());
+                        "Failed to migrate " + pkg.getPackageName() + ": " + e.getMessage());
             }
             return true;
         } else {
@@ -21796,7 +21375,6 @@
      */
     private class PackageFreezer implements AutoCloseable {
         private final String mPackageName;
-        private final PackageFreezer[] mChildren;
 
         private final boolean mWeFroze;
 
@@ -21811,7 +21389,6 @@
          */
         public PackageFreezer() {
             mPackageName = null;
-            mChildren = null;
             mWeFroze = false;
             mCloseGuard.open("close");
         }
@@ -21825,18 +21402,6 @@
                 if (ps != null) {
                     killApplication(ps.name, ps.appId, userId, killReason);
                 }
-
-                final PackageParser.Package p = mPackages.get(packageName);
-                if (p != null && p.childPackages != null) {
-                    final int N = p.childPackages.size();
-                    mChildren = new PackageFreezer[N];
-                    for (int i = 0; i < N; i++) {
-                        mChildren[i] = new PackageFreezer(p.childPackages.get(i).packageName,
-                                userId, killReason);
-                    }
-                } else {
-                    mChildren = null;
-                }
             }
             mCloseGuard.open("close");
         }
@@ -21859,12 +21424,6 @@
                     if (mWeFroze) {
                         mFrozenPackages.remove(mPackageName);
                     }
-
-                    if (mChildren != null) {
-                        for (PackageFreezer freezer : mChildren) {
-                            freezer.close();
-                        }
-                    }
                 }
             }
         }
@@ -21919,14 +21478,14 @@
 
         // reader
         synchronized (mLock) {
-            final PackageParser.Package pkg = mPackages.get(packageName);
+            final AndroidPackage pkg = mPackages.get(packageName);
             final PackageSetting ps = mSettings.mPackages.get(packageName);
             if (pkg == null
                     || ps == null
                     || shouldFilterApplicationLocked(ps, callingUid, user.getIdentifier())) {
                 throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package");
             }
-            if (pkg.applicationInfo.isSystemApp()) {
+            if (pkg.isSystemApp()) {
                 throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE,
                         "Cannot move system application");
             }
@@ -21941,7 +21500,7 @@
 
             currentVolumeUuid = ps.volumeUuid;
 
-            final File probe = new File(pkg.codePath);
+            final File probe = new File(pkg.getCodePath());
             final File probeOat = new File(probe, "oat");
             if (!probe.isDirectory() || !probeOat.isDirectory()) {
                 throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
@@ -21952,7 +21511,7 @@
                 throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
                         "Package already moved to " + volumeUuid);
             }
-            if (pkg.applicationInfo.isInternal() && isPackageDeviceAdminOnAnyUser(packageName)) {
+            if (pkg.isInternal() && isPackageDeviceAdminOnAnyUser(packageName)) {
                 throw new PackageManagerException(MOVE_FAILED_DEVICE_ADMIN,
                         "Device admin cannot be moved");
             }
@@ -21963,13 +21522,13 @@
             }
 
             isCurrentLocationExternal = isExternal(pkg);
-            codeFile = new File(pkg.codePath);
+            codeFile = new File(pkg.getCodePath());
             installSource = ps.installSource;
             packageAbiOverride = ps.cpuAbiOverrideString;
-            appId = UserHandle.getAppId(pkg.applicationInfo.uid);
-            seinfo = pkg.applicationInfo.seInfo;
-            label = String.valueOf(pm.getApplicationLabel(pkg.applicationInfo));
-            targetSdkVersion = pkg.applicationInfo.targetSdkVersion;
+            appId = UserHandle.getAppId(pkg.getUid());
+            seinfo = pkg.getSeInfo();
+            label = String.valueOf(pm.getApplicationLabel(pkg.toAppInfoWithoutState()));
+            targetSdkVersion = pkg.getTargetSdkVersion();
             freezer = freezePackage(packageName, "movePackageInternal");
             installedUserIds = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
         }
@@ -22130,7 +21689,7 @@
      * @param packageName The package that was moved.
      */
     private void logAppMovedStorage(String packageName, boolean isPreviousLocationExternal) {
-        final PackageParser.Package pkg;
+        final AndroidPackage pkg;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
         }
@@ -22138,8 +21697,8 @@
             return;
         }
 
-        final StorageManager storage = mInjector.getStorageManager();
-        VolumeInfo volume = storage.findVolumeByUuid(pkg.applicationInfo.storageUuid.toString());
+        final StorageManager storage = mInjector.getStorageManager();;
+        VolumeInfo volume = storage.findVolumeByUuid(pkg.getStorageUuid().toString());
         int packageExternalStorageType = getPackageExternalStorageType(volume, isExternal(pkg));
 
         if (!isPreviousLocationExternal && isExternal(pkg)) {
@@ -22253,10 +21812,10 @@
             if (ps.pkg == null) {
                 continue;
             }
-            final String packageName = ps.pkg.packageName;
+            final String packageName = ps.pkg.getPackageName();
             // Skip over if system app or static shared library
             if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0
-                    || !TextUtils.isEmpty(ps.pkg.staticSharedLibName)) {
+                    || !TextUtils.isEmpty(ps.pkg.getStaticSharedLibName())) {
                 continue;
             }
             if (DEBUG_CLEAN_APKS) {
@@ -22383,13 +21942,13 @@
         if (packageName == null || alias == null) {
             return null;
         }
-        synchronized (mLock) {
-            final PackageParser.Package pkg = mPackages.get(packageName);
+        synchronized(mLock) {
+            final AndroidPackage pkg = mPackages.get(packageName);
             if (pkg == null) {
                 Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
                 throw new IllegalArgumentException("Unknown package: " + packageName);
             }
-            final PackageSetting ps = (PackageSetting) pkg.mExtras;
+            final PackageSetting ps = getPackageSetting(pkg.getPackageName());
             if (shouldFilterApplicationLocked(
                     ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) {
                 Slog.w(TAG, "KeySet requested for filtered package: " + packageName);
@@ -22408,19 +21967,19 @@
         synchronized (mLock) {
             final int callingUid = Binder.getCallingUid();
             final int callingUserId = UserHandle.getUserId(callingUid);
-            final PackageParser.Package pkg = mPackages.get(packageName);
+            final AndroidPackage pkg = mPackages.get(packageName);
             if (pkg == null) {
                 Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
                 throw new IllegalArgumentException("Unknown package: " + packageName);
             }
-            final PackageSetting ps = (PackageSetting) pkg.mExtras;
+            final PackageSetting ps = getPackageSetting(pkg.getPackageName());
             if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
                 // filter and pretend the package doesn't exist
                 Slog.w(TAG, "KeySet requested for filtered package: " + packageName
                         + ", uid:" + callingUid);
                 throw new IllegalArgumentException("Unknown package: " + packageName);
             }
-            if (pkg.applicationInfo.uid != callingUid
+            if (pkg.getUid() != callingUid
                     && Process.SYSTEM_UID != callingUid) {
                 throw new SecurityException("May not access signing KeySet of other apps.");
             }
@@ -22438,11 +21997,11 @@
         if (packageName == null || ks == null) {
             return false;
         }
-        synchronized (mLock) {
-            final PackageParser.Package pkg = mPackages.get(packageName);
+        synchronized(mLock) {
+            final AndroidPackage pkg = mPackages.get(packageName);
             if (pkg == null
-                    || shouldFilterApplicationLocked((PackageSetting) pkg.mExtras, callingUid,
-                            UserHandle.getUserId(callingUid))) {
+                    || shouldFilterApplicationLocked(getPackageSetting(pkg.getPackageName()),
+                    callingUid, UserHandle.getUserId(callingUid))) {
                 Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
                 throw new IllegalArgumentException("Unknown package: " + packageName);
             }
@@ -22465,10 +22024,10 @@
             return false;
         }
         synchronized (mLock) {
-            final PackageParser.Package pkg = mPackages.get(packageName);
+            final AndroidPackage pkg = mPackages.get(packageName);
             if (pkg == null
-                    || shouldFilterApplicationLocked((PackageSetting) pkg.mExtras, callingUid,
-                            UserHandle.getUserId(callingUid))) {
+                    || shouldFilterApplicationLocked(getPackageSetting(pkg.getPackageName()),
+                    callingUid, UserHandle.getUserId(callingUid))) {
                 Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
                 throw new IllegalArgumentException("Unknown package: " + packageName);
             }
@@ -22500,29 +22059,29 @@
      * Check and throw if the given before/after packages would be considered a
      * downgrade.
      */
-    private static void checkDowngrade(PackageParser.Package before, PackageInfoLite after)
+    private static void checkDowngrade(AndroidPackage before, PackageInfoLite after)
             throws PackageManagerException {
         if (after.getLongVersionCode() < before.getLongVersionCode()) {
             throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
                     "Update version code " + after.versionCode + " is older than current "
                     + before.getLongVersionCode());
         } else if (after.getLongVersionCode() == before.getLongVersionCode()) {
-            if (after.baseRevisionCode < before.baseRevisionCode) {
+            if (after.baseRevisionCode < before.getBaseRevisionCode()) {
                 throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
                         "Update base revision code " + after.baseRevisionCode
-                        + " is older than current " + before.baseRevisionCode);
+                        + " is older than current " + before.getBaseRevisionCode());
             }
 
             if (!ArrayUtils.isEmpty(after.splitNames)) {
                 for (int i = 0; i < after.splitNames.length; i++) {
                     final String splitName = after.splitNames[i];
-                    final int j = ArrayUtils.indexOf(before.splitNames, splitName);
+                    final int j = ArrayUtils.indexOf(before.getSplitNames(), splitName);
                     if (j != -1) {
-                        if (after.splitRevisionCodes[i] < before.splitRevisionCodes[j]) {
+                        if (after.splitRevisionCodes[i] < before.getSplitRevisionCodes()[j]) {
                             throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
                                     "Update split " + splitName + " revision code "
                                     + after.splitRevisionCodes[i] + " is older than current "
-                                    + before.splitRevisionCodes[j]);
+                                    + before.getSplitRevisionCodes()[j]);
                         }
                     }
                 }
@@ -22712,13 +22271,13 @@
             if (packageSetting == null) {
                 return false;
             }
-            PackageParser.Package pkg = packageSetting.pkg;
+            AndroidPackage pkg = packageSetting.pkg;
             if (pkg == null) {
                 // May happen if package in on a removable sd card
                 return false;
             }
-            return pkg.mSigningDetails.hasAncestorOrSelf(mPlatformPackage.mSigningDetails)
-                    || mPlatformPackage.mSigningDetails.checkCapability(pkg.mSigningDetails,
+            return pkg.getSigningDetails().hasAncestorOrSelf(mPlatformPackage.getSigningDetails())
+                    || mPlatformPackage.getSigningDetails().checkCapability(pkg.getSigningDetails(),
                     PackageParser.SigningDetails.CertCapabilities.PERMISSION);
         }
 
@@ -22754,11 +22313,11 @@
 
         private SigningDetails getSigningDetails(@NonNull String packageName) {
             synchronized (mLock) {
-                PackageParser.Package p = mPackages.get(packageName);
+                AndroidPackage p = mPackages.get(packageName);
                 if (p == null) {
                     return null;
                 }
-                return p.mSigningDetails;
+                return p.getSigningDetails();
             }
         }
 
@@ -22789,28 +22348,25 @@
         }
 
         @Override
-        public boolean filterAppAccess(PackageParser.Package pkg, int callingUid, int userId) {
+        public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
             synchronized (mLock) {
-                return PackageManagerService.this.shouldFilterApplicationLocked(
-                        (PackageSetting) pkg.mExtras, callingUid, userId);
+                PackageSetting ps = getPackageSetting(pkg.getPackageName());
+                return PackageManagerService.this.shouldFilterApplicationLocked(ps, callingUid,
+                        userId);
             }
         }
 
         @Override
         public boolean filterAppAccess(String packageName, int callingUid, int userId) {
             synchronized (mLock) {
-                final PackageParser.Package pkg = mPackages.get(packageName);
-                if (pkg == null) {
-                    return false;
-                }
-                return PackageManagerService.this
-                        .shouldFilterApplicationLocked(
-                                (PackageSetting) pkg.mExtras, callingUid, userId);
+                PackageSetting ps = getPackageSetting(packageName);
+                return PackageManagerService.this.shouldFilterApplicationLocked(ps, callingUid,
+                        userId);
             }
         }
 
         @Override
-        public PackageParser.Package getPackage(String packageName) {
+        public AndroidPackage getPackage(String packageName) {
             synchronized (mLock) {
                 packageName = resolveInternalPackageNameLPr(
                         packageName, PackageManager.VERSION_CODE_HIGHEST);
@@ -22819,10 +22375,10 @@
         }
 
         @Override
-        public PackageParser.Package getPackage(int uid) {
+        public AndroidPackage getPackage(int uid) {
             synchronized (mLock) {
                 final String[] packageNames = getPackagesForUid(uid);
-                PackageParser.Package pkg = null;
+                AndroidPackage pkg = null;
                 final int numPackages = packageNames == null ? 0 : packageNames.length;
                 for (int i = 0; pkg == null && i < numPackages; i++) {
                     pkg = mPackages.get(packageNames[i]);
@@ -22831,6 +22387,12 @@
             }
         }
 
+        @Nullable
+        @Override
+        public PackageSetting getPackageSetting(String packageName) {
+            return PackageManagerService.this.getPackageSetting(packageName);
+        }
+
         @Override
         public PackageList getPackageList(PackageListObserver observer) {
             synchronized (mLock) {
@@ -22855,17 +22417,19 @@
         }
 
         @Override
-        public PackageParser.Package getDisabledSystemPackage(String packageName) {
+        public Object getDisabledSystemPackage(@NonNull String packageName) {
             synchronized (mLock) {
-                final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
-                return (ps != null) ? ps.pkg : null;
+                return mSettings.getDisabledSystemPkgLPr(packageName);
             }
         }
 
         @Override
-        public @Nullable String getDisabledSystemPackageName(@NonNull String packageName) {
-            PackageParser.Package pkg = getDisabledSystemPackage(packageName);
-            return pkg == null ? null : pkg.packageName;
+        public @Nullable
+        String getDisabledSystemPackageName(@NonNull String packageName) {
+            PackageSetting disabledPkgSetting = (PackageSetting) getDisabledSystemPackage(
+                    packageName);
+            AndroidPackage disabledPkg = disabledPkgSetting == null ? null : disabledPkgSetting.pkg;
+            return disabledPkg == null ? null : disabledPkg.getPackageName();
         }
 
         /**
@@ -22889,7 +22453,7 @@
                         continue;
                     }
 
-                    PackageParser.Package pkg = getPackage(pkgName);
+                    AndroidPackage pkg = getPackage(pkgName);
                     if (pkg == null) {
                         Log.w(TAG, "Could not find package " + pkgName);
                         continue;
@@ -22978,7 +22542,7 @@
         @Override
         public boolean isPermissionsReviewRequired(String packageName, int userId) {
             synchronized (mLock) {
-                final PackageParser.Package pkg = mPackages.get(packageName);
+                final AndroidPackage pkg = mPackages.get(packageName);
                 if (pkg == null) {
                     return false;
                 }
@@ -23164,9 +22728,10 @@
         }
 
         @Override
-        public boolean isEnabledAndMatches(ComponentInfo info, int flags, int userId) {
+        public boolean isEnabledAndMatches(ParsedComponent component, int flags, int userId) {
             synchronized (mLock) {
-                return mSettings.isEnabledAndMatchLPr(info, flags, userId);
+                AndroidPackage pkg = getPackage(component.getPackageName());
+                return mSettings.isEnabledAndMatchLPr(pkg, component, flags, userId);
             }
         }
 
@@ -23183,10 +22748,10 @@
         }
 
         @Override
-        public boolean setInstalled(PackageParser.Package pkg, @UserIdInt int userId,
+        public boolean setInstalled(AndroidPackage pkg, @UserIdInt int userId,
                 boolean installed) {
             synchronized (mLock) {
-                final PackageSetting ps = mSettings.mPackages.get(pkg.packageName);
+                final PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName());
                 if (ps.getInstalled(userId) != installed) {
                     ps.setInstalled(installed, userId);
                     return true;
@@ -23208,16 +22773,15 @@
         public void grantImplicitAccess(int userId, Intent intent,
                 int callingUid, int targetAppId) {
             synchronized (mLock) {
-                final PackageParser.Package callingPackage = getPackage(callingUid);
+                final AndroidPackage callingPackage = getPackage(callingUid);
                 final int targetUid = UserHandle.getUid(userId, targetAppId);
-                final PackageParser.Package targetPackage =
-                        getPackage(targetUid);
+                final AndroidPackage targetPackage = getPackage(targetUid);
                 if (callingPackage == null || targetPackage == null) {
                     return;
                 }
 
-                final boolean instantApp = isInstantAppInternal(callingPackage.packageName, userId,
-                        callingUid);
+                final boolean instantApp = isInstantAppInternal(callingPackage.getPackageName(),
+                        userId, callingUid);
                 if (instantApp) {
                     mInstantAppRegistry.grantInstantAccessLPw(userId, intent,
                             UserHandle.getAppId(callingUid), targetAppId);
@@ -23254,9 +22818,9 @@
         @Override
         public boolean isPackagePersistent(String packageName) {
             synchronized (mLock) {
-                PackageParser.Package pkg = mPackages.get(packageName);
+                AndroidPackage pkg = mPackages.get(packageName);
                 return pkg != null
-                        ? ((pkg.applicationInfo.flags&(ApplicationInfo.FLAG_SYSTEM
+                        ? ((pkg.getFlags() & (ApplicationInfo.FLAG_SYSTEM
                                         | ApplicationInfo.FLAG_PERSISTENT)) ==
                                 (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PERSISTENT))
                         : false;
@@ -23264,9 +22828,9 @@
         }
 
         @Override
-        public boolean isLegacySystemApp(PackageParser.Package pkg) {
+        public boolean isLegacySystemApp(AndroidPackage pkg) {
             synchronized (mLock) {
-                final PackageSetting ps = (PackageSetting) pkg.mExtras;
+                final PackageSetting ps = getPackageSetting(pkg.getPackageName());
                 return mPromoteSystemApps
                         && ps.isSystem()
                         && mExistingSystemPackages.contains(ps.name);
@@ -23277,9 +22841,10 @@
         public List<PackageInfo> getOverlayPackages(int userId) {
             final ArrayList<PackageInfo> overlayPackages = new ArrayList<PackageInfo>();
             synchronized (mLock) {
-                for (PackageParser.Package p : mPackages.values()) {
-                    if (p.mOverlayTarget != null) {
-                        PackageInfo pkg = generatePackageInfo((PackageSetting)p.mExtras, 0, userId);
+                for (AndroidPackage p : mPackages.values()) {
+                    if (p.getOverlayTarget() != null) {
+                        PackageInfo pkg = generatePackageInfo(getPackageSetting(p.getPackageName()),
+                                0, userId);
                         if (pkg != null) {
                             overlayPackages.add(pkg);
                         }
@@ -23293,9 +22858,9 @@
         public List<String> getTargetPackageNames(int userId) {
             List<String> targetPackages = new ArrayList<>();
             synchronized (mLock) {
-                for (PackageParser.Package p : mPackages.values()) {
-                    if (p.mOverlayTarget == null) {
-                        targetPackages.add(p.packageName);
+                for (AndroidPackage p : mPackages.values()) {
+                    if (p.getOverlayTarget() == null) {
+                        targetPackages.add(p.getPackageName());
                     }
                 }
             }
@@ -23316,12 +22881,12 @@
                     overlayPaths = new ArrayList<>(N);
                     for (int i = 0; i < N; i++) {
                         final String packageName = overlayPackageNames.get(i);
-                        final PackageParser.Package pkg = mPackages.get(packageName);
+                        final AndroidPackage pkg = mPackages.get(packageName);
                         if (pkg == null) {
                             Slog.e(TAG, "failed to find package " + packageName);
                             return false;
                         }
-                        overlayPaths.add(pkg.baseCodePath);
+                        overlayPaths.add(pkg.getBaseCodePath());
                     }
                 }
 
@@ -23439,12 +23004,12 @@
         }
 
         @Override
-        public void forEachPackage(Consumer<PackageParser.Package> actionLocked) {
+        public void forEachPackage(Consumer<AndroidPackage> actionLocked) {
             PackageManagerService.this.forEachPackage(actionLocked);
         }
 
         @Override
-        public void forEachInstalledPackage(@NonNull Consumer<PackageParser.Package> actionLocked,
+        public void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> actionLocked,
                 @UserIdInt int userId) {
             PackageManagerService.this.forEachInstalledPackage(actionLocked, userId);
         }
@@ -23493,7 +23058,7 @@
          */
         @Override
         public boolean compileLayouts(String packageName) {
-            PackageParser.Package pkg;
+            AndroidPackage pkg;
             synchronized (mLock) {
                 pkg = mPackages.get(packageName);
                 if (pkg == null) {
@@ -23523,7 +23088,7 @@
 
         @Override
         public void uninstallApex(String packageName, long versionCode, int userId,
-                IntentSender intentSender) {
+                IntentSender intentSender, int flags) {
             final int callerUid = Binder.getCallingUid();
             if (callerUid != Process.ROOT_UID && callerUid != Process.SHELL_UID) {
                 throw new SecurityException("Not allowed to uninstall apexes");
@@ -23532,7 +23097,7 @@
                     new PackageInstallerService.PackageDeleteObserverAdapter(
                             PackageManagerService.this.mContext, intentSender, packageName,
                             false, userId);
-            if (userId != UserHandle.USER_ALL) {
+            if ((flags & PackageManager.DELETE_ALL_USERS) == 0) {
                 adapter.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_ABORTED,
                         "Can't uninstall an apex for a single user");
                 return;
@@ -23600,12 +23165,12 @@
 
         @Override
         public boolean isCallerInstallerOfRecord(
-                @NonNull PackageParser.Package pkg, int callingUid) {
+                @NonNull AndroidPackage pkg, int callingUid) {
             synchronized (mLock) {
                 if (pkg == null) {
                     return false;
                 }
-                final PackageSetting packageSetting = (PackageSetting) pkg.mExtras;
+                final PackageSetting packageSetting = getPackageSetting(pkg.getPackageName());
                 if (packageSetting == null) {
                     return false;
                 }
@@ -23702,7 +23267,16 @@
         }
     }
 
-    void forEachPackage(Consumer<PackageParser.Package> actionLocked) {
+    @Nullable
+    public PackageSetting getPackageSetting(String packageName) {
+        synchronized (mPackages) {
+            packageName = resolveInternalPackageNameLPr(
+                    packageName, PackageManager.VERSION_CODE_HIGHEST);
+            return mSettings.mPackages.get(packageName);
+        }
+    }
+
+    void forEachPackage(Consumer<AndroidPackage> actionLocked) {
         synchronized (mLock) {
             int numPackages = mPackages.size();
             for (int i = 0; i < numPackages; i++) {
@@ -23711,13 +23285,13 @@
         }
     }
 
-    void forEachInstalledPackage(@NonNull Consumer<PackageParser.Package> actionLocked,
+    void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> actionLocked,
             @UserIdInt int userId) {
         synchronized (mLock) {
             int numPackages = mPackages.size();
             for (int i = 0; i < numPackages; i++) {
-                PackageParser.Package pkg = mPackages.valueAt(i);
-                PackageSetting setting = mSettings.getPackageLPr(pkg.packageName);
+                AndroidPackage pkg = mPackages.valueAt(i);
+                PackageSetting setting = mSettings.getPackageLPr(pkg.getPackageName());
                 if (setting == null || !setting.getInstalled(userId)) {
                     continue;
                 }
@@ -23734,7 +23308,7 @@
      * Return a <b>copy</b> of the collection of packages known to the package manager.
      * @return A copy of the values of mPackages.
      */
-    Collection<PackageParser.Package> getPackages() {
+    Collection<AndroidPackage> getPackages() {
         synchronized (mLock) {
             return new ArrayList<>(mPackages.values());
         }
@@ -23770,8 +23344,8 @@
         return mCompilerStats.getPackageStats(pkgName);
     }
 
-    public CompilerStats.PackageStats getOrCreateCompilerPackageStats(PackageParser.Package pkg) {
-        return getOrCreateCompilerPackageStats(pkg.packageName);
+    public CompilerStats.PackageStats getOrCreateCompilerPackageStats(AndroidPackage pkg) {
+        return getOrCreateCompilerPackageStats(pkg.getPackageName());
     }
 
     public CompilerStats.PackageStats getOrCreateCompilerPackageStats(String pkgName) {
@@ -23881,7 +23455,7 @@
 
     boolean canHaveOatDir(String packageName) {
         synchronized (mLock) {
-            PackageParser.Package p = mPackages.get(packageName);
+            AndroidPackage p = mPackages.get(packageName);
             if (p == null) {
                 return false;
             }
@@ -23889,11 +23463,11 @@
         }
     }
 
-    private String getOatDir(PackageParser.Package pkg) {
+    private String getOatDir(AndroidPackage pkg) {
         if (!pkg.canHaveOatDir()) {
             return null;
         }
-        File codePath = new File(pkg.codePath);
+        File codePath = new File(pkg.getCodePath());
         if (codePath.isDirectory()) {
             return PackageDexOptimizer.getOatDir(codePath).getAbsolutePath();
         }
@@ -23904,11 +23478,12 @@
         final String[] instructionSets;
         final List<String> codePaths;
         final String oatDir;
-        final PackageParser.Package pkg;
+        final AndroidPackage pkg;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
         }
-        instructionSets = getAppDexInstructionSets(pkg.applicationInfo);
+        instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(),
+                pkg.getSecondaryCpuAbi());
         codePaths = pkg.getAllCodePaths();
         oatDir = getOatDir(pkg);
 
@@ -23927,19 +23502,19 @@
         Set<String> unusedPackages = new HashSet<>();
         long currentTimeInMillis = System.currentTimeMillis();
         synchronized (mLock) {
-            for (PackageParser.Package pkg : mPackages.values()) {
-                PackageSetting ps =  mSettings.mPackages.get(pkg.packageName);
+            for (AndroidPackage pkg : mPackages.values()) {
+                PackageSetting ps =  mSettings.mPackages.get(pkg.getPackageName());
                 if (ps == null) {
                     continue;
                 }
                 PackageDexUsage.PackageUseInfo packageUseInfo =
-                      getDexManager().getPackageUseInfoOrDefault(pkg.packageName);
+                      getDexManager().getPackageUseInfoOrDefault(pkg.getPackageName());
                 if (PackageManagerServiceUtils
                         .isUnusedSinceTimeInMillis(ps.firstInstallTime, currentTimeInMillis,
                                 downgradeTimeThresholdMillis, packageUseInfo,
                                 pkg.getLatestPackageUseTimeInMills(),
                                 pkg.getLatestForegroundPackageUseTimeInMills())) {
-                    unusedPackages.add(pkg.packageName);
+                    unusedPackages.add(pkg.getPackageName());
                 }
             }
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index ef47410..ded9a9c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -35,10 +35,13 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfoLite;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.PackageParserException;
 import android.content.pm.ResolveInfo;
 import android.content.pm.Signature;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ApkParseUtils;
 import android.os.Build;
 import android.os.Debug;
 import android.os.Environment;
@@ -120,7 +123,7 @@
     // Sort a list of apps by their last usage, most recently used apps first. The order of
     // packages without usage data is undefined (but they will be sorted after the packages
     // that do have usage data).
-    public static void sortPackagesByUsageDate(List<PackageParser.Package> pkgs,
+    public static void sortPackagesByUsageDate(List<AndroidPackage> pkgs,
             PackageManagerService packageManagerService) {
         if (!packageManagerService.isHistoricalPackageUsageAvailable()) {
             return;
@@ -135,12 +138,12 @@
     // package will be removed from {@code packages} and added to {@code result} with its
     // dependencies. If usage data is available, the positive packages will be sorted by usage
     // data (with {@code sortTemp} as temporary storage).
-    private static void applyPackageFilter(Predicate<PackageParser.Package> filter,
-            Collection<PackageParser.Package> result,
-            Collection<PackageParser.Package> packages,
-            @NonNull List<PackageParser.Package> sortTemp,
+    private static void applyPackageFilter(Predicate<AndroidPackage> filter,
+            Collection<AndroidPackage> result,
+            Collection<AndroidPackage> packages,
+            @NonNull List<AndroidPackage> sortTemp,
             PackageManagerService packageManagerService) {
-        for (PackageParser.Package pkg : packages) {
+        for (AndroidPackage pkg : packages) {
             if (filter.test(pkg)) {
                 sortTemp.add(pkg);
             }
@@ -149,10 +152,10 @@
         sortPackagesByUsageDate(sortTemp, packageManagerService);
         packages.removeAll(sortTemp);
 
-        for (PackageParser.Package pkg : sortTemp) {
+        for (AndroidPackage pkg : sortTemp) {
             result.add(pkg);
 
-            Collection<PackageParser.Package> deps =
+            Collection<AndroidPackage> deps =
                     packageManagerService.findSharedNonSystemLibraries(pkg);
             if (!deps.isEmpty()) {
                 deps.removeAll(result);
@@ -166,50 +169,51 @@
 
     // Sort apps by importance for dexopt ordering. Important apps are given
     // more priority in case the device runs out of space.
-    public static List<PackageParser.Package> getPackagesForDexopt(
-            Collection<PackageParser.Package> packages,
+    public static List<AndroidPackage> getPackagesForDexopt(
+            Collection<AndroidPackage> packages,
             PackageManagerService packageManagerService) {
         return getPackagesForDexopt(packages, packageManagerService, DEBUG_DEXOPT);
     }
 
-    public static List<PackageParser.Package> getPackagesForDexopt(
-            Collection<PackageParser.Package> packages,
+    public static List<AndroidPackage> getPackagesForDexopt(
+            Collection<AndroidPackage> packages,
             PackageManagerService packageManagerService,
             boolean debug) {
-        ArrayList<PackageParser.Package> remainingPkgs = new ArrayList<>(packages);
-        LinkedList<PackageParser.Package> result = new LinkedList<>();
-        ArrayList<PackageParser.Package> sortTemp = new ArrayList<>(remainingPkgs.size());
+        ArrayList<AndroidPackage> remainingPkgs = new ArrayList<>(packages);
+        LinkedList<AndroidPackage> result = new LinkedList<>();
+        ArrayList<AndroidPackage> sortTemp = new ArrayList<>(remainingPkgs.size());
 
         // Give priority to core apps.
-        applyPackageFilter((pkg) -> pkg.coreApp, result, remainingPkgs, sortTemp,
+        applyPackageFilter((pkg) -> pkg.isCoreApp(), result, remainingPkgs, sortTemp,
                 packageManagerService);
 
         // Give priority to system apps that listen for pre boot complete.
         Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
         final ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
-        applyPackageFilter((pkg) -> pkgNames.contains(pkg.packageName), result, remainingPkgs,
+        applyPackageFilter((pkg) -> pkgNames.contains(pkg.getPackageName()), result, remainingPkgs,
                 sortTemp, packageManagerService);
 
         // Give priority to apps used by other apps.
         DexManager dexManager = packageManagerService.getDexManager();
         applyPackageFilter((pkg) ->
-                dexManager.getPackageUseInfoOrDefault(pkg.packageName)
+                dexManager.getPackageUseInfoOrDefault(pkg.getPackageName())
                         .isAnyCodePathUsedByOtherApps(),
                 result, remainingPkgs, sortTemp, packageManagerService);
 
         // Filter out packages that aren't recently used, add all remaining apps.
         // TODO: add a property to control this?
-        Predicate<PackageParser.Package> remainingPredicate;
+        Predicate<AndroidPackage> remainingPredicate;
         if (!remainingPkgs.isEmpty() && packageManagerService.isHistoricalPackageUsageAvailable()) {
             if (debug) {
                 Log.i(TAG, "Looking at historical package use");
             }
             // Get the package that was used last.
-            PackageParser.Package lastUsed = Collections.max(remainingPkgs, (pkg1, pkg2) ->
+            AndroidPackage lastUsed = Collections.max(remainingPkgs, (pkg1, pkg2) ->
                     Long.compare(pkg1.getLatestForegroundPackageUseTimeInMills(),
                             pkg2.getLatestForegroundPackageUseTimeInMills()));
             if (debug) {
-                Log.i(TAG, "Taking package " + lastUsed.packageName + " as reference in time use");
+                Log.i(TAG, "Taking package " + lastUsed.getPackageName()
+                        + " as reference in time use");
             }
             long estimatedPreviousSystemUseTime =
                     lastUsed.getLatestForegroundPackageUseTimeInMills();
@@ -285,13 +289,13 @@
         }
     }
 
-    public static String packagesToString(Collection<PackageParser.Package> c) {
+    public static String packagesToString(Collection<AndroidPackage> c) {
         StringBuilder sb = new StringBuilder();
-        for (PackageParser.Package pkg : c) {
+        for (AndroidPackage pkg : c) {
             if (sb.length() > 0) {
                 sb.append(", ");
             }
-            sb.append(pkg.packageName);
+            sb.append(pkg.getPackageName());
         }
         return sb.toString();
     }
@@ -309,16 +313,16 @@
         return false;
     }
 
-    public static long getLastModifiedTime(PackageParser.Package pkg) {
-        final File srcFile = new File(pkg.codePath);
+    public static long getLastModifiedTime(AndroidPackage pkg) {
+        final File srcFile = new File(pkg.getCodePath());
         if (!srcFile.isDirectory()) {
             return srcFile.lastModified();
         }
-        final File baseFile = new File(pkg.baseCodePath);
+        final File baseFile = new File(pkg.getBaseCodePath());
         long maxModifiedTime = baseFile.lastModified();
-        if (pkg.splitCodePaths != null) {
-            for (int i = pkg.splitCodePaths.length - 1; i >=0; --i) {
-                final File splitFile = new File(pkg.splitCodePaths[i]);
+        if (pkg.getSplitCodePaths() != null) {
+            for (int i = pkg.getSplitCodePaths().length - 1; i >=0; --i) {
+                final File splitFile = new File(pkg.getSplitCodePaths()[i]);
                 maxModifiedTime = Math.max(maxModifiedTime, splitFile.lastModified());
             }
         }
@@ -539,7 +543,7 @@
     private static boolean matchSignatureInSystem(PackageSetting pkgSetting,
             PackageSetting disabledPkgSetting) {
         try {
-            PackageParser.collectCertificates(disabledPkgSetting.pkg, true /* skipVerify */);
+            ApkParseUtils.collectCertificates(disabledPkgSetting.pkg, true /* skipVerify */);
             if (pkgSetting.signatures.mSigningDetails.checkCapability(
                     disabledPkgSetting.signatures.mSigningDetails,
                     PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
@@ -905,8 +909,10 @@
      * Returns the {@link PermissionsState} for the given package. If the {@link PermissionsState}
      * could not be found, {@code null} will be returned.
      */
-    public static PermissionsState getPermissionsState(PackageParser.Package pkg) {
-        final PackageSetting packageSetting = (PackageSetting) pkg.mExtras;
+    public static PermissionsState getPermissionsState(
+            PackageManagerInternal packageManagerInternal, AndroidPackage pkg) {
+        final PackageSetting packageSetting =
+                (PackageSetting) packageManagerInternal.getPackageSetting(pkg.getPackageName());
         if (packageSetting == null) {
             return null;
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 232374c..fff404f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -48,7 +48,6 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.ApkLite;
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
@@ -62,6 +61,7 @@
 import android.content.pm.dex.ArtManager;
 import android.content.pm.dex.DexMetadataHelper;
 import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
+import android.content.pm.parsing.ApkLiteParseUtils;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.content.rollback.IRollbackManager;
@@ -453,7 +453,7 @@
                 throw new IllegalArgumentException("Error: Can't open file: " + inPath);
             }
             try {
-                ApkLite baseApk = PackageParser.parseApkLite(fd.getFileDescriptor(), inPath, 0);
+                ApkLite baseApk = ApkLiteParseUtils.parseApkLite(fd.getFileDescriptor(), inPath, 0);
                 PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
                         null, null);
                 sessionSize += PackageHelper.calculateInstalledSize(pkgLite,
@@ -504,11 +504,9 @@
             getErrPrintWriter().println("Error: no package specified");
             return 1;
         }
-        userId = translateUserId(userId, true /*allowAll*/, "runPath");
-        if (userId == UserHandle.USER_ALL) {
-            userId = UserHandle.USER_SYSTEM;
-        }
-        return displayPackageFilePath(pkg, userId);
+        final int translatedUserId =
+                translateUserId(userId, UserHandle.USER_NULL, "runPath");
+        return displayPackageFilePath(pkg, translatedUserId);
     }
 
     private int runList() throws RemoteException {
@@ -730,13 +728,14 @@
 
         final String filter = getNextArg();
 
-        userId = translateUserId(userId, true /*allowAll*/, "runListPackages");
         if (userId == UserHandle.USER_ALL) {
-            userId = UserHandle.USER_SYSTEM;
+            getFlags |= PackageManager.MATCH_KNOWN_PACKAGES;
         }
+        final int translatedUserId =
+                translateUserId(userId, UserHandle.USER_SYSTEM, "runListPackages");
         @SuppressWarnings("unchecked")
         final ParceledListSlice<PackageInfo> slice =
-                mInterface.getInstalledPackages(getFlags, userId);
+                mInterface.getInstalledPackages(getFlags, translatedUserId);
         final List<PackageInfo> packages = slice.getList();
 
         final int count = packages.size();
@@ -900,29 +899,29 @@
     }
 
     private int runListStagedSessions() {
-        final IndentingPrintWriter pw = new IndentingPrintWriter(
-                getOutPrintWriter(), /* singleIndent */ "  ", /* wrapLength */ 120);
+        try (IndentingPrintWriter pw = new IndentingPrintWriter(
+                getOutPrintWriter(), /* singleIndent */ "  ", /* wrapLength */ 120)) {
+            final SessionDump sessionDump = new SessionDump();
+            String opt;
+            while ((opt = getNextOption()) != null) {
+                if (!setSessionFlag(opt, sessionDump)) {
+                    pw.println("Error: Unknown option: " + opt);
+                    return -1;
+                }
+            }
 
-        SessionDump sessionDump = new SessionDump();
-        String opt;
-        while ((opt = getNextOption()) != null) {
-            if (!setSessionFlag(opt, sessionDump)) {
-                pw.println("Error: Unknown option: " + opt);
+            try {
+                final List<SessionInfo> stagedSessions =
+                        mInterface.getPackageInstaller().getStagedSessions().getList();
+                printSessionList(pw, stagedSessions, sessionDump);
+            } catch (RemoteException e) {
+                pw.println("Failure ["
+                        + e.getClass().getName() + " - "
+                        + e.getMessage() + "]");
                 return -1;
             }
+            return 1;
         }
-
-        try {
-            List<SessionInfo> stagedSessions =
-                    mInterface.getPackageInstaller().getStagedSessions().getList();
-            printSessionList(pw, stagedSessions, sessionDump);
-        } catch (RemoteException e) {
-            pw.println("Failure ["
-                    + e.getClass().getName() + " - "
-                    + e.getMessage() + "]");
-            return -1;
-        }
-        return 1;
     }
 
     private void printSessionList(IndentingPrintWriter pw, List<SessionInfo> stagedSessions,
@@ -1357,19 +1356,17 @@
             pw.println("Error: package name not specified");
             return 1;
         }
-        userId = translateUserId(userId, true /*allowAll*/, "runInstallExisting");
-        if (userId == UserHandle.USER_ALL) {
-            userId = UserHandle.USER_SYSTEM;
-        }
+        final int translatedUserId =
+                translateUserId(userId, UserHandle.USER_NULL, "runInstallExisting");
 
         int installReason = PackageManager.INSTALL_REASON_UNKNOWN;
         try {
             if (waitTillComplete) {
                 final LocalIntentReceiver receiver = new LocalIntentReceiver();
                 final IPackageInstaller installer = mInterface.getPackageInstaller();
-                pw.println("Installing package " + packageName + " for user: " + userId);
+                pw.println("Installing package " + packageName + " for user: " + translatedUserId);
                 installer.installExistingPackage(packageName, installFlags, installReason,
-                        receiver.getIntentSender(), userId, null);
+                        receiver.getIntentSender(), translatedUserId, null);
                 final Intent result = receiver.getResult();
                 final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
                         PackageInstaller.STATUS_FAILURE);
@@ -1377,12 +1374,12 @@
                 return status == PackageInstaller.STATUS_SUCCESS ? 0 : 1;
             }
 
-            final int res = mInterface.installExistingPackageAsUser(packageName, userId,
+            final int res = mInterface.installExistingPackageAsUser(packageName, translatedUserId,
                     installFlags, installReason, null);
             if (res == PackageManager.INSTALL_FAILED_INVALID_URI) {
                 throw new NameNotFoundException("Package " + packageName + " doesn't exist");
             }
-            pw.println("Package " + packageName + " installed for user: " + userId);
+            pw.println("Package " + packageName + " installed for user: " + translatedUserId);
             return 0;
         } catch (RemoteException | NameNotFoundException e) {
             pw.println(e.toString());
@@ -1845,21 +1842,24 @@
             return runRemoveSplits(packageName, splitNames);
         }
 
-        userId = translateUserId(userId, true /*allowAll*/, "runUninstall");
+        if (userId == UserHandle.USER_ALL) {
+            flags |= PackageManager.DELETE_ALL_USERS;
+        }
+        final int translatedUserId =
+                translateUserId(userId, UserHandle.USER_SYSTEM, "runUninstall");
         final LocalIntentReceiver receiver = new LocalIntentReceiver();
-        PackageManagerInternal internal = LocalServices.getService(PackageManagerInternal.class);
+        final PackageManagerInternal internal =
+                LocalServices.getService(PackageManagerInternal.class);
 
         if (internal.isApexPackage(packageName)) {
-            internal.uninstallApex(packageName, versionCode, userId, receiver.getIntentSender());
+            internal.uninstallApex(
+                    packageName, versionCode, translatedUserId, receiver.getIntentSender(), flags);
         } else {
-            if (userId == UserHandle.USER_ALL) {
-                userId = UserHandle.USER_SYSTEM;
-                flags |= PackageManager.DELETE_ALL_USERS;
-            } else {
+            if ((flags & PackageManager.DELETE_ALL_USERS) == 0) {
                 final PackageInfo info = mInterface.getPackageInfo(packageName,
-                        PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId);
+                        PackageManager.MATCH_STATIC_SHARED_LIBRARIES, translatedUserId);
                 if (info == null) {
-                    pw.println("Failure [not installed for " + userId + "]");
+                    pw.println("Failure [not installed for " + translatedUserId + "]");
                     return 1;
                 }
                 final boolean isSystem =
@@ -1871,10 +1871,9 @@
                     flags |= PackageManager.DELETE_SYSTEM_APP;
                 }
             }
-
             mInterface.getPackageInstaller().uninstall(new VersionedPackage(packageName,
                             versionCode), null /*callerPackageName*/, flags,
-                    receiver.getIntentSender(), userId);
+                    receiver.getIntentSender(), translatedUserId);
         }
 
         final Intent result = receiver.getResult();
@@ -1948,8 +1947,10 @@
             return 1;
         }
 
-        ClearDataObserver obs = new ClearDataObserver();
-        ActivityManager.getService().clearApplicationUserData(pkg, false, obs, userId);
+        final int translatedUserId =
+                translateUserId(userId, UserHandle.USER_NULL, "runClear");
+        final ClearDataObserver obs = new ClearDataObserver();
+        ActivityManager.getService().clearApplicationUserData(pkg, false, obs, translatedUserId);
         synchronized (obs) {
             while (!obs.finished) {
                 try {
@@ -1991,28 +1992,26 @@
             userId = UserHandle.parseUserArg(getNextArgRequired());
         }
 
-        String pkg = getNextArg();
+        final String pkg = getNextArg();
         if (pkg == null) {
             getErrPrintWriter().println("Error: no package or component specified");
             return 1;
         }
-        userId = translateUserId(userId, true /*allowAll*/, "runSetEnabledSetting");
-        if (userId == UserHandle.USER_ALL) {
-            userId = UserHandle.USER_SYSTEM;
-        }
-        ComponentName cn = ComponentName.unflattenFromString(pkg);
+        final int translatedUserId =
+                translateUserId(userId, UserHandle.USER_NULL, "runSetEnabledSetting");
+        final ComponentName cn = ComponentName.unflattenFromString(pkg);
         if (cn == null) {
-            mInterface.setApplicationEnabledSetting(pkg, state, 0, userId,
+            mInterface.setApplicationEnabledSetting(pkg, state, 0, translatedUserId,
                     "shell:" + android.os.Process.myUid());
             getOutPrintWriter().println("Package " + pkg + " new state: "
                     + enabledSettingToString(
-                    mInterface.getApplicationEnabledSetting(pkg, userId)));
+                    mInterface.getApplicationEnabledSetting(pkg, translatedUserId)));
             return 0;
         } else {
-            mInterface.setComponentEnabledSetting(cn, state, 0, userId);
+            mInterface.setComponentEnabledSetting(cn, state, 0, translatedUserId);
             getOutPrintWriter().println("Component " + cn.toShortString() + " new state: "
                     + enabledSettingToString(
-                    mInterface.getComponentEnabledSetting(cn, userId)));
+                    mInterface.getComponentEnabledSetting(cn, translatedUserId)));
             return 0;
         }
     }
@@ -2029,13 +2028,11 @@
             getErrPrintWriter().println("Error: no package or component specified");
             return 1;
         }
-        userId = translateUserId(userId, true /*allowAll*/, "runSetHiddenSetting");
-        if (userId == UserHandle.USER_ALL) {
-            userId = UserHandle.USER_SYSTEM;
-        }
-        mInterface.setApplicationHiddenSettingAsUser(pkg, state, userId);
+        final int translatedUserId =
+                translateUserId(userId, UserHandle.USER_NULL, "runSetHiddenSetting");
+        mInterface.setApplicationHiddenSettingAsUser(pkg, state, translatedUserId);
         getOutPrintWriter().println("Package " + pkg + " new hidden state: "
-                + mInterface.getApplicationHiddenSettingAsUser(pkg, userId));
+                + mInterface.getApplicationHiddenSettingAsUser(pkg, translatedUserId));
         return 0;
     }
 
@@ -2102,16 +2099,14 @@
             info = null;
         }
         try {
-            userId = translateUserId(userId, true /*allowAll*/, "runSuspend");
-            if (userId == UserHandle.USER_ALL) {
-                userId = UserHandle.USER_SYSTEM;
-            }
+            final int translatedUserId =
+                    translateUserId(userId, UserHandle.USER_NULL, "runSuspend");
             mInterface.setPackagesSuspendedAsUser(new String[]{packageName}, suspendedState,
                     ((appExtras.size() > 0) ? appExtras : null),
                     ((launcherExtras.size() > 0) ? launcherExtras : null),
-                    info, callingPackage, userId);
+                    info, callingPackage, translatedUserId);
             pw.println("Package " + packageName + " new suspended state: "
-                    + mInterface.isPackageSuspendedForUser(packageName, userId));
+                    + mInterface.isPackageSuspendedForUser(packageName, translatedUserId));
             return 0;
         } catch (RemoteException | IllegalArgumentException e) {
             pw.println(e.toString());
@@ -2139,11 +2134,12 @@
             getErrPrintWriter().println("Error: no permission specified");
             return 1;
         }
-        userId = translateUserId(userId, true /*allowAll*/, "runGrantRevokePermission");
+        final int translatedUserId =
+                translateUserId(userId, UserHandle.USER_NULL, "runGrantRevokePermission");
         if (grant) {
-            mPermissionManager.grantRuntimePermission(pkg, perm, userId);
+            mPermissionManager.grantRuntimePermission(pkg, perm, translatedUserId);
         } else {
-            mPermissionManager.revokeRuntimePermission(pkg, perm, userId);
+            mPermissionManager.revokeRuntimePermission(pkg, perm, translatedUserId);
         }
         return 0;
     }
@@ -2327,11 +2323,9 @@
                 return 1;
         }
 
-        userId = translateUserId(userId, true /*allowAll*/, "runSetAppLink");
-        if (userId == UserHandle.USER_ALL) {
-            userId = UserHandle.USER_SYSTEM;
-        }
-        final PackageInfo info = mInterface.getPackageInfo(pkg, 0, userId);
+        final int translatedUserId =
+                translateUserId(userId, UserHandle.USER_NULL, "runSetAppLink");
+        final PackageInfo info = mInterface.getPackageInfo(pkg, 0, translatedUserId);
         if (info == null) {
             getErrPrintWriter().println("Error: package " + pkg + " not found.");
             return 1;
@@ -2342,7 +2336,7 @@
             return 1;
         }
 
-        if (!mInterface.updateIntentVerificationStatus(pkg, newMode, userId)) {
+        if (!mInterface.updateIntentVerificationStatus(pkg, newMode, translatedUserId)) {
             getErrPrintWriter().println("Error: unable to update app link status for " + pkg);
             return 1;
         }
@@ -2371,11 +2365,9 @@
             return 1;
         }
 
-        userId = translateUserId(userId, true /*allowAll*/, "runGetAppLink");
-        if (userId == UserHandle.USER_ALL) {
-            userId = UserHandle.USER_SYSTEM;
-        }
-        final PackageInfo info = mInterface.getPackageInfo(pkg, 0, userId);
+        final int translatedUserId =
+                translateUserId(userId, UserHandle.USER_NULL, "runGetAppLink");
+        final PackageInfo info = mInterface.getPackageInfo(pkg, 0, translatedUserId);
         if (info == null) {
             getErrPrintWriter().println("Error: package " + pkg + " not found.");
             return 1;
@@ -2388,7 +2380,7 @@
         }
 
         getOutPrintWriter().println(linkStateToString(
-                mInterface.getIntentVerificationStatus(pkg, userId)));
+                mInterface.getIntentVerificationStatus(pkg, translatedUserId)));
 
         return 0;
     }
@@ -2565,9 +2557,11 @@
             getErrPrintWriter().println("Error: valid value not specified");
             return 1;
         }
-        IUserManager um = IUserManager.Stub.asInterface(
+        final int translatedUserId =
+                translateUserId(userId, UserHandle.USER_NULL, "runSetUserRestriction");
+        final IUserManager um = IUserManager.Stub.asInterface(
                 ServiceManager.getService(Context.USER_SERVICE));
-        um.setUserRestriction(restriction, value, userId);
+        um.setUserRestriction(restriction, value, translatedUserId);
         return 0;
     }
 
@@ -2763,14 +2757,15 @@
             }
             pkgName = componentName.getPackageName();
         }
-        userId = translateUserId(userId, true /*allowAll*/, "runInstallCreate");
+        final int translatedUserId =
+                translateUserId(userId, UserHandle.USER_NULL, "runSetHomeActivity");
         final CompletableFuture<Boolean> future = new CompletableFuture<>();
         final RemoteCallback callback = new RemoteCallback(res -> future.complete(res != null));
         try {
             IRoleManager roleManager = android.app.role.IRoleManager.Stub.asInterface(
                     ServiceManager.getServiceOrThrow(Context.ROLE_SERVICE));
             roleManager.addRoleHolderAsUser(RoleManager.ROLE_HOME, pkgName,
-                    0, userId, callback);
+                    0, translatedUserId, callback);
             boolean success = future.get();
             if (success) {
                 pw.println("Success");
@@ -2859,14 +2854,12 @@
             }
         }
 
-        userId = translateUserId(userId, true /*allowAll*/, "runSetHarmfulAppWarning");
-        if (userId == UserHandle.USER_ALL) {
-            userId = UserHandle.USER_SYSTEM;
-        }
+        final int translatedUserId =
+                translateUserId(userId, UserHandle.USER_NULL, "runSetHarmfulAppWarning");
         final String packageName = getNextArgRequired();
         final String warning = getNextArg();
 
-        mInterface.setHarmfulAppWarning(packageName, warning, userId);
+        mInterface.setHarmfulAppWarning(packageName, warning, translatedUserId);
 
         return 0;
     }
@@ -2884,12 +2877,10 @@
             }
         }
 
-        userId = translateUserId(userId, true /*allowAll*/, "runGetHarmfulAppWarning");
-        if (userId == UserHandle.USER_ALL) {
-            userId = UserHandle.USER_SYSTEM;
-        }
+        final int translatedUserId =
+                translateUserId(userId, UserHandle.USER_NULL, "runGetHarmfulAppWarning");
         final String packageName = getNextArgRequired();
-        final CharSequence warning = mInterface.getHarmfulAppWarning(packageName, userId);
+        final CharSequence warning = mInterface.getHarmfulAppWarning(packageName, translatedUserId);
         if (!TextUtils.isEmpty(warning)) {
             getOutPrintWriter().println(warning);
             return 0;
@@ -2917,21 +2908,22 @@
         throw new IllegalArgumentException("ABI " + abi + " not supported on this device");
     }
 
-    private int translateUserId(int userId, boolean allowAll, String logContext) {
-        return ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
-                userId, allowAll, true, logContext, "pm command");
+    private int translateUserId(int userId, int allUserId, String logContext) {
+        final boolean allowAll = (allUserId != UserHandle.USER_NULL);
+        final int translatedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+                Binder.getCallingUid(), userId, allowAll, true, logContext, "pm command");
+        return translatedUserId == UserHandle.USER_ALL ? allUserId : translatedUserId;
     }
 
     private int doCreateSession(SessionParams params, String installerPackageName, int userId)
             throws RemoteException {
-        userId = translateUserId(userId, true /*allowAll*/, "doCreateSession");
         if (userId == UserHandle.USER_ALL) {
-            userId = UserHandle.USER_SYSTEM;
             params.installFlags |= PackageManager.INSTALL_ALL_USERS;
         }
-
+        final int translatedUserId =
+                translateUserId(userId, UserHandle.USER_SYSTEM, "doCreateSession");
         final int sessionId = mInterface.getPackageInstaller()
-                .createSession(params, installerPackageName, userId);
+                .createSession(params, installerPackageName, translatedUserId);
         return sessionId;
     }
 
@@ -3288,7 +3280,7 @@
         pw.println("       [--user USER_ID] INTENT");
         pw.println("    Prints all broadcast receivers that can handle the given INTENT.");
         pw.println("");
-        pw.println("  install [-rtsfdgw] [-i PACKAGE] [--user USER_ID|all|current]");
+        pw.println("  install [-rtfdgw] [-i PACKAGE] [--user USER_ID|all|current]");
         pw.println("       [-p INHERIT_PACKAGE] [--install-location 0/1/2]");
         pw.println("       [--install-reason 0/1/2/3/4] [--originating-uri URI]");
         pw.println("       [--referrer URI] [--abi ABI_NAME] [--force-sdk]");
@@ -3302,7 +3294,6 @@
         pw.println("      -R: disallow replacement of existing application");
         pw.println("      -t: allow test packages");
         pw.println("      -i: specify package name of installer owning the app");
-        pw.println("      -s: install application on sdcard");
         pw.println("      -f: install application on internal flash");
         pw.println("      -d: allow version code downgrade (debuggable packages only)");
         pw.println("      -p: partial application install (new split on top of existing pkg)");
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 1254891..bbc0dc9 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -18,8 +18,9 @@
 
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
 import android.content.pm.UserInfo;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ParsedPackage;
 import android.service.pm.PackageProto;
 import android.util.proto.ProtoOutputStream;
 
@@ -31,9 +32,11 @@
 /**
  * Settings data for a particular package we know about.
  */
-public final class PackageSetting extends PackageSettingBase {
+public final class PackageSetting extends PackageSettingBase implements
+        ParsedPackage.PackageSettingCallback {
     int appId;
-    PackageParser.Package pkg;
+
+    public AndroidPackage pkg;
     /**
      * WARNING. The object reference is important. We perform integer equality and NOT
      * object equality to check whether shared user settings are the same.
@@ -50,12 +53,12 @@
     PackageSetting(String name, String realName, File codePath, File resourcePath,
             String legacyNativeLibraryPathString, String primaryCpuAbiString,
             String secondaryCpuAbiString, String cpuAbiOverrideString,
-            long pVersionCode, int pkgFlags, int privateFlags, String parentPackageName,
-            List<String> childPackageNames, int sharedUserId, String[] usesStaticLibraries,
+            long pVersionCode, int pkgFlags, int privateFlags,
+            int sharedUserId, String[] usesStaticLibraries,
             long[] usesStaticLibrariesVersions) {
         super(name, realName, codePath, resourcePath, legacyNativeLibraryPathString,
                 primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
-                pVersionCode, pkgFlags, privateFlags, parentPackageName, childPackageNames,
+                pVersionCode, pkgFlags, privateFlags,
                 usesStaticLibraries, usesStaticLibrariesVersions);
         this.sharedUserId = sharedUserId;
     }
@@ -116,10 +119,6 @@
                 : super.getPermissionsState();
     }
 
-    public PackageParser.Package getPackage() {
-        return pkg;
-    }
-
     public int getAppId() {
         return appId;
     }
@@ -132,6 +131,7 @@
         return installPermissionsFixed;
     }
 
+    // TODO(b/135203078): Remove these in favor of reading from the package directly
     public boolean isPrivileged() {
         return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
     }
@@ -176,11 +176,7 @@
         return true;
     }
 
-    public boolean hasChildPackages() {
-        return childPackageNames != null && !childPackageNames.isEmpty();
-    }
-
-    public void writeToProto(ProtoOutputStream proto, long fieldId, List<UserInfo> users) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId, List<UserInfo> users) {
         final long packageToken = proto.start(fieldId);
         proto.write(PackageProto.NAME, (realName != null ? realName : name));
         proto.write(PackageProto.UID, appId);
@@ -190,18 +186,19 @@
         proto.write(PackageProto.INSTALLER_NAME, installSource.installerPackageName);
 
         if (pkg != null) {
-            proto.write(PackageProto.VERSION_STRING, pkg.mVersionName);
+            proto.write(PackageProto.VERSION_STRING, pkg.getVersionName());
 
             long splitToken = proto.start(PackageProto.SPLITS);
             proto.write(PackageProto.SplitProto.NAME, "base");
-            proto.write(PackageProto.SplitProto.REVISION_CODE, pkg.baseRevisionCode);
+            proto.write(PackageProto.SplitProto.REVISION_CODE, pkg.getBaseRevisionCode());
             proto.end(splitToken);
 
-            if (pkg.splitNames != null) {
-                for (int i = 0; i < pkg.splitNames.length; i++) {
+            if (pkg.getSplitNames() != null) {
+                for (int i = 0; i < pkg.getSplitNames().length; i++) {
                     splitToken = proto.start(PackageProto.SPLITS);
-                    proto.write(PackageProto.SplitProto.NAME, pkg.splitNames[i]);
-                    proto.write(PackageProto.SplitProto.REVISION_CODE, pkg.splitRevisionCodes[i]);
+                    proto.write(PackageProto.SplitProto.NAME, pkg.getSplitNames()[i]);
+                    proto.write(PackageProto.SplitProto.REVISION_CODE,
+                            pkg.getSplitRevisionCodes()[i]);
                     proto.end(splitToken);
                 }
             }
@@ -225,4 +222,10 @@
         sharedUserId = other.sharedUserId;
         sharedUser = other.sharedUser;
     }
+
+    // TODO(b/135203078): Move to constructor
+    @Override
+    public void setAndroidPackage(AndroidPackage pkg) {
+        this.pkg = pkg;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 45ab357..671450d7 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -39,7 +39,6 @@
 import com.android.internal.util.Preconditions;
 
 import java.io.File;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
@@ -54,9 +53,6 @@
     public final String name;
     final String realName;
 
-    String parentPackageName;
-    List<String> childPackageNames;
-
     /**
      * Path where this package was found on disk. For monolithic packages
      * this is path to single base APK file; for cluster packages this is
@@ -138,14 +134,10 @@
             String legacyNativeLibraryPathString, String primaryCpuAbiString,
             String secondaryCpuAbiString, String cpuAbiOverrideString,
             long pVersionCode, int pkgFlags, int pkgPrivateFlags,
-            String parentPackageName, List<String> childPackageNames,
             String[] usesStaticLibraries, long[] usesStaticLibrariesVersions) {
         super(pkgFlags, pkgPrivateFlags);
         this.name = name;
         this.realName = realName;
-        this.parentPackageName = parentPackageName;
-        this.childPackageNames = (childPackageNames != null)
-                ? new ArrayList<>(childPackageNames) : null;
         this.usesStaticLibraries = usesStaticLibraries;
         this.usesStaticLibrariesVersions = usesStaticLibrariesVersions;
         this.codePath = codePath;
@@ -235,8 +227,6 @@
     }
 
     private void doCopy(PackageSettingBase orig) {
-        childPackageNames = (orig.childPackageNames != null)
-                ? new ArrayList<>(orig.childPackageNames) : null;
         codePath = orig.codePath;
         codePathString = orig.codePathString;
         cpuAbiOverrideString = orig.cpuAbiOverrideString;
@@ -247,7 +237,6 @@
         lastUpdateTime = orig.lastUpdateTime;
         legacyNativeLibraryPathString = orig.legacyNativeLibraryPathString;
         // Intentionally skip mOldCodePaths; it's not relevant for copies
-        parentPackageName = orig.parentPackageName;
         primaryCpuAbiString = orig.primaryCpuAbiString;
         resourcePath = orig.resourcePath;
         resourcePathString = orig.resourcePathString;
@@ -670,8 +659,6 @@
 
     protected PackageSettingBase updateFrom(PackageSettingBase other) {
         super.copyFrom(other);
-        this.parentPackageName = other.parentPackageName;
-        this.childPackageNames = other.childPackageNames;
         this.codePath = other.codePath;
         this.codePathString = other.codePathString;
         this.resourcePath = other.resourcePath;
diff --git a/services/core/java/com/android/server/pm/PackageUsage.java b/services/core/java/com/android/server/pm/PackageUsage.java
index ac1f739..ce2c9e7 100644
--- a/services/core/java/com/android/server/pm/PackageUsage.java
+++ b/services/core/java/com/android/server/pm/PackageUsage.java
@@ -20,7 +20,7 @@
 import static android.os.Process.SYSTEM_UID;
 
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.FileUtils;
 import android.util.AtomicFile;
 import android.util.Log;
@@ -36,7 +36,7 @@
 import java.nio.charset.StandardCharsets;
 import java.util.Map;
 
-class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> {
+class PackageUsage extends AbstractStatsBase<Map<String, AndroidPackage>> {
 
     private static final String USAGE_FILE_MAGIC = "PACKAGE_USAGE__VERSION_";
     private static final String USAGE_FILE_MAGIC_VERSION_1 = USAGE_FILE_MAGIC + "1";
@@ -52,7 +52,7 @@
     }
 
     @Override
-    protected void writeInternal(Map<String, PackageParser.Package> packages) {
+    protected void writeInternal(Map<String, AndroidPackage> packages) {
         AtomicFile file = getFile();
         FileOutputStream f = null;
         try {
@@ -66,13 +66,13 @@
             sb.append('\n');
             out.write(sb.toString().getBytes(StandardCharsets.US_ASCII));
 
-            for (PackageParser.Package pkg : packages.values()) {
+            for (AndroidPackage pkg : packages.values()) {
                 if (pkg.getLatestPackageUseTimeInMills() == 0L) {
                     continue;
                 }
                 sb.setLength(0);
-                sb.append(pkg.packageName);
-                for (long usageTimeInMillis : pkg.mLastPackageUsageTimeInMills) {
+                sb.append(pkg.getPackageName());
+                for (long usageTimeInMillis : pkg.getLastPackageUsageTimeInMills()) {
                     sb.append(' ');
                     sb.append(usageTimeInMillis);
                 }
@@ -90,7 +90,7 @@
     }
 
     @Override
-    protected void readInternal(Map<String, PackageParser.Package> packages) {
+    protected void readInternal(Map<String, AndroidPackage> packages) {
         AtomicFile file = getFile();
         BufferedInputStream in = null;
         try {
@@ -114,7 +114,7 @@
         }
     }
 
-    private void readVersion0LP(Map<String, PackageParser.Package> packages, InputStream in,
+    private void readVersion0LP(Map<String, AndroidPackage> packages, InputStream in,
             StringBuffer sb, String firstLine)
             throws IOException {
         // Initial version of the file had no version number and stored one
@@ -128,7 +128,7 @@
             }
 
             String packageName = tokens[0];
-            PackageParser.Package pkg = packages.get(packageName);
+            AndroidPackage pkg = packages.get(packageName);
             if (pkg == null) {
                 continue;
             }
@@ -137,12 +137,12 @@
             for (int reason = 0;
                     reason < PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT;
                     reason++) {
-                pkg.mLastPackageUsageTimeInMills[reason] = timestamp;
+                pkg.mutate().setLastPackageUsageTimeInMills(reason, timestamp);
             }
         }
     }
 
-    private void readVersion1LP(Map<String, PackageParser.Package> packages, InputStream in,
+    private void readVersion1LP(Map<String, AndroidPackage> packages, InputStream in,
             StringBuffer sb) throws IOException {
         // Version 1 of the file started with the corresponding version
         // number and then stored a package name and eight timestamps per line.
@@ -154,7 +154,7 @@
             }
 
             String packageName = tokens[0];
-            PackageParser.Package pkg = packages.get(packageName);
+            AndroidPackage pkg = packages.get(packageName);
             if (pkg == null) {
                 continue;
             }
@@ -162,7 +162,8 @@
             for (int reason = 0;
                     reason < PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT;
                     reason++) {
-                pkg.mLastPackageUsageTimeInMills[reason] = parseAsLong(tokens[reason + 1]);
+                pkg.mutate().setLastPackageUsageTimeInMills(reason,
+                        parseAsLong(tokens[reason + 1]));
             }
         }
     }
@@ -196,4 +197,4 @@
             sb.append((char)ch);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/pm/ParallelPackageParser.java b/services/core/java/com/android/server/pm/ParallelPackageParser.java
index 4ff3e12..a506514 100644
--- a/services/core/java/com/android/server/pm/ParallelPackageParser.java
+++ b/services/core/java/com/android/server/pm/ParallelPackageParser.java
@@ -16,7 +16,10 @@
 
 package com.android.server.pm;
 
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
 import android.content.pm.PackageParser;
+import android.content.pm.parsing.ParsedPackage;
 import android.os.Process;
 import android.os.Trace;
 import android.util.DisplayMetrics;
@@ -30,8 +33,6 @@
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.ExecutorService;
 
-import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
-
 /**
  * Helper class for parallel parsing of packages using {@link PackageParser}.
  * <p>Parsing requests are processed by a thread-pool of {@link #MAX_THREADS}.
@@ -65,14 +66,14 @@
 
     static class ParseResult {
 
-        PackageParser.Package pkg; // Parsed package
+        ParsedPackage parsedPackage; // Parsed package
         File scanFile; // File that was parsed
         Throwable throwable; // Set if an error occurs during parsing
 
         @Override
         public String toString() {
             return "ParseResult{" +
-                    "pkg=" + pkg +
+                    "parsedPackage=" + parsedPackage +
                     ", scanFile=" + scanFile +
                     ", throwable=" + throwable +
                     '}';
@@ -100,7 +101,7 @@
     /**
      * Submits the file for parsing
      * @param scanFile file to scan
-     * @param parseFlags parse falgs
+     * @param parseFlags parse flags
      */
     public void submit(File scanFile, int parseFlags) {
         mService.submit(() -> {
@@ -114,7 +115,7 @@
                 pp.setCacheDir(mCacheDir);
                 pp.setCallback(mPackageParserCallback);
                 pr.scanFile = scanFile;
-                pr.pkg = parsePackage(pp, scanFile, parseFlags);
+                pr.parsedPackage = parsePackage(pp, scanFile, parseFlags);
             } catch (Throwable e) {
                 pr.throwable = e;
             } finally {
@@ -133,9 +134,9 @@
     }
 
     @VisibleForTesting
-    protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile,
+    protected ParsedPackage parsePackage(PackageParser packageParser, File scanFile,
             int parseFlags) throws PackageParser.PackageParserException {
-        return packageParser.parsePackage(scanFile, parseFlags, true /* useCaches */);
+        return packageParser.parseParsedPackage(scanFile, parseFlags, true);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index b464988..466f19c 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -16,13 +16,18 @@
 
 package com.android.server.pm;
 
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.SigningDetails;
 import android.content.pm.Signature;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.Environment;
 import android.util.Slog;
 import android.util.Xml;
 
+import com.android.server.compat.PlatformCompat;
+
 import libcore.io.IoUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -72,6 +77,19 @@
     // Append targetSdkVersion=n to existing seinfo label where n is the app's targetSdkVersion
     private static final String TARGETSDKVERSION_STR = ":targetSdkVersion=";
 
+    /**
+     * This change gates apps access to untrusted_app_R-targetSDk SELinux domain. Allows opt-in
+     * to R targetSdkVersion enforced changes without changing target SDK. Turning this change
+     * off for an app targeting R is a no-op.
+     *
+     * <p>Has no effect for apps using shared user id.
+     *
+     * TODO(b/143539591): Update description with relevant SELINUX changes this opts in to.
+     */
+    @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.Q)
+    @ChangeId
+    static final long SELINUX_LATEST_CHANGES = 143539591L;
+
     // Only initialize sMacPermissions once.
     static {
         // Platform mac permissions.
@@ -319,6 +337,48 @@
         }
     }
 
+    private static int getTargetSdkVersionForSeInfo(AndroidPackage pkg,
+            SharedUserSetting sharedUserSetting, PlatformCompat compatibility) {
+        // Apps which share a sharedUserId must be placed in the same selinux domain. If this
+        // package is the first app installed as this shared user, set seInfoTargetSdkVersion to its
+        // targetSdkVersion. These are later adjusted in PackageManagerService's constructor to be
+        // the lowest targetSdkVersion of all apps within the shared user, which corresponds to the
+        // least restrictive selinux domain.
+        // NOTE: As new packages are installed / updated, the shared user's seinfoTargetSdkVersion
+        // will NOT be modified until next boot, even if a lower targetSdkVersion is used. This
+        // ensures that all packages continue to run in the same selinux domain.
+        if ((sharedUserSetting != null) && (sharedUserSetting.packages.size() != 0)) {
+            return sharedUserSetting.seInfoTargetSdkVersion;
+        }
+        if (compatibility.isChangeEnabled(SELINUX_LATEST_CHANGES, pkg.toAppInfoWithoutState())) {
+            return android.os.Build.VERSION_CODES.R;
+        }
+
+        return pkg.getTargetSdkVersion();
+    }
+
+    /**
+     * Selects a security label to a package based on input parameters and the seinfo tag taken
+     * from a matched policy. All signature based policy stanzas are consulted and, if no match
+     * is found, the default seinfo label of 'default' is used. The security label is attached to
+     * the ApplicationInfo instance of the package.
+     *
+     * @param pkg               object representing the package to be labeled.
+     * @param sharedUserSetting if the app shares a sharedUserId, then this has the shared setting.
+     * @param compatibility     the PlatformCompat service to ask about state of compat changes.
+     * @return String representing the resulting seinfo.
+     */
+    public static String getSeInfo(AndroidPackage pkg, SharedUserSetting sharedUserSetting,
+            PlatformCompat compatibility) {
+        final int targetSdkVersion = getTargetSdkVersionForSeInfo(pkg, sharedUserSetting,
+                compatibility);
+        // TODO(b/71593002): isPrivileged for sharedUser and appInfo should never be out of sync.
+        // They currently can be if the sharedUser apps are signed with the platform key.
+        final boolean isPrivileged = (sharedUserSetting != null)
+                ? sharedUserSetting.isPrivileged() | pkg.isPrivileged() : pkg.isPrivileged();
+        return getSeInfo(pkg, isPrivileged, targetSdkVersion);
+    }
+
     /**
      * Selects a security label to a package based on input parameters and the seinfo tag taken
      * from a matched policy. All signature based policy stanzas are consulted and, if no match
@@ -332,7 +392,7 @@
      *        MINIMUM_TARGETSDKVERSION.
      * @return String representing the resulting seinfo.
      */
-    public static String getSeInfo(PackageParser.Package pkg, boolean isPrivileged,
+    public static String getSeInfo(AndroidPackage pkg, boolean isPrivileged,
             int targetSdkVersion) {
         String seInfo = null;
         synchronized (sPolicies) {
@@ -361,8 +421,8 @@
         seInfo += TARGETSDKVERSION_STR + targetSdkVersion;
 
         if (DEBUG_POLICY_INSTALL) {
-            Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " +
-                    "seinfo=" + seInfo);
+            Slog.i(TAG, "package (" + pkg.getPackageName() + ") labeled with "
+                    + "seinfo=" + seInfo);
         }
         return seInfo;
     }
@@ -371,7 +431,7 @@
 /**
  * Holds valid policy representations of individual stanzas from a mac_permissions.xml
  * file. Each instance can further be used to assign seinfo values to apks using the
- * {@link Policy#getMatchedSeinfo} method. To create an instance of this use the
+ * {@link Policy#getMatchedSeInfo(AndroidPackage)} method. To create an instance of this use the
  * {@link PolicyBuilder} pattern class, where each instance is validated against a set
  * of invariants before being built and returned. Each instance can be guaranteed to
  * hold one valid policy stanza as outlined in the system/sepolicy/mac_permissions.xml
@@ -498,21 +558,21 @@
      * @return A string representing the seinfo matched during policy lookup.
      *         A value of null can also be returned if no match occured.
      */
-    public String getMatchedSeInfo(PackageParser.Package pkg) {
+    public String getMatchedSeInfo(AndroidPackage pkg) {
         // Check for exact signature matches across all certs.
         Signature[] certs = mCerts.toArray(new Signature[0]);
-        if (pkg.mSigningDetails != SigningDetails.UNKNOWN
-                && !Signature.areExactMatch(certs, pkg.mSigningDetails.signatures)) {
+        if (pkg.getSigningDetails() != SigningDetails.UNKNOWN
+                && !Signature.areExactMatch(certs, pkg.getSigningDetails().signatures)) {
 
             // certs aren't exact match, but the package may have rotated from the known system cert
-            if (certs.length > 1 || !pkg.mSigningDetails.hasCertificate(certs[0])) {
+            if (certs.length > 1 || !pkg.getSigningDetails().hasCertificate(certs[0])) {
                 return null;
             }
         }
 
         // Check for inner package name matches given that the
         // signature checks already passed.
-        String seinfoValue = mPkgMap.get(pkg.packageName);
+        String seinfoValue = mPkgMap.get(pkg.getPackageName());
         if (seinfoValue != null) {
             return seinfoValue;
         }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index f67d3c0..6653011 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -42,7 +42,6 @@
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser;
 import android.content.pm.PackageUserState;
 import android.content.pm.PermissionInfo;
 import android.content.pm.ResolveInfo;
@@ -50,6 +49,10 @@
 import android.content.pm.SuspendDialogInfo;
 import android.content.pm.UserInfo;
 import android.content.pm.VerifierDeviceIdentity;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils;
+import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
@@ -479,8 +482,8 @@
         final PackageSetting dp = mDisabledSysPackages.get(name);
         // always make sure the system package code and resource paths dont change
         if (dp == null && p.pkg != null && p.pkg.isSystem() && !p.pkg.isUpdatedSystemApp()) {
-            if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
-                p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+            if(p.pkg != null) {
+                p.pkg.mutate().setUpdatedSystemApp(true);
             }
             final PackageSetting disabled;
             if (replaced) {
@@ -506,14 +509,14 @@
             return null;
         }
         // Reset flag in ApplicationInfo object
-        if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
-            p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+        if(p.pkg != null) {
+            p.pkg.mutate().setUpdatedSystemApp(false);
         }
         PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath,
                 p.legacyNativeLibraryPathString, p.primaryCpuAbiString,
                 p.secondaryCpuAbiString, p.cpuAbiOverrideString,
                 p.appId, p.versionCode, p.pkgFlags, p.pkgPrivateFlags,
-                p.parentPackageName, p.childPackageNames, p.usesStaticLibraries,
+                p.usesStaticLibraries,
                 p.usesStaticLibrariesVersions);
         mDisabledSysPackages.remove(name);
         return ret;
@@ -530,8 +533,7 @@
     PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,
             String legacyNativeLibraryPathString, String primaryCpuAbiString,
             String secondaryCpuAbiString, String cpuAbiOverrideString, int uid, long vc, int
-            pkgFlags, int pkgPrivateFlags, String parentPackageName,
-            List<String> childPackageNames, String[] usesStaticLibraries,
+            pkgFlags, int pkgPrivateFlags, String[] usesStaticLibraries,
             long[] usesStaticLibraryNames) {
         PackageSetting p = mPackages.get(name);
         if (p != null) {
@@ -544,8 +546,8 @@
         }
         p = new PackageSetting(name, realName, codePath, resourcePath,
                 legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
-                cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags, parentPackageName,
-                childPackageNames, 0 /*userId*/, usesStaticLibraries, usesStaticLibraryNames);
+                cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags,
+                0 /*userId*/, usesStaticLibraries, usesStaticLibraryNames);
         p.appId = uid;
         if (registerExistingAppIdLPw(uid, p, name)) {
             mPackages.put(name, p);
@@ -607,19 +609,15 @@
             File codePath, File resourcePath, String legacyNativeLibraryPath, String primaryCpuAbi,
             String secondaryCpuAbi, long versionCode, int pkgFlags, int pkgPrivateFlags,
             UserHandle installUser, boolean allowInstall, boolean instantApp,
-            boolean virtualPreload, String parentPkgName, List<String> childPkgNames,
-            UserManagerService userManager,
+            boolean virtualPreload, UserManagerService userManager,
             String[] usesStaticLibraries, long[] usesStaticLibrariesVersions) {
         final PackageSetting pkgSetting;
         if (originalPkg != null) {
             if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package "
                     + pkgName + " is adopting original package " + originalPkg.name);
             pkgSetting = new PackageSetting(originalPkg, pkgName /*realPkgName*/);
-            pkgSetting.childPackageNames =
-                    (childPkgNames != null) ? new ArrayList<>(childPkgNames) : null;
             pkgSetting.codePath = codePath;
             pkgSetting.legacyNativeLibraryPathString = legacyNativeLibraryPath;
-            pkgSetting.parentPackageName = parentPkgName;
             pkgSetting.pkgFlags = pkgFlags;
             pkgSetting.pkgPrivateFlags = pkgPrivateFlags;
             pkgSetting.primaryCpuAbiString = primaryCpuAbi;
@@ -637,7 +635,7 @@
             pkgSetting = new PackageSetting(pkgName, realPkgName, codePath, resourcePath,
                     legacyNativeLibraryPath, primaryCpuAbi, secondaryCpuAbi,
                     null /*cpuAbiOverrideString*/, versionCode, pkgFlags, pkgPrivateFlags,
-                    parentPkgName, childPkgNames, 0 /*sharedUserId*/, usesStaticLibraries,
+                    0 /*sharedUserId*/, usesStaticLibraries,
                     usesStaticLibrariesVersions);
             pkgSetting.setTimeStamp(codePath.lastModified());
             pkgSetting.sharedUser = sharedUser;
@@ -721,7 +719,7 @@
             @NonNull File codePath, File resourcePath,
             @Nullable String legacyNativeLibraryPath, @Nullable String primaryCpuAbi,
             @Nullable String secondaryCpuAbi, int pkgFlags, int pkgPrivateFlags,
-            @Nullable List<String> childPkgNames, @NonNull UserManagerService userManager,
+            @NonNull UserManagerService userManager,
             @Nullable String[] usesStaticLibraries, @Nullable long[] usesStaticLibrariesVersions)
                     throws PackageManagerException {
         final String pkgName = pkgSetting.name;
@@ -799,9 +797,6 @@
                 pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_ODM;
         pkgSetting.primaryCpuAbiString = primaryCpuAbi;
         pkgSetting.secondaryCpuAbiString = secondaryCpuAbi;
-        if (childPkgNames != null) {
-            pkgSetting.childPackageNames = new ArrayList<>(childPkgNames);
-        }
         // Update static shared library dependencies if needed
         if (usesStaticLibraries != null && usesStaticLibrariesVersions != null
                 && usesStaticLibraries.length == usesStaticLibrariesVersions.length) {
@@ -870,15 +865,15 @@
 
     // TODO: Move to scanPackageOnlyLI() after verifying signatures are setup correctly
     // by that time.
-    void insertPackageSettingLPw(PackageSetting p, PackageParser.Package pkg) {
+    void insertPackageSettingLPw(PackageSetting p, AndroidPackage pkg) {
         // Update signatures if needed.
         if (p.signatures.mSigningDetails.signatures == null) {
-            p.signatures.mSigningDetails = pkg.mSigningDetails;
+            p.signatures.mSigningDetails = pkg.getSigningDetails();
         }
         // If this app defines a shared user id initialize
         // the shared user signatures as well.
         if (p.sharedUser != null && p.sharedUser.signatures.mSigningDetails.signatures == null) {
-            p.sharedUser.signatures.mSigningDetails = pkg.mSigningDetails;
+            p.sharedUser.signatures.mSigningDetails = pkg.getSigningDetails();
         }
         addPackageSettingLPw(p, p.sharedUser);
     }
@@ -955,7 +950,7 @@
 
         int affectedUserId = UserHandle.USER_NULL;
         // Update permissions
-        for (String eachPerm : deletedPs.pkg.requestedPermissions) {
+        for (String eachPerm : deletedPs.pkg.getRequestedPermissions()) {
             BasePermission bp = mPermissions.getPermission(eachPerm);
             if (bp == null) {
                 continue;
@@ -965,8 +960,8 @@
             boolean used = false;
             for (PackageSetting pkg : sus.packages) {
                 if (pkg.pkg != null
-                        && !pkg.pkg.packageName.equals(deletedPs.pkg.packageName)
-                        && pkg.pkg.requestedPermissions.contains(eachPerm)) {
+                        && !pkg.pkg.getPackageName().equals(deletedPs.pkg.getPackageName())
+                        && pkg.pkg.getRequestedPermissions().contains(eachPerm)) {
                     used = true;
                     break;
                 }
@@ -976,13 +971,13 @@
             }
 
             PermissionsState permissionsState = sus.getPermissionsState();
-            PackageSetting disabledPs = getDisabledSystemPkgLPr(deletedPs.pkg.packageName);
+            PackageSetting disabledPs = getDisabledSystemPkgLPr(deletedPs.pkg.getPackageName());
 
             // If the package is shadowing is a disabled system package,
             // do not drop permissions that the shadowed package requests.
             if (disabledPs != null) {
                 boolean reqByDisabledSysPkg = false;
-                for (String permission : disabledPs.pkg.requestedPermissions) {
+                for (String permission : disabledPs.pkg.getRequestedPermissions()) {
                     if (permission.equals(eachPerm)) {
                         reqByDisabledSysPkg = true;
                         break;
@@ -2215,20 +2210,6 @@
         serializer.endTag(null, TAG_PERMISSIONS);
     }
 
-    void writeChildPackagesLPw(XmlSerializer serializer, List<String> childPackageNames)
-            throws IOException {
-        if (childPackageNames == null) {
-            return;
-        }
-        final int childCount = childPackageNames.size();
-        for (int i = 0; i < childCount; i++) {
-            String childPackageName = childPackageNames.get(i);
-            serializer.startTag(null, TAG_CHILD_PACKAGE);
-            serializer.attribute(null, ATTR_NAME, childPackageName);
-            serializer.endTag(null, TAG_CHILD_PACKAGE);
-        }
-    }
-
     void readUsesStaticLibLPw(XmlPullParser parser, PackageSetting outPs)
             throws IOException, XmlPullParserException {
         int outerDepth = parser.getDepth();
@@ -2682,17 +2663,15 @@
 
             StringBuilder sb = new StringBuilder();
             for (final PackageSetting pkg : mPackages.values()) {
-                if (pkg.pkg == null || pkg.pkg.applicationInfo == null
-                        || pkg.pkg.applicationInfo.dataDir == null) {
+                if (pkg.pkg == null || pkg.pkg.getDataDir() == null) {
                     if (!"android".equals(pkg.name)) {
                         Slog.w(TAG, "Skipping " + pkg + " due to missing metadata");
                     }
                     continue;
                 }
 
-                final ApplicationInfo ai = pkg.pkg.applicationInfo;
-                final String dataPath = ai.dataDir;
-                final boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+                final String dataPath = pkg.pkg.getDataDir();
+                final boolean isDebug = (pkg.pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
                 final int[] gids = pkg.getPermissionsState().computeGids(userIds);
 
                 // Avoid any application that has a space in its path.
@@ -2717,13 +2696,13 @@
                 //   system/core/libpackagelistparser
                 //
                 sb.setLength(0);
-                sb.append(ai.packageName);
+                sb.append(pkg.pkg.getPackageName());
                 sb.append(" ");
-                sb.append(ai.uid);
+                sb.append(pkg.pkg.getUid());
                 sb.append(isDebug ? " 1 " : " 0 ");
                 sb.append(dataPath);
                 sb.append(" ");
-                sb.append(ai.seInfo);
+                sb.append(pkg.pkg.getSeInfo());
                 sb.append(" ");
                 if (gids != null && gids.length > 0) {
                     sb.append(gids[0]);
@@ -2735,9 +2714,9 @@
                     sb.append("none");
                 }
                 sb.append(" ");
-                sb.append(ai.isProfileableByShell() ? "1" : "0");
+                sb.append(pkg.pkg.isProfileableByShell() ? "1" : "0");
                 sb.append(" ");
-                sb.append(String.valueOf(ai.longVersionCode));
+                sb.append(pkg.pkg.getLongVersionCode());
                 sb.append("\n");
                 writer.append(sb);
             }
@@ -2786,12 +2765,6 @@
             serializer.attribute(null, "sharedUserId", Integer.toString(pkg.appId));
         }
 
-        if (pkg.parentPackageName != null) {
-            serializer.attribute(null, "parentPackageName", pkg.parentPackageName);
-        }
-
-        writeChildPackagesLPw(serializer, pkg.childPackageNames);
-
         writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions);
 
         // If this is a shared user, the permissions will be written there.
@@ -2861,15 +2834,10 @@
         if (pkg.categoryHint != ApplicationInfo.CATEGORY_UNDEFINED) {
             serializer.attribute(null, "categoryHint", Integer.toString(pkg.categoryHint));
         }
-        if (pkg.parentPackageName != null) {
-            serializer.attribute(null, "parentPackageName", pkg.parentPackageName);
-        }
         if (pkg.updateAvailable) {
             serializer.attribute(null, "updateAvailable", "true");
         }
 
-        writeChildPackagesLPw(serializer, pkg.childPackageNames);
-
         writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions);
 
         pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
@@ -3161,13 +3129,13 @@
                 LocalServices.getService(PackageManagerInternal.class);
         for (PackageSetting ps : mPackages.values()) {
             if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0 && ps.pkg != null
-                    && ps.pkg.preferredActivityFilters != null) {
-                ArrayList<PackageParser.ActivityIntentInfo> intents
-                        = ps.pkg.preferredActivityFilters;
+                    && ps.pkg.getPreferredActivityFilters() != null) {
+                List<ComponentParseUtils.ParsedActivityIntentInfo> intents
+                        = ps.pkg.getPreferredActivityFilters();
                 for (int i=0; i<intents.size(); i++) {
-                    PackageParser.ActivityIntentInfo aii = intents.get(i);
+                    ComponentParseUtils.ParsedActivityIntentInfo aii = intents.get(i);
                     applyDefaultPreferredActivityLPw(pmInternal, aii, new ComponentName(
-                                    ps.name, aii.activity.className), userId);
+                                    ps.name, aii.getClassName()), userId);
                 }
             }
         }
@@ -3527,7 +3495,7 @@
         PackageSetting ps = new PackageSetting(name, realName, new File(codePathStr),
                 new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiStr,
                 secondaryCpuAbiStr, cpuAbiOverrideStr, versionCode, pkgFlags, pkgPrivateFlags,
-                parentPackageName, null /*childPackageNames*/, 0 /*sharedUserId*/, null, null);
+                0 /*sharedUserId*/, null, null);
         String timeStampStr = parser.getAttributeValue(null, "ft");
         if (timeStampStr != null) {
             try {
@@ -3576,12 +3544,6 @@
 
             if (parser.getName().equals(TAG_PERMISSIONS)) {
                 readInstallPermissionsLPr(parser, ps.getPermissionsState());
-            } else if (parser.getName().equals(TAG_CHILD_PACKAGE)) {
-                String childPackageName = parser.getAttributeValue(null, ATTR_NAME);
-                if (ps.childPackageNames == null) {
-                    ps.childPackageNames = new ArrayList<>();
-                }
-                ps.childPackageNames.add(childPackageName);
             } else if (parser.getName().equals(TAG_USES_STATIC_LIB)) {
                 readUsesStaticLibLPw(parser, ps);
             } else {
@@ -3628,7 +3590,6 @@
         PackageSetting packageSetting = null;
         String version = null;
         long versionCode = 0;
-        String parentPackageName;
         try {
             name = parser.getAttributeValue(null, ATTR_NAME);
             realName = parser.getAttributeValue(null, "realName");
@@ -3640,8 +3601,6 @@
 
             legacyCpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi");
 
-            parentPackageName = parser.getAttributeValue(null, "parentPackageName");
-
             legacyNativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
             primaryCpuAbiString = parser.getAttributeValue(null, "primaryCpuAbi");
             secondaryCpuAbiString = parser.getAttributeValue(null, "secondaryCpuAbi");
@@ -3770,7 +3729,7 @@
                 packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
                         new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString,
                         secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags,
-                        pkgPrivateFlags, parentPackageName, null /*childPackageNames*/,
+                        pkgPrivateFlags,
                         null /*usesStaticLibraries*/, null /*usesStaticLibraryVersions*/);
                 if (PackageManagerService.DEBUG_SETTINGS)
                     Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId="
@@ -3789,8 +3748,8 @@
                     packageSetting = new PackageSetting(name.intern(), realName, new File(
                             codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr,
                             primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
-                            versionCode, pkgFlags, pkgPrivateFlags, parentPackageName,
-                            null /*childPackageNames*/, sharedUserId,
+                            versionCode, pkgFlags, pkgPrivateFlags,
+                            sharedUserId,
                             null /*usesStaticLibraries*/, null /*usesStaticLibraryVersions*/);
                     packageSetting.setTimeStamp(timeStamp);
                     packageSetting.firstInstallTime = firstInstallTime;
@@ -3899,12 +3858,6 @@
                     packageSetting.keySetData.addDefinedKeySet(id, alias);
                 } else if (tagName.equals(TAG_DOMAIN_VERIFICATION)) {
                     readDomainVerificationLPw(parser, packageSetting);
-                } else if (tagName.equals(TAG_CHILD_PACKAGE)) {
-                    String childPackageName = parser.getAttributeValue(null, ATTR_NAME);
-                    if (packageSetting.childPackageNames == null) {
-                        packageSetting.childPackageNames = new ArrayList<>();
-                    }
-                    packageSetting.childPackageNames.add(childPackageName);
                 } else {
                     PackageManagerService.reportSettingsProblem(Log.WARN,
                             "Unknown element under <package>: " + parser.getName());
@@ -4057,13 +4010,13 @@
             Iterator<PackageSetting> packagesIterator = packages.iterator();
             for (int i = 0; i < packagesCount; i++) {
                 PackageSetting ps = packagesIterator.next();
-                if (ps.pkg == null || ps.pkg.applicationInfo == null) {
+                if (ps.pkg == null) {
                     continue;
                 }
                 final boolean shouldInstall = ps.isSystem() &&
                         (skipPackageWhitelist || installablePackages.contains(ps.name)) &&
                         !ArrayUtils.contains(disallowedPackages, ps.name) &&
-                        !ps.pkg.applicationInfo.hiddenUntilInstalled;
+                        !ps.pkg.isHiddenUntilInstalled();
                 // Only system apps are initially installed.
                 ps.setInstalled(shouldInstall, userHandle);
                 if (!shouldInstall) {
@@ -4074,8 +4027,8 @@
                 volumeUuids[i] = ps.volumeUuid;
                 names[i] = ps.name;
                 appIds[i] = ps.appId;
-                seinfos[i] = ps.pkg.applicationInfo.seInfo;
-                targetSdkVersions[i] = ps.pkg.applicationInfo.targetSdkVersion;
+                seinfos[i] = ps.pkg.getSeInfo();
+                targetSdkVersions[i] = ps.pkg.getTargetSdkVersion();
             }
         }
         t.traceBegin("createAppData");
@@ -4185,28 +4138,6 @@
         return mVerifierDeviceIdentity;
     }
 
-    boolean hasOtherDisabledSystemPkgWithChildLPr(String parentPackageName,
-            String childPackageName) {
-        final int packageCount = mDisabledSysPackages.size();
-        for (int i = 0; i < packageCount; i++) {
-            PackageSetting disabledPs = mDisabledSysPackages.valueAt(i);
-            if (disabledPs.childPackageNames == null || disabledPs.childPackageNames.isEmpty()) {
-                continue;
-            }
-            if (disabledPs.name.equals(parentPackageName)) {
-                continue;
-            }
-            final int childCount = disabledPs.childPackageNames.size();
-            for (int j = 0; j < childCount; j++) {
-                String currChildPackageName = disabledPs.childPackageNames.get(j);
-                if (currChildPackageName.equals(childPackageName)) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
     /**
      * Returns the disabled {@link PackageSetting} for the provided package name if one exists,
      * {@code null} otherwise.
@@ -4229,26 +4160,6 @@
         return getDisabledSystemPkgLPr(enabledPackageSetting.name);
     }
 
-    /**
-     * Fetches an array of the child {@link PackageSetting}s for all child package names referenced
-     * by the provided parent {@link PackageSetting} or {@code null} if no children are referenced.
-     *
-     * Note: Any child packages not found will be null in the returned array.
-     */
-    @Nullable
-    public PackageSetting[] getChildSettingsLPr(PackageSetting parentPackageSetting) {
-        if (parentPackageSetting == null || !parentPackageSetting.hasChildPackages()) {
-            return null;
-        }
-        final int childCount = parentPackageSetting.childPackageNames.size();
-        PackageSetting[] children =
-                new PackageSetting[childCount];
-        for (int i = 0; i < childCount; i++) {
-            children[i] = mPackages.get(parentPackageSetting.childPackageNames.get(i));
-        }
-        return children;
-    }
-
     boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, int flags, int userId) {
         final PackageSetting ps = mPackages.get(componentInfo.packageName);
         if (ps == null) return false;
@@ -4257,12 +4168,13 @@
         return userState.isMatch(componentInfo, flags);
     }
 
-    String getInstallerPackageNameLPr(String packageName) {
-        final PackageSetting pkg = mPackages.get(packageName);
-        if (pkg == null) {
-            throw new IllegalArgumentException("Unknown package: " + packageName);
-        }
-        return pkg.installSource.installerPackageName;
+    boolean isEnabledAndMatchLPr(AndroidPackage pkg, ParsedComponent component, int flags,
+            int userId) {
+        final PackageSetting ps = mPackages.get(component.getPackageName());
+        if (ps == null) return false;
+
+        final PackageUserState userState = ps.readUserState(userId);
+        return userState.isMatch(pkg.isSystem(), pkg.isEnabled(), component, flags);
     }
 
     boolean isOrphaned(String packageName) {
@@ -4475,6 +4387,7 @@
     void dumpPackageLPr(PrintWriter pw, String prefix, String checkinTag,
             ArraySet<String> permissionNames, PackageSetting ps, SimpleDateFormat sdf,
             Date date, List<UserInfo> users, boolean dumpAll, boolean dumpAllComponents) {
+        AndroidPackage pkg = ps.pkg;
         if (checkinTag != null) {
             pw.print(checkinTag);
             pw.print(",");
@@ -4491,15 +4404,16 @@
             pw.print(ps.installSource.installerPackageName != null
                     ? ps.installSource.installerPackageName : "?");
             pw.println();
-            if (ps.pkg != null) {
+            if (pkg != null) {
                 pw.print(checkinTag); pw.print("-"); pw.print("splt,");
                 pw.print("base,");
-                pw.println(ps.pkg.baseRevisionCode);
-                if (ps.pkg.splitNames != null) {
-                    for (int i = 0; i < ps.pkg.splitNames.length; i++) {
+                pw.println(pkg.getBaseRevisionCode());
+                if (pkg.getSplitNames() != null) {
+                    int[] splitRevisionCodes = pkg.getSplitRevisionCodes();
+                    for (int i = 0; i < pkg.getSplitNames().length; i++) {
                         pw.print(checkinTag); pw.print("-"); pw.print("splt,");
-                        pw.print(ps.pkg.splitNames[i]); pw.print(",");
-                        pw.println(ps.pkg.splitRevisionCodes[i]);
+                        pw.print(pkg.getSplitNames()[i]); pw.print(",");
+                        pw.println(splitRevisionCodes[i]);
                     }
                 }
             }
@@ -4546,7 +4460,7 @@
         if (ps.sharedUser != null) {
             pw.print(prefix); pw.print("  sharedUser="); pw.println(ps.sharedUser);
         }
-        pw.print(prefix); pw.print("  pkg="); pw.println(ps.pkg);
+        pw.print(prefix); pw.print("  pkg="); pw.println(pkg);
         pw.print(prefix); pw.print("  codePath="); pw.println(ps.codePathString);
         if (permissionNames == null) {
             pw.print(prefix); pw.print("  resourcePath="); pw.println(ps.resourcePathString);
@@ -4556,140 +4470,123 @@
             pw.print(prefix); pw.print("  secondaryCpuAbi="); pw.println(ps.secondaryCpuAbiString);
         }
         pw.print(prefix); pw.print("  versionCode="); pw.print(ps.versionCode);
-        if (ps.pkg != null) {
-            pw.print(" minSdk="); pw.print(ps.pkg.applicationInfo.minSdkVersion);
-            pw.print(" targetSdk="); pw.print(ps.pkg.applicationInfo.targetSdkVersion);
+        if (pkg != null) {
+            pw.print(" minSdk="); pw.print(pkg.getMinSdkVersion());
+            pw.print(" targetSdk="); pw.print(pkg.getTargetSdkVersion());
         }
         pw.println();
-        if (ps.pkg != null) {
-            if (ps.pkg.parentPackage != null) {
-                PackageParser.Package parentPkg = ps.pkg.parentPackage;
-                PackageSetting pps = mPackages.get(parentPkg.packageName);
-                if (pps == null || !pps.codePathString.equals(parentPkg.codePath)) {
-                    pps = mDisabledSysPackages.get(parentPkg.packageName);
-                }
-                if (pps != null) {
-                    pw.print(prefix); pw.print("  parentPackage=");
-                    pw.println(pps.realName != null ? pps.realName : pps.name);
-                }
-            } else if (ps.pkg.childPackages != null) {
-                pw.print(prefix); pw.print("  childPackages=[");
-                final int childCount = ps.pkg.childPackages.size();
-                for (int i = 0; i < childCount; i++) {
-                    PackageParser.Package childPkg = ps.pkg.childPackages.get(i);
-                    PackageSetting cps = mPackages.get(childPkg.packageName);
-                    if (cps == null || !cps.codePathString.equals(childPkg.codePath)) {
-                        cps = mDisabledSysPackages.get(childPkg.packageName);
-                    }
-                    if (cps != null) {
-                        if (i > 0) {
-                            pw.print(", ");
-                        }
-                        pw.print(cps.realName != null ? cps.realName : cps.name);
-                    }
-                }
-                pw.println("]");
-            }
-            pw.print(prefix); pw.print("  versionName="); pw.println(ps.pkg.mVersionName);
-            pw.print(prefix); pw.print("  splits="); dumpSplitNames(pw, ps.pkg); pw.println();
-            final int apkSigningVersion = ps.pkg.mSigningDetails.signatureSchemeVersion;
+        if (pkg != null) {
+            pw.print(prefix); pw.print("  versionName="); pw.println(pkg.getVersionName());
+            pw.print(prefix); pw.print("  splits="); dumpSplitNames(pw, pkg); pw.println();
+            final int apkSigningVersion = pkg.getSigningDetails().signatureSchemeVersion;
             pw.print(prefix); pw.print("  apkSigningVersion="); pw.println(apkSigningVersion);
+            // TODO(b/135203078): Is there anything to print here with AppInfo removed?
             pw.print(prefix); pw.print("  applicationInfo=");
-                pw.println(ps.pkg.applicationInfo.toString());
-            pw.print(prefix); pw.print("  flags="); printFlags(pw, ps.pkg.applicationInfo.flags,
+            pw.println(pkg.toAppInfoWithoutState().toString());
+            pw.print(prefix); pw.print("  flags="); printFlags(pw, pkg.getFlags(),
                     FLAG_DUMP_SPEC); pw.println();
-            if (ps.pkg.applicationInfo.privateFlags != 0) {
+            if (pkg.getPrivateFlags() != 0) {
                 pw.print(prefix); pw.print("  privateFlags="); printFlags(pw,
-                        ps.pkg.applicationInfo.privateFlags, PRIVATE_FLAG_DUMP_SPEC); pw.println();
+                        pkg.getPrivateFlags(), PRIVATE_FLAG_DUMP_SPEC); pw.println();
             }
-            pw.print(prefix); pw.print("  forceQueryable="); pw.println(ps.pkg.mForceQueryable);
-            if (ps.pkg.mQueriesPackages != null) {
-                pw.append(prefix).append("  queriesPackages=").println(ps.pkg.mQueriesPackages);
+            pw.print(prefix); pw.print("  forceQueryable="); pw.println(ps.pkg.isForceQueryable());
+            if (ps.pkg.getQueriesPackages() != null) {
+                pw.append(prefix).append("  queriesPackages=").println(ps.pkg.getQueriesPackages());
             }
-            if (ps.pkg.mQueriesIntents != null) {
-                pw.append(prefix).append("  queriesIntents=").println(ps.pkg.mQueriesIntents);
+            if (ps.pkg.getQueriesIntents() != null) {
+                pw.append(prefix).append("  queriesIntents=").println(ps.pkg.getQueriesIntents());
             }
-            pw.print(prefix); pw.print("  dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
+            pw.print(prefix); pw.print("  dataDir="); pw.println(ps.pkg.getDataDir());
             pw.print(prefix); pw.print("  supportsScreens=[");
             boolean first = true;
-            if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) {
+            if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) {
                 if (!first)
                     pw.print(", ");
                 first = false;
                 pw.print("small");
             }
-            if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) {
+            if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) {
                 if (!first)
                     pw.print(", ");
                 first = false;
                 pw.print("medium");
             }
-            if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
+            if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
                 if (!first)
                     pw.print(", ");
                 first = false;
                 pw.print("large");
             }
-            if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
+            if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
                 if (!first)
                     pw.print(", ");
                 first = false;
                 pw.print("xlarge");
             }
-            if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
+            if ((pkg.getFlags() & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
                 if (!first)
                     pw.print(", ");
                 first = false;
                 pw.print("resizeable");
             }
-            if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
+            if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
                 if (!first)
                     pw.print(", ");
                 first = false;
                 pw.print("anyDensity");
             }
             pw.println("]");
-            if (ps.pkg.libraryNames != null && ps.pkg.libraryNames.size() > 0) {
+            List<String> libraryNames = pkg.getLibraryNames();
+            if (libraryNames != null && libraryNames.size() > 0) {
                 pw.print(prefix); pw.println("  dynamic libraries:");
-                for (int i = 0; i<ps.pkg.libraryNames.size(); i++) {
+                for (int i = 0; i< libraryNames.size(); i++) {
                     pw.print(prefix); pw.print("    ");
-                            pw.println(ps.pkg.libraryNames.get(i));
+                            pw.println(libraryNames.get(i));
                 }
             }
-            if (ps.pkg.staticSharedLibName != null) {
+            if (pkg.getStaticSharedLibName() != null) {
                 pw.print(prefix); pw.println("  static library:");
                 pw.print(prefix); pw.print("    ");
-                pw.print("name:"); pw.print(ps.pkg.staticSharedLibName);
-                pw.print(" version:"); pw.println(ps.pkg.staticSharedLibVersion);
+                pw.print("name:"); pw.print(pkg.getStaticSharedLibName());
+                pw.print(" version:"); pw.println(pkg.getStaticSharedLibVersion());
             }
-            if (ps.pkg.usesLibraries != null && ps.pkg.usesLibraries.size() > 0) {
+
+            List<String> usesLibraries = pkg.getUsesLibraries();
+            if (usesLibraries != null && usesLibraries.size() > 0) {
                 pw.print(prefix); pw.println("  usesLibraries:");
-                for (int i=0; i<ps.pkg.usesLibraries.size(); i++) {
-                    pw.print(prefix); pw.print("    "); pw.println(ps.pkg.usesLibraries.get(i));
+                for (int i=0; i< usesLibraries.size(); i++) {
+                    pw.print(prefix); pw.print("    "); pw.println(usesLibraries.get(i));
                 }
             }
-            if (ps.pkg.usesStaticLibraries != null
-                    && ps.pkg.usesStaticLibraries.size() > 0) {
+
+            List<String> usesStaticLibraries = pkg.getUsesStaticLibraries();
+            long[] usesStaticLibrariesVersions = pkg.getUsesStaticLibrariesVersions();
+            if (usesStaticLibraries != null
+                    && usesStaticLibraries.size() > 0) {
                 pw.print(prefix); pw.println("  usesStaticLibraries:");
-                for (int i=0; i<ps.pkg.usesStaticLibraries.size(); i++) {
+                for (int i=0; i< usesStaticLibraries.size(); i++) {
                     pw.print(prefix); pw.print("    ");
-                    pw.print(ps.pkg.usesStaticLibraries.get(i)); pw.print(" version:");
-                            pw.println(ps.pkg.usesStaticLibrariesVersions[i]);
+                    pw.print(usesStaticLibraries.get(i)); pw.print(" version:");
+                            pw.println(usesStaticLibrariesVersions[i]);
                 }
             }
-            if (ps.pkg.usesOptionalLibraries != null
-                    && ps.pkg.usesOptionalLibraries.size() > 0) {
+
+            List<String> usesOptionalLibraries = pkg.getUsesOptionalLibraries();
+            if (usesOptionalLibraries != null
+                    && usesOptionalLibraries.size() > 0) {
                 pw.print(prefix); pw.println("  usesOptionalLibraries:");
-                for (int i=0; i<ps.pkg.usesOptionalLibraries.size(); i++) {
+                for (int i=0; i< usesOptionalLibraries.size(); i++) {
                     pw.print(prefix); pw.print("    ");
-                    pw.println(ps.pkg.usesOptionalLibraries.get(i));
+                    pw.println(usesOptionalLibraries.get(i));
                 }
             }
-            if (ps.pkg.usesLibraryFiles != null
-                    && ps.pkg.usesLibraryFiles.length > 0) {
+
+            String[] usesLibraryFiles = pkg.getUsesLibraryFiles();
+            if (usesLibraryFiles != null
+                    && usesLibraryFiles.length > 0) {
                 pw.print(prefix); pw.println("  usesLibraryFiles:");
-                for (int i=0; i<ps.pkg.usesLibraryFiles.length; i++) {
-                    pw.print(prefix); pw.print("    "); pw.println(ps.pkg.usesLibraryFiles[i]);
+                for (int i=0; i< usesLibraryFiles.length; i++) {
+                    pw.print(prefix); pw.print("    "); pw.println(usesLibraryFiles[i]);
                 }
             }
         }
@@ -4717,40 +4614,40 @@
         pw.print(prefix); pw.print("  pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC);
                 pw.println();
 
-        if (ps.pkg != null && ps.pkg.mOverlayTarget != null) {
-            pw.print(prefix); pw.print("  overlayTarget="); pw.println(ps.pkg.mOverlayTarget);
-            pw.print(prefix); pw.print("  overlayCategory="); pw.println(ps.pkg.mOverlayCategory);
+        if (pkg != null && pkg.getOverlayTarget() != null) {
+            pw.print(prefix); pw.print("  overlayTarget="); pw.println(pkg.getOverlayTarget());
+            pw.print(prefix); pw.print("  overlayCategory="); pw.println(pkg.getOverlayCategory());
         }
 
-        if (ps.pkg != null && ps.pkg.permissions != null && ps.pkg.permissions.size() > 0) {
-            final ArrayList<PackageParser.Permission> perms = ps.pkg.permissions;
+        if (pkg != null && pkg.getPermissions() != null && pkg.getPermissions().size() > 0) {
+            final List<ParsedPermission> perms = pkg.getPermissions();
             pw.print(prefix); pw.println("  declared permissions:");
             for (int i=0; i<perms.size(); i++) {
-                PackageParser.Permission perm = perms.get(i);
+                ParsedPermission perm = perms.get(i);
                 if (permissionNames != null
-                        && !permissionNames.contains(perm.info.name)) {
+                        && !permissionNames.contains(perm.getName())) {
                     continue;
                 }
-                pw.print(prefix); pw.print("    "); pw.print(perm.info.name);
+                pw.print(prefix); pw.print("    "); pw.print(perm.getName());
                 pw.print(": prot=");
-                pw.print(PermissionInfo.protectionToString(perm.info.protectionLevel));
-                if ((perm.info.flags&PermissionInfo.FLAG_COSTS_MONEY) != 0) {
+                pw.print(PermissionInfo.protectionToString(perm.protectionLevel));
+                if ((perm.flags&PermissionInfo.FLAG_COSTS_MONEY) != 0) {
                     pw.print(", COSTS_MONEY");
                 }
-                if ((perm.info.flags&PermissionInfo.FLAG_REMOVED) != 0) {
+                if ((perm.flags&PermissionInfo.FLAG_REMOVED) != 0) {
                     pw.print(", HIDDEN");
                 }
-                if ((perm.info.flags&PermissionInfo.FLAG_INSTALLED) != 0) {
+                if ((perm.flags&PermissionInfo.FLAG_INSTALLED) != 0) {
                     pw.print(", INSTALLED");
                 }
                 pw.println();
             }
         }
 
-        if ((permissionNames != null || dumpAll) && ps.pkg != null
-                && ps.pkg.requestedPermissions != null
-                && ps.pkg.requestedPermissions.size() > 0) {
-            final ArrayList<String> perms = ps.pkg.requestedPermissions;
+        if ((permissionNames != null || dumpAll) && pkg != null
+                && pkg.getRequestedPermissions() != null
+                && pkg.getRequestedPermissions().size() > 0) {
+            final List<String> perms = pkg.getRequestedPermissions();
             pw.print(prefix); pw.println("  requested permissions:");
             for (int i=0; i<perms.size(); i++) {
                 String perm = perms.get(i);
@@ -4942,7 +4839,7 @@
         final int count = mPackages.size();
         for (int i = 0; i < count; i++) {
             final PackageSetting ps = mPackages.valueAt(i);
-            ps.writeToProto(proto, PackageServiceDumpProto.PACKAGES, users);
+            ps.dumpDebug(proto, PackageServiceDumpProto.PACKAGES, users);
         }
     }
 
@@ -5018,7 +4915,7 @@
     void dumpSharedUsersProto(ProtoOutputStream proto) {
         final int count = mSharedUsers.size();
         for (int i = 0; i < count; i++) {
-            mSharedUsers.valueAt(i).writeToProto(proto, PackageServiceDumpProto.SHARED_USERS);
+            mSharedUsers.valueAt(i).dumpDebug(proto, PackageServiceDumpProto.SHARED_USERS);
         }
     }
 
@@ -5027,22 +4924,24 @@
         pw.print(mReadMessages.toString());
     }
 
-    private static void dumpSplitNames(PrintWriter pw, PackageParser.Package pkg) {
+    private static void dumpSplitNames(PrintWriter pw, AndroidPackage pkg) {
         if (pkg == null) {
             pw.print("unknown");
         } else {
             // [base:10, config.mdpi, config.xhdpi:12]
             pw.print("[");
             pw.print("base");
-            if (pkg.baseRevisionCode != 0) {
-                pw.print(":"); pw.print(pkg.baseRevisionCode);
+            if (pkg.getBaseRevisionCode() != 0) {
+                pw.print(":"); pw.print(pkg.getBaseRevisionCode());
             }
-            if (pkg.splitNames != null) {
-                for (int i = 0; i < pkg.splitNames.length; i++) {
+            String[] splitNames = pkg.getSplitNames();
+            int[] splitRevisionCodes = pkg.getSplitRevisionCodes();
+            if (splitNames != null) {
+                for (int i = 0; i < splitNames.length; i++) {
                     pw.print(", ");
-                    pw.print(pkg.splitNames[i]);
-                    if (pkg.splitRevisionCodes[i] != 0) {
-                        pw.print(":"); pw.print(pkg.splitRevisionCodes[i]);
+                    pw.print(splitNames[i]);
+                    if (splitRevisionCodes[i] != 0) {
+                        pw.print(":"); pw.print(splitRevisionCodes[i]);
                     }
                 }
             }
@@ -5118,22 +5017,23 @@
     }
 
     void dumpComponents(PrintWriter pw, String prefix, PackageSetting ps) {
-        dumpComponents(pw, prefix, ps, "activities:", ps.pkg.activities);
-        dumpComponents(pw, prefix, ps, "services:", ps.pkg.services);
-        dumpComponents(pw, prefix, ps, "receivers:", ps.pkg.receivers);
-        dumpComponents(pw, prefix, ps, "providers:", ps.pkg.providers);
-        dumpComponents(pw, prefix, ps, "instrumentations:", ps.pkg.instrumentation);
+        // TODO(b/135203078): ParsedComponent toString methods for dumping
+        dumpComponents(pw, prefix, "activities:", ps.pkg.getActivities());
+        dumpComponents(pw, prefix, "services:", ps.pkg.getServices());
+        dumpComponents(pw, prefix, "receivers:", ps.pkg.getReceivers());
+        dumpComponents(pw, prefix, "providers:", ps.pkg.getProviders());
+        dumpComponents(pw, prefix, "instrumentations:", ps.pkg.getInstrumentations());
     }
 
-    void dumpComponents(PrintWriter pw, String prefix, PackageSetting ps,
-            String label, List<? extends PackageParser.Component<?>> list) {
+    void dumpComponents(PrintWriter pw, String prefix, String label,
+            List<? extends ParsedComponent> list) {
         final int size = CollectionUtils.size(list);
         if (size == 0) {
             return;
         }
         pw.print(prefix);pw.println(label);
         for (int i = 0; i < size; i++) {
-            final PackageParser.Component<?> component = list.get(i);
+            final ParsedComponent component = list.get(i);
             pw.print(prefix);pw.print("  ");
             pw.println(component.getComponentName().flattenToShortString());
         }
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index 2ee07a2..0a42ccf 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -18,7 +18,7 @@
 
 import android.annotation.Nullable;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
 import android.service.pm.PackageServiceDumpProto;
 import android.util.ArraySet;
 import android.util.proto.ProtoOutputStream;
@@ -46,7 +46,7 @@
     // that all apps within the sharedUser run in the same selinux context.
     int seInfoTargetSdkVersion;
 
-    final ArraySet<PackageSetting> packages = new ArraySet<PackageSetting>();
+    final ArraySet<PackageSetting> packages = new ArraySet<>();
 
     final PackageSignatures signatures = new PackageSignatures();
     Boolean signaturesChanged;
@@ -65,7 +65,7 @@
                 + name + "/" + userId + "}";
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         long token = proto.start(fieldId);
         proto.write(PackageServiceDumpProto.SharedUserProto.UID, userId);
         proto.write(PackageServiceDumpProto.SharedUserProto.NAME, name);
@@ -98,7 +98,7 @@
         // If this is the first package added to this shared user, temporarily (until next boot) use
         // its targetSdkVersion when assigning seInfo for the shared user.
         if ((packages.size() == 0) && (packageSetting.pkg != null)) {
-            seInfoTargetSdkVersion = packageSetting.pkg.applicationInfo.targetSdkVersion;
+            seInfoTargetSdkVersion = packageSetting.pkg.getTargetSdkVersion();
         }
         if (packages.add(packageSetting)) {
             setFlags(this.pkgFlags | packageSetting.pkgFlags);
@@ -106,11 +106,11 @@
         }
     }
 
-    public @Nullable List<PackageParser.Package> getPackages() {
+    public @Nullable List<AndroidPackage> getPackages() {
         if (packages == null || packages.size() == 0) {
             return null;
         }
-        final ArrayList<PackageParser.Package> pkgList = new ArrayList<>(packages.size());
+        final ArrayList<AndroidPackage> pkgList = new ArrayList<>(packages.size());
         for (PackageSetting ps : packages) {
             if ((ps == null) || (ps.pkg == null)) {
                 continue;
@@ -131,20 +131,20 @@
      * restrictive selinux domain.
      */
     public void fixSeInfoLocked() {
-        final List<PackageParser.Package> pkgList = getPackages();
+        final List<AndroidPackage> pkgList = getPackages();
         if (pkgList == null || pkgList.size() == 0) {
             return;
         }
 
-        for (PackageParser.Package pkg : pkgList) {
-            if (pkg.applicationInfo.targetSdkVersion < seInfoTargetSdkVersion) {
-                seInfoTargetSdkVersion = pkg.applicationInfo.targetSdkVersion;
+        for (AndroidPackage pkg : pkgList) {
+            if (pkg.getTargetSdkVersion() < seInfoTargetSdkVersion) {
+                seInfoTargetSdkVersion = pkg.getTargetSdkVersion();
             }
         }
-        for (PackageParser.Package pkg : pkgList) {
+        for (AndroidPackage pkg : pkgList) {
             final boolean isPrivileged = isPrivileged() | pkg.isPrivileged();
-            pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, isPrivileged,
-                seInfoTargetSdkVersion);
+            pkg.mutate().setSeInfo(SELinuxMMAC.getSeInfo(pkg, isPrivileged,
+                    seInfoTargetSdkVersion));
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 27eefc6..7ea4e98 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -620,32 +620,6 @@
                             PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
                             "Cannot stage multiple sessions without checkpoint support", null);
                 }
-
-                // TODO:b/141843321 Add support for staging multiple sessions in apexd
-                // Since apexd doesn't support multiple staged sessions yet, we have to careful how
-                // we handle apex sessions. We want to allow a set of apex sessions under the same
-                // parent to be staged when there is no previously staged apex sessions.
-                if (isApexSession(session) && isApexSession(stagedSession)) {
-                    // session is apex and it can co-exist with stagedSession only if they are from
-                    // same parent
-                    final boolean coExist;
-                    if (!session.hasParentSessionId() && !stagedSession.hasParentSessionId()) {
-                        // Both single package apex sessions. Cannot co-exist.
-                        coExist = false;
-                    } else {
-                        // At least one of the session has parent. Both must be from same parent.
-                        coExist =
-                                session.getParentSessionId() == stagedSession.getParentSessionId();
-                    }
-                    if (!coExist) {
-                        throw new PackageManagerException(
-                                PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
-                                "Package: " + session.getPackageName() + " in session: "
-                                        + session.sessionId + " cannot be staged as there is "
-                                        + "already another apex staged session: "
-                                        + stagedSession.sessionId, null);
-                    }
-                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 8144338..ad4411c 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1634,13 +1634,14 @@
      * See {@link UserManagerInternal#setDevicePolicyUserRestrictions}
      */
     private void setDevicePolicyUserRestrictionsInner(@UserIdInt int userId,
-            @Nullable Bundle restrictions, boolean isDeviceOwner, int cameraRestrictionScope) {
+            @Nullable Bundle restrictions,
+            @UserManagerInternal.OwnerType int restrictionOwnerType) {
         final Bundle global = new Bundle();
         final Bundle local = new Bundle();
 
         // Sort restrictions into local and global ensuring they don't overlap.
-        UserRestrictionsUtils.sortToGlobalAndLocal(restrictions, isDeviceOwner,
-                cameraRestrictionScope, global, local);
+        UserRestrictionsUtils.sortToGlobalAndLocal(restrictions, restrictionOwnerType, global,
+                local);
 
         boolean globalChanged, localChanged;
         synchronized (mRestrictionsLock) {
@@ -1650,7 +1651,7 @@
             localChanged = updateRestrictionsIfNeededLR(
                     userId, local, mDevicePolicyLocalUserRestrictions);
 
-            if (isDeviceOwner) {
+            if (restrictionOwnerType == UserManagerInternal.OWNER_TYPE_DEVICE_OWNER) {
                 // Remember the global restriction owner userId to be able to make a distinction
                 // in getUserRestrictionSource on who set local policies.
                 mDeviceOwnerUserId = userId;
@@ -3106,36 +3107,11 @@
             }
         }
 
-        // First try to use a pre-created user (if available).
-        // TODO(b/142482943): Move this to its own function later.
-        if (!preCreate
-                && (parentId < 0 && isUserTypeEligibleForPreCreation(userTypeDetails))) {
-            final UserData preCreatedUserData;
-            synchronized (mUsersLock) {
-                preCreatedUserData = getPreCreatedUserLU(userType);
-            }
-            if (preCreatedUserData != null) {
-                final UserInfo preCreatedUser = preCreatedUserData.info;
-                final int newFlags = preCreatedUser.flags | flags;
-                if (!checkUserTypeConsistency(newFlags)) {
-                    Slog.wtf(LOG_TAG, "Cannot reuse pre-created user " + preCreatedUser.id
-                            + " of type " + userType + " because flags are inconsistent. "
-                            + "Flags (" + Integer.toHexString(flags) + "); preCreatedUserFlags ( "
-                            + Integer.toHexString(preCreatedUser.flags) + ").");
-                } else {
-                    Log.i(LOG_TAG, "Reusing pre-created user " + preCreatedUser.id + " of type "
-                            + userType + " and bestowing on it flags "
-                            + UserInfo.flagsToString(flags));
-                    preCreatedUser.name = name;
-                    preCreatedUser.flags = newFlags;
-                    preCreatedUser.preCreated = false;
-                    preCreatedUser.creationTime = getCreationTime();
-
-                    dispatchUserAddedIntent(preCreatedUser);
-                    writeUserLP(preCreatedUserData);
-                    writeUserListLP();
-                    return preCreatedUser;
-                }
+        // Try to use a pre-created user (if available).
+        if (!preCreate && parentId < 0 && isUserTypeEligibleForPreCreation(userTypeDetails)) {
+            final UserInfo preCreatedUser = convertPreCreatedUserIfPossible(userType, flags, name);
+            if (preCreatedUser != null) {
+                return preCreatedUser;
             }
         }
 
@@ -3209,6 +3185,13 @@
                         flags |= UserInfo.FLAG_EPHEMERAL;
                     }
 
+                    // Always clear EPHEMERAL for pre-created users, otherwise the storage key
+                    // won't be persisted. The flag will be re-added (if needed) when the
+                    // pre-created user is "converted" to a normal user.
+                    if (preCreate) {
+                        flags &= ~UserInfo.FLAG_EPHEMERAL;
+                    }
+
                     userInfo = new UserInfo(userId, name, null, flags, userType);
                     userInfo.serialNumber = mNextSerialNumber++;
                     userInfo.creationTime = getCreationTime();
@@ -3312,6 +3295,44 @@
         return userInfo;
     }
 
+    /**
+     * Finds and converts a previously pre-created user into a regular user, if possible.
+     *
+     * @return the converted user, or {@code null} if no pre-created user could be converted.
+     */
+    private @Nullable UserInfo convertPreCreatedUserIfPossible(String userType,
+            @UserInfoFlag int flags, String name) {
+        final UserData preCreatedUserData;
+        synchronized (mUsersLock) {
+            preCreatedUserData = getPreCreatedUserLU(userType);
+        }
+        if (preCreatedUserData == null) {
+            return null;
+        }
+        final UserInfo preCreatedUser = preCreatedUserData.info;
+        final int newFlags = preCreatedUser.flags | flags;
+        if (!checkUserTypeConsistency(newFlags)) {
+            Slog.wtf(LOG_TAG, "Cannot reuse pre-created user " + preCreatedUser.id
+                    + " of type " + userType + " because flags are inconsistent. "
+                    + "Flags (" + Integer.toHexString(flags) + "); preCreatedUserFlags ( "
+                    + Integer.toHexString(preCreatedUser.flags) + ").");
+            return null;
+        }
+        Log.i(LOG_TAG, "Reusing pre-created user " + preCreatedUser.id + " of type "
+                + userType + " and bestowing on it flags " + UserInfo.flagsToString(flags));
+        preCreatedUser.name = name;
+        preCreatedUser.flags = newFlags;
+        preCreatedUser.preCreated = false;
+        preCreatedUser.creationTime = getCreationTime();
+
+        dispatchUserAddedIntent(preCreatedUser);
+        synchronized (mPackagesLock) {
+            writeUserLP(preCreatedUserData);
+            writeUserListLP();
+        }
+        return preCreatedUser;
+    }
+
     /** Checks that the flags do not contain mutually exclusive types/properties. */
     static boolean checkUserTypeConsistency(@UserInfoFlag int flags) {
         // Mask to check that flags don't refer to multiple user types.
@@ -3431,8 +3452,13 @@
     /**
      * Find the current guest user. If the Guest user is partial,
      * then do not include it in the results as it is about to die.
+     *
+     * @return The current guest user.  Null if it doesn't exist.
+     * @hide
      */
-    private UserInfo findCurrentGuestUser() {
+    @Override
+    public UserInfo findCurrentGuestUser() {
+        checkManageUsersPermission("findCurrentGuestUser");
         synchronized (mUsersLock) {
             final int size = mUsers.size();
             for (int i = 0; i < size; i++) {
@@ -4427,6 +4453,7 @@
         pw.println("  Supports switchable users: " + UserManager.supportsMultipleUsers());
         pw.println("  All guests ephemeral: " + Resources.getSystem().getBoolean(
                 com.android.internal.R.bool.config_guestUserEphemeral));
+        pw.println("  Force ephemeral users: " + mForceEphemeralUsers);
         pw.println("  Is split-system user: " + UserManager.isSplitSystemUser());
         pw.println("  Is headless-system mode: " + UserManager.isHeadlessSystemUserMode());
         pw.println("  User version: " + mUserVersion);
@@ -4484,9 +4511,9 @@
     private class LocalService extends UserManagerInternal {
         @Override
         public void setDevicePolicyUserRestrictions(@UserIdInt int userId,
-                @Nullable Bundle restrictions, boolean isDeviceOwner, int cameraRestrictionScope) {
-            UserManagerService.this.setDevicePolicyUserRestrictionsInner(userId, restrictions,
-                isDeviceOwner, cameraRestrictionScope);
+                @Nullable Bundle restrictions, @OwnerType int restrictionOwnerType) {
+            UserManagerService.this.setDevicePolicyUserRestrictionsInner(userId,
+                    restrictions, restrictionOwnerType);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 3be51c5..0beff7a 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -20,7 +20,6 @@
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.AppGlobals;
-import android.app.admin.DevicePolicyManager;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
@@ -194,7 +193,18 @@
             UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS,
             UserManager.DISALLOW_RUN_IN_BACKGROUND,
             UserManager.DISALLOW_UNMUTE_MICROPHONE,
-            UserManager.DISALLOW_UNMUTE_DEVICE
+            UserManager.DISALLOW_UNMUTE_DEVICE,
+            UserManager.DISALLOW_CAMERA
+    );
+
+    /**
+     * Special user restrictions that are applied globally when set by the profile owner of a
+     * managed profile that was created during the device provisioning flow.
+     */
+    private static final Set<String> PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS =
+            Sets.newArraySet(
+                    UserManager.DISALLOW_CONFIG_DATE_TIME,
+                    UserManager.DISALLOW_CAMERA
     );
 
     /**
@@ -419,15 +429,9 @@
      * Takes restrictions that can be set by device owner, and sort them into what should be applied
      * globally and what should be applied only on the current user.
      */
-    public static void sortToGlobalAndLocal(@Nullable Bundle in, boolean isDeviceOwner,
-            int cameraRestrictionScope,
-            @NonNull Bundle global, @NonNull Bundle local) {
-        // Camera restriction (as well as all others) goes to at most one bundle.
-        if (cameraRestrictionScope == UserManagerInternal.CAMERA_DISABLED_GLOBALLY) {
-            global.putBoolean(UserManager.DISALLOW_CAMERA, true);
-        } else if (cameraRestrictionScope == UserManagerInternal.CAMERA_DISABLED_LOCALLY) {
-            local.putBoolean(UserManager.DISALLOW_CAMERA, true);
-        }
+    public static void sortToGlobalAndLocal(@Nullable Bundle in,
+            @UserManagerInternal.OwnerType int restrictionOwnerType, @NonNull Bundle global,
+            @NonNull Bundle local) {
         if (in == null || in.size() == 0) {
             return;
         }
@@ -435,7 +439,7 @@
             if (!in.getBoolean(key)) {
                 continue;
             }
-            if (isGlobal(isDeviceOwner, key)) {
+            if (isGlobal(restrictionOwnerType, key)) {
                 global.putBoolean(key, true);
             } else {
                 local.putBoolean(key, true);
@@ -446,9 +450,13 @@
     /**
      * Whether given user restriction should be enforced globally.
      */
-    private static boolean isGlobal(boolean isDeviceOwner, String key) {
-        return (isDeviceOwner &&
-                (PRIMARY_USER_ONLY_RESTRICTIONS.contains(key) || GLOBAL_RESTRICTIONS.contains(key)))
+    private static boolean isGlobal(@UserManagerInternal.OwnerType int restrictionOwnerType,
+            String key) {
+        return ((restrictionOwnerType == UserManagerInternal.OWNER_TYPE_DEVICE_OWNER) && (
+                PRIMARY_USER_ONLY_RESTRICTIONS.contains(key) || GLOBAL_RESTRICTIONS.contains(key)))
+                || ((restrictionOwnerType
+                == UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE)
+                && PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS.contains(key))
                 || PROFILE_GLOBAL_RESTRICTIONS.contains(key)
                 || DEVICE_OWNER_ONLY_RESTRICTIONS.contains(key);
     }
@@ -569,10 +577,6 @@
                     if (newValue) {
                         android.provider.Settings.Global.putStringForUser(
                                 context.getContentResolver(),
-                                android.provider.Settings.Global.PACKAGE_VERIFIER_ENABLE, "1",
-                                userId);
-                        android.provider.Settings.Global.putStringForUser(
-                                context.getContentResolver(),
                                 android.provider.Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, "1",
                                 userId);
                     }
@@ -708,7 +712,6 @@
                 restriction = UserManager.DISALLOW_DEBUGGING_FEATURES;
                 break;
 
-            case android.provider.Settings.Global.PACKAGE_VERIFIER_ENABLE:
             case android.provider.Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB:
                 if ("1".equals(value)) {
                     return false;
@@ -773,16 +776,6 @@
                 break;
 
             case android.provider.Settings.Global.AUTO_TIME:
-                DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
-                if (dpm != null && dpm.getAutoTimeRequired()
-                        && "0".equals(value)) {
-                    return true;
-                } else if (callingUid == Process.SYSTEM_UID) {
-                    return false;
-                }
-                restriction = UserManager.DISALLOW_CONFIG_DATE_TIME;
-                break;
-
             case android.provider.Settings.Global.AUTO_TIME_ZONE:
                 if (callingUid == Process.SYSTEM_UID) {
                     return false;
diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
index 6abfbdc..c36b993 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -22,6 +22,7 @@
 import android.annotation.UserIdInt;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
 import android.content.res.Resources;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -85,28 +86,30 @@
      * System Property whether to only install system packages on a user if they're whitelisted for
      * that user type. These are flags and can be freely combined.
      * <ul>
-     * <li> 0 (0b000) - disable whitelist (install all system packages; no logging)</li>
-     * <li> 1 (0b001) - enforce (only install system packages if they are whitelisted)</li>
-     * <li> 2 (0b010) - log (log when a non-whitelisted package is run)</li>
-     * <li> 4 (0b100) - implicitly whitelist any package not mentioned in the whitelist</li>
-     * <li>-1         - use device default (as defined in res/res/values/config.xml)</li>
+     * <li> 0 (0b0000) - disable whitelist (install all system packages; no logging)</li>
+     * <li> 1 (0b0001) - enforce (only install system packages if they are whitelisted)</li>
+     * <li> 2 (0b0010) - log (log when a non-whitelisted package is run)</li>
+     * <li> 4 (0b0100) - implicitly whitelist any package not mentioned in the whitelist</li>
+     * <li> 8 (0b1000) - ignore OTAs (don't install system packages during OTAs)</li>
+     * <li>-1          - use device default (as defined in res/res/values/config.xml)</li>
      * </ul>
      * Note: This list must be kept current with config_userTypePackageWhitelistMode in
      * frameworks/base/core/res/res/values/config.xml
      */
     static final String PACKAGE_WHITELIST_MODE_PROP = "persist.debug.user.package_whitelist_mode";
     static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE = 0;
-    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0b001;
-    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_LOG = 0b010;
-    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0b100;
+    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0b0001;
+    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_LOG = 0b0010;
+    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0b0100;
+    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA = 0b1000;
     static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT = -1;
 
     @IntDef(flag = true, prefix = "USER_TYPE_PACKAGE_WHITELIST_MODE_", value = {
             USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE,
             USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE,
-            USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE,
             USER_TYPE_PACKAGE_WHITELIST_MODE_LOG,
             USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST,
+            USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface PackageWhitelistMode {}
@@ -169,11 +172,17 @@
     boolean installWhitelistedSystemPackages(boolean isFirstBoot, boolean isUpgrade) {
         final int mode = getWhitelistMode();
         checkWhitelistedSystemPackages(mode);
-        if (!isUpgrade && !isFirstBoot) {
+        final boolean isConsideredUpgrade = isUpgrade && !isIgnoreOtaMode(mode);
+        if (!isConsideredUpgrade && !isFirstBoot) {
+            return false;
+        }
+        if (isFirstBoot && !isEnforceMode(mode)) {
+            // Note that if !isEnforceMode, we nonetheless still install packages if isUpgrade
+            // in order to undo any previous non-installing. isFirstBoot lacks this requirement.
             return false;
         }
         Slog.i(TAG, "Reviewing whitelisted packages due to "
-                + (isFirstBoot ? "[firstBoot]" : "") + (isUpgrade ? "[upgrade]" : ""));
+                + (isFirstBoot ? "[firstBoot]" : "") + (isConsideredUpgrade ? "[upgrade]" : ""));
         final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class);
         // Install/uninstall system packages per user.
         for (int userId : mUm.getUserIds()) {
@@ -183,15 +192,15 @@
                     return;
                 }
                 final boolean install =
-                        (userWhitelist == null || userWhitelist.contains(pkg.packageName))
-                        && !pkg.applicationInfo.hiddenUntilInstalled;
-                if (isUpgrade && !isFirstBoot && !install) {
+                        (userWhitelist == null || userWhitelist.contains(pkg.getPackageName()))
+                        && !pkg.isHiddenUntilInstalled();
+                if (isConsideredUpgrade && !isFirstBoot && !install) {
                     return; // To be careful, we don’t uninstall apps during OTAs
                 }
                 final boolean changed = pmInt.setInstalled(pkg, userId, install);
                 if (changed) {
                     Slog.i(TAG, (install ? "Installed " : "Uninstalled ")
-                            + pkg.packageName + " for user " + userId);
+                            + pkg.getPackageName() + " for user " + userId);
                 }
             });
         }
@@ -212,7 +221,7 @@
 
         // Check whether all whitelisted packages are indeed on the system.
         for (String pkgName : allWhitelistedPackages) {
-            PackageParser.Package pkg = pmInt.getPackage(pkgName);
+            AndroidPackage pkg = pmInt.getPackage(pkgName);
             if (pkg == null) {
                 Slog.w(TAG, pkgName + " is whitelisted but not present.");
             } else if (!pkg.isSystem()) {
@@ -226,8 +235,8 @@
         }
         final boolean doWtf = isEnforceMode(mode);
         pmInt.forEachPackage(pkg -> {
-            if (pkg.isSystem() && !allWhitelistedPackages.contains(pkg.manifestPackageName)) {
-                final String msg = "System package " + pkg.manifestPackageName
+            if (pkg.isSystem() && !allWhitelistedPackages.contains(pkg.getManifestPackageName())) {
+                final String msg = "System package " + pkg.getManifestPackageName()
                         + " is not whitelisted using 'install-in-user-type' in SystemConfig "
                         + "for any user types!";
                 if (doWtf) {
@@ -245,6 +254,19 @@
     }
 
     /**
+     * Whether to ignore OTAs, and therefore not install missing system packages during OTAs.
+     * <p>Note:
+     * If in this mode, old system packages will not be installed on pre-existing users during OTAs.
+     * Any system packages that had not been installed at the time of the user's creation,
+     * due to {@link UserSystemPackageInstaller}'s previous actions, will therefore continue to
+     * remain uninstalled, even if the whitelist (or enforcement mode) now declares that they should
+     * be.
+     */
+    boolean isIgnoreOtaMode() {
+        return isIgnoreOtaMode(getWhitelistMode());
+    }
+
+    /**
      * Whether to log a warning concerning potential problems with the user-type package whitelist.
      */
     boolean isLogMode() {
@@ -264,6 +286,11 @@
         return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE) != 0;
     }
 
+    /** See {@link #isIgnoreOtaMode()}. */
+    private static boolean isIgnoreOtaMode(int whitelistMode) {
+        return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA) != 0;
+    }
+
     /** See {@link #isLogMode()}. */
     private static boolean isLogMode(int whitelistMode) {
         return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_LOG) != 0;
@@ -318,7 +345,7 @@
             if (shouldInstallPackage(pkg, mWhitelistedPackagesForUserTypes,
                     whitelistedPackages, isImplicitWhitelistMode, isSystemUser)) {
                 // Although the whitelist uses manifest names, this function returns packageNames.
-                installPackages.add(pkg.packageName);
+                installPackages.add(pkg.getPackageName());
             }
         });
         return installPackages;
@@ -340,12 +367,12 @@
      * @param isSystemUser whether the user is USER_SYSTEM (which gets special treatment).
      */
     @VisibleForTesting
-    static boolean shouldInstallPackage(PackageParser.Package sysPkg,
+    static boolean shouldInstallPackage(AndroidPackage sysPkg,
             @NonNull ArrayMap<String, Long> userTypeWhitelist,
             @NonNull Set<String> userWhitelist, boolean isImplicitWhitelistMode,
             boolean isSystemUser) {
 
-        final String pkgName = sysPkg.manifestPackageName;
+        final String pkgName = sysPkg.getManifestPackageName();
         boolean install = (isImplicitWhitelistMode && !userTypeWhitelist.containsKey(pkgName))
                 || userWhitelist.contains(pkgName);
 
@@ -536,6 +563,7 @@
         pw.print(isEnforceMode(mode) ? " (enforced)" : "");
         pw.print(isLogMode(mode) ? " (logged)" : "");
         pw.print(isImplicitWhitelistMode(mode) ? " (implicit)" : "");
+        pw.print(isIgnoreOtaMode(mode) ? " (ignore OTAs)" : "");
         pw.println();
 
         pw.print(prefix); pw.println("Legend");
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index cc5aec2..486cfef 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -25,13 +25,13 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
 import android.content.pm.dex.ArtManager;
 import android.content.pm.dex.ArtManager.ProfileType;
 import android.content.pm.dex.ArtManagerInternal;
 import android.content.pm.dex.DexMetadataHelper;
 import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
 import android.content.pm.dex.PackageOptimizationInfo;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Handler;
@@ -390,9 +390,10 @@
      *   - create the current primary profile to save time at app startup time.
      *   - copy the profiles from the associated dex metadata file to the reference profile.
      */
-    public void prepareAppProfiles(PackageParser.Package pkg, @UserIdInt int user,
+    public void prepareAppProfiles(
+            AndroidPackage pkg, @UserIdInt int user,
             boolean updateReferenceProfileContent) {
-        final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
+        final int appId = UserHandle.getAppId(pkg.getUid());
         if (user < 0) {
             Slog.wtf(TAG, "Invalid user id: " + user);
             return;
@@ -415,23 +416,24 @@
                     dexMetadataPath = dexMetadata == null ? null : dexMetadata.getAbsolutePath();
                 }
                 synchronized (mInstaller) {
-                    boolean result = mInstaller.prepareAppProfile(pkg.packageName, user, appId,
+                    boolean result = mInstaller.prepareAppProfile(pkg.getPackageName(), user, appId,
                             profileName, codePath, dexMetadataPath);
                     if (!result) {
                         Slog.e(TAG, "Failed to prepare profile for " +
-                                pkg.packageName + ":" + codePath);
+                                pkg.getPackageName() + ":" + codePath);
                     }
                 }
             }
         } catch (InstallerException e) {
-            Slog.e(TAG, "Failed to prepare profile for " + pkg.packageName, e);
+            Slog.e(TAG, "Failed to prepare profile for " + pkg.getPackageName(), e);
         }
     }
 
     /**
      * Prepares the app profiles for a set of users. {@see ArtManagerService#prepareAppProfiles}.
      */
-    public void prepareAppProfiles(PackageParser.Package pkg, int[] user,
+    public void prepareAppProfiles(
+            AndroidPackage pkg, int[] user,
             boolean updateReferenceProfileContent) {
         for (int i = 0; i < user.length; i++) {
             prepareAppProfiles(pkg, user[i], updateReferenceProfileContent);
@@ -441,12 +443,12 @@
     /**
      * Clear the profiles for the given package.
      */
-    public void clearAppProfiles(PackageParser.Package pkg) {
+    public void clearAppProfiles(AndroidPackage pkg) {
         try {
             ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg);
             for (int i = packageProfileNames.size() - 1; i >= 0; i--) {
                 String profileName = packageProfileNames.valueAt(i);
-                mInstaller.clearAppProfiles(pkg.packageName, profileName);
+                mInstaller.clearAppProfiles(pkg.getPackageName(), profileName);
             }
         } catch (InstallerException e) {
             Slog.w(TAG, String.valueOf(e));
@@ -456,15 +458,15 @@
     /**
      * Dumps the profiles for the given package.
      */
-    public void dumpProfiles(PackageParser.Package pkg) {
-        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+    public void dumpProfiles(AndroidPackage pkg) {
+        final int sharedGid = UserHandle.getSharedAppGid(pkg.getUid());
         try {
             ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg);
             for (int i = packageProfileNames.size() - 1; i >= 0; i--) {
                 String codePath = packageProfileNames.keyAt(i);
                 String profileName = packageProfileNames.valueAt(i);
                 synchronized (mInstallLock) {
-                    mInstaller.dumpProfiles(sharedGid, pkg.packageName, profileName, codePath);
+                    mInstaller.dumpProfiles(sharedGid, pkg.getPackageName(), profileName, codePath);
                 }
             }
         } catch (InstallerException e) {
@@ -475,14 +477,13 @@
     /**
      * Compile layout resources in a given package.
      */
-    public boolean compileLayouts(PackageParser.Package pkg) {
+    public boolean compileLayouts(AndroidPackage pkg) {
         try {
-            final String packageName = pkg.packageName;
-            final String apkPath = pkg.baseCodePath;
-            final ApplicationInfo appInfo = pkg.applicationInfo;
-            final String outDexFile = appInfo.dataDir + "/code_cache/compiled_view.dex";
-            if (appInfo.isPrivilegedApp() || appInfo.isEmbeddedDexUsed()
-                    || appInfo.isDefaultToDeviceProtectedStorage()) {
+            final String packageName = pkg.getPackageName();
+            final String apkPath = pkg.getBaseCodePath();
+            final String outDexFile = pkg.getDataDir() + "/code_cache/compiled_view.dex";
+            if (pkg.isPrivileged() || pkg.isEmbeddedDexUsed()
+                    || pkg.isDefaultToDeviceProtectedStorage()) {
                 // Privileged apps prefer to load trusted code so they don't use compiled views.
                 // If the app is not privileged but prefers code integrity, also avoid compiling
                 // views.
@@ -496,7 +497,7 @@
             try {
                 synchronized (mInstallLock) {
                     return mInstaller.compileLayouts(apkPath, packageName, outDexFile,
-                            appInfo.uid);
+                            pkg.getUid());
                 }
             } finally {
                 Binder.restoreCallingIdentity(callingId);
@@ -512,15 +513,19 @@
      * Build the profiles names for all the package code paths (excluding resource only paths).
      * Return the map [code path -> profile name].
      */
-    private ArrayMap<String, String> getPackageProfileNames(PackageParser.Package pkg) {
+    private ArrayMap<String, String> getPackageProfileNames(AndroidPackage pkg) {
         ArrayMap<String, String> result = new ArrayMap<>();
-        if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
-            result.put(pkg.baseCodePath, ArtManager.getProfileName(null));
+        if ((pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) != 0) {
+            result.put(pkg.getBaseCodePath(), ArtManager.getProfileName(null));
         }
-        if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
-            for (int i = 0; i < pkg.splitCodePaths.length; i++) {
-                if ((pkg.splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) {
-                    result.put(pkg.splitCodePaths[i], ArtManager.getProfileName(pkg.splitNames[i]));
+
+        String[] splitCodePaths = pkg.getSplitCodePaths();
+        int[] splitFlags = pkg.getSplitFlags();
+        String[] splitNames = pkg.getSplitNames();
+        if (!ArrayUtils.isEmpty(splitCodePaths)) {
+            for (int i = 0; i < splitCodePaths.length; i++) {
+                if ((splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) {
+                    result.put(splitCodePaths[i], ArtManager.getProfileName(splitNames[i]));
                 }
             }
         }
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 41dcaa5..29183bb 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -588,7 +588,7 @@
 
         // We found the package. Now record the usage for all declared ISAs.
         boolean update = false;
-        for (String isa : getAppDexInstructionSets(info)) {
+        for (String isa : getAppDexInstructionSets(info.primaryCpuAbi, info.secondaryCpuAbi)) {
             boolean newUpdate = mPackageDexUsage.record(searchResult.mOwningPackageName,
                     dexPath, userId, isa, isUsedByOtherApps, /*primaryOrSplit*/ false,
                     searchResult.mOwningPackageName,
diff --git a/services/core/java/com/android/server/pm/dex/DexoptUtils.java b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
index 5a473c1..6e6b137 100644
--- a/services/core/java/com/android/server/pm/dex/DexoptUtils.java
+++ b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
@@ -18,10 +18,12 @@
 
 import android.content.pm.ApplicationInfo;
 import android.content.pm.SharedLibraryInfo;
+import android.content.pm.parsing.AndroidPackage;
 import android.util.Slog;
 import android.util.SparseArray;
 
 import com.android.internal.os.ClassLoaderFactory;
+import com.android.internal.util.ArrayUtils;
 
 import java.io.File;
 import java.util.List;
@@ -66,7 +68,7 @@
      * {@link android.app.LoadedApk#makePaths(
      * android.app.ActivityThread, boolean, ApplicationInfo, List, List)}.
      */
-    public static String[] getClassLoaderContexts(ApplicationInfo info,
+    public static String[] getClassLoaderContexts(AndroidPackage pkg,
             List<SharedLibraryInfo> sharedLibraries, boolean[] pathsWithCode) {
         // The base class loader context contains only the shared library.
         String sharedLibrariesContext = "";
@@ -75,8 +77,8 @@
         }
 
         String baseApkContextClassLoader = encodeClassLoader(
-                "", info.classLoaderName, sharedLibrariesContext);
-        if (info.getSplitCodePaths() == null) {
+                "", pkg.getAppInfoClassLoaderName(), sharedLibrariesContext);
+        if (pkg.getSplitCodePaths() == null) {
             // The application has no splits.
             return new String[] {baseApkContextClassLoader};
         }
@@ -84,11 +86,11 @@
         // The application has splits. Compute their class loader contexts.
 
         // First, cache the relative paths of the splits and do some sanity checks
-        String[] splitRelativeCodePaths = getSplitRelativeCodePaths(info);
+        String[] splitRelativeCodePaths = getSplitRelativeCodePaths(pkg);
 
         // The splits have an implicit dependency on the base apk.
         // This means that we have to add the base apk file in addition to the shared libraries.
-        String baseApkName = new File(info.getBaseCodePath()).getName();
+        String baseApkName = new File(pkg.getBaseCodePath()).getName();
         String baseClassPath = baseApkName;
 
         // The result is stored in classLoaderContexts.
@@ -97,7 +99,11 @@
         String[] classLoaderContexts = new String[/*base apk*/ 1 + splitRelativeCodePaths.length];
         classLoaderContexts[0] = pathsWithCode[0] ? baseApkContextClassLoader : null;
 
-        if (!info.requestsIsolatedSplitLoading() || info.splitDependencies == null) {
+        SparseArray<int[]> splitDependencies = pkg.getSplitDependencies();
+
+        if (!pkg.requestsIsolatedSplitLoading()
+                || splitDependencies == null
+                || splitDependencies.size() == 0) {
             // If the app didn't request for the splits to be loaded in isolation or if it does not
             // declare inter-split dependencies, then all the splits will be loaded in the base
             // apk class loader (in the order of their definition).
@@ -105,7 +111,7 @@
             for (int i = 1; i < classLoaderContexts.length; i++) {
                 if (pathsWithCode[i]) {
                     classLoaderContexts[i] = encodeClassLoader(
-                            classpath, info.classLoaderName, sharedLibrariesContext);
+                            classpath, pkg.getAppInfoClassLoaderName(), sharedLibrariesContext);
                 } else {
                     classLoaderContexts[i] = null;
                 }
@@ -132,11 +138,10 @@
             String[] splitClassLoaderEncodingCache = new String[splitRelativeCodePaths.length];
             for (int i = 0; i < splitRelativeCodePaths.length; i++) {
                 splitClassLoaderEncodingCache[i] = encodeClassLoader(splitRelativeCodePaths[i],
-                        info.splitClassLoaderNames[i]);
+                        pkg.getSplitClassLoaderNames()[i]);
             }
             String splitDependencyOnBase = encodeClassLoader(
-                    baseClassPath, info.classLoaderName);
-            SparseArray<int[]> splitDependencies = info.splitDependencies;
+                    baseClassPath, pkg.getClassLoaderName());
 
             // Note that not all splits have dependencies (e.g. configuration splits)
             // The splits without dependencies will have classLoaderContexts[config_split_index]
@@ -154,7 +159,8 @@
             // We also need to add the class loader of the current split which should
             // come first in the context.
             for (int i = 1; i < classLoaderContexts.length; i++) {
-                String splitClassLoader = encodeClassLoader("", info.splitClassLoaderNames[i - 1]);
+                String splitClassLoader = encodeClassLoader("",
+                        pkg.getSplitClassLoaderNames()[i - 1]);
                 if (pathsWithCode[i]) {
                     // If classLoaderContexts[i] is null it means that the split does not have
                     // any dependency. In this case its context equals its declared class loader.
@@ -394,11 +400,11 @@
      * Returns the relative paths of the splits declared by the application {@code info}.
      * Assumes that the application declares a non-null array of splits.
      */
-    private static String[] getSplitRelativeCodePaths(ApplicationInfo info) {
-        String baseCodePath = new File(info.getBaseCodePath()).getParent();
-        String[] splitCodePaths = info.getSplitCodePaths();
-        String[] splitRelativeCodePaths = new String[splitCodePaths.length];
-        for (int i = 0; i < splitCodePaths.length; i++) {
+    private static String[] getSplitRelativeCodePaths(AndroidPackage pkg) {
+        String baseCodePath = new File(pkg.getBaseCodePath()).getParent();
+        String[] splitCodePaths = pkg.getSplitCodePaths();
+        String[] splitRelativeCodePaths = new String[ArrayUtils.size(splitCodePaths)];
+        for (int i = 0; i < splitRelativeCodePaths.length; i++) {
             File pathFile = new File(splitCodePaths[i]);
             splitRelativeCodePaths[i] = pathFile.getName();
             // Sanity check that the base paths of the splits are all the same.
diff --git a/services/core/java/com/android/server/pm/dex/ViewCompiler.java b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
index 8d8e17e..b7443f3 100644
--- a/services/core/java/com/android/server/pm/dex/ViewCompiler.java
+++ b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
@@ -16,10 +16,10 @@
 
 package com.android.server.pm.dex;
 
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.Binder;
 import android.util.Log;
+
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.pm.Installer;
 
@@ -33,19 +33,18 @@
         mInstaller = installer;
     }
 
-    public boolean compileLayouts(PackageParser.Package pkg) {
+    public boolean compileLayouts(AndroidPackage pkg) {
         try {
-            final String packageName = pkg.packageName;
-            final String apkPath = pkg.baseCodePath;
-            final ApplicationInfo appInfo = pkg.applicationInfo;
-            final String outDexFile = appInfo.dataDir + "/code_cache/compiled_view.dex";
+            final String packageName = pkg.getPackageName();
+            final String apkPath = pkg.getBaseCodePath();
+            final String outDexFile = pkg.getDataDir() + "/code_cache/compiled_view.dex";
             Log.i("PackageManager", "Compiling layouts in " + packageName + " (" + apkPath +
                 ") to " + outDexFile);
             long callingId = Binder.clearCallingIdentity();
             try {
                 synchronized (mInstallLock) {
                     return mInstaller.compileLayouts(apkPath, packageName, outDexFile,
-                        appInfo.uid);
+                        pkg.getUid());
                 }
             } finally {
                 Binder.restoreCallingIdentity(callingId);
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index c39dcfe..9668c21 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -29,10 +29,12 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.Permission;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.PermissionInfo;
 import android.content.pm.Signature;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.PackageInfoUtils;
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.Slog;
@@ -89,7 +91,7 @@
 
     int protectionLevel;
 
-    PackageParser.Permission perm;
+    ParsedPermission perm;
 
     PermissionInfo pendingPermissionInfo;
 
@@ -113,12 +115,6 @@
         protectionLevel = PermissionInfo.PROTECTION_SIGNATURE;
     }
 
-    @Override
-    public String toString() {
-        return "BasePermission{" + Integer.toHexString(System.identityHashCode(this)) + " " + name
-                + "}";
-    }
-
     public String getName() {
         return name;
     }
@@ -144,7 +140,7 @@
         this.gids = gids;
         this.perUser = perUser;
     }
-    public void setPermission(@Nullable Permission perm) {
+    public void setPermission(@Nullable ParsedPermission perm) {
         this.perm = perm;
     }
     public void setSourcePackageSetting(PackageSettingBase sourcePackageSetting) {
@@ -165,13 +161,16 @@
 
     public int calculateFootprint(BasePermission perm) {
         if (uid == perm.uid) {
-            return perm.name.length() + perm.perm.info.calculateFootprint();
+            return perm.name.length() + perm.perm.calculateFootprint();
         }
         return 0;
     }
 
-    public boolean isPermission(Permission perm) {
-        return this.perm == perm;
+    public boolean isPermission(@NonNull ParsedPermission perm) {
+        if (this.perm == null) {
+            return false;
+        }
+        return Objects.equals(this.perm.className, perm.className);
     }
 
     public boolean isDynamic() {
@@ -189,29 +188,24 @@
     }
 
     public boolean isRemoved() {
-        return perm != null && perm.info != null
-                && (perm.info.flags & PermissionInfo.FLAG_REMOVED) != 0;
+        return perm != null && (perm.flags & PermissionInfo.FLAG_REMOVED) != 0;
     }
 
     public boolean isSoftRestricted() {
-        return perm != null && perm.info != null
-                && (perm.info.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0;
+        return perm != null && (perm.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0;
     }
 
     public boolean isHardRestricted() {
-        return perm != null && perm.info != null
-                && (perm.info.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0;
+        return perm != null && (perm.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0;
     }
 
     public boolean isHardOrSoftRestricted() {
-        return perm != null && perm.info != null
-                && (perm.info.flags & (PermissionInfo.FLAG_HARD_RESTRICTED
+        return perm != null && (perm.flags & (PermissionInfo.FLAG_HARD_RESTRICTED
                 | PermissionInfo.FLAG_SOFT_RESTRICTED)) != 0;
     }
 
     public boolean isImmutablyRestricted() {
-        return perm != null && perm.info != null
-                && (perm.info.flags & PermissionInfo.FLAG_IMMUTABLY_RESTRICTED) != 0;
+        return perm != null && (perm.flags & PermissionInfo.FLAG_IMMUTABLY_RESTRICTED) != 0;
     }
 
     public boolean isSignature() {
@@ -300,13 +294,12 @@
                 (this.protectionLevel != protectionLevel
                     || perm == null
                     || uid != tree.uid
-                    || !perm.owner.equals(tree.perm.owner)
-                    || !comparePermissionInfos(perm.info, info));
+                    || !Objects.equals(perm.getPackageName(), tree.perm.getPackageName())
+                    || !comparePermissionInfos(perm, info));
         this.protectionLevel = protectionLevel;
         info = new PermissionInfo(info);
         info.protectionLevel = protectionLevel;
-        perm = new PackageParser.Permission(tree.perm.owner, info);
-        perm.info.packageName = tree.perm.info.packageName;
+        perm = new ParsedPermission(tree.perm);
         uid = tree.uid;
         return changed;
     }
@@ -319,71 +312,89 @@
             final BasePermission tree = findPermissionTree(permissionTrees, name);
             if (tree != null && tree.perm != null) {
                 sourcePackageSetting = tree.sourcePackageSetting;
-                perm = new PackageParser.Permission(tree.perm.owner,
-                        new PermissionInfo(pendingPermissionInfo));
-                perm.info.packageName = tree.perm.info.packageName;
-                perm.info.name = name;
+                perm = new ParsedPermission(tree.perm);
+                perm.protectionLevel = pendingPermissionInfo.protectionLevel;
+                perm.flags = pendingPermissionInfo.flags;
+                perm.setGroup(pendingPermissionInfo.group);
+                perm.backgroundPermission = pendingPermissionInfo.backgroundPermission;
+                perm.descriptionRes = pendingPermissionInfo.descriptionRes;
+                perm.requestRes = pendingPermissionInfo.requestRes;
+                perm.setPackageName(tree.perm.getPackageName());
+                perm.setName(name);
                 uid = tree.uid;
             }
         }
     }
 
-    static BasePermission createOrUpdate(@Nullable BasePermission bp, @NonNull Permission p,
-            @NonNull PackageParser.Package pkg, Collection<BasePermission> permissionTrees,
+    static BasePermission createOrUpdate(PackageManagerInternal packageManagerInternal,
+            @Nullable BasePermission bp, @NonNull ParsedPermission p,
+            @NonNull AndroidPackage pkg, Collection<BasePermission> permissionTrees,
             boolean chatty) {
-        final PackageSettingBase pkgSetting = (PackageSettingBase) pkg.mExtras;
+        final PackageSettingBase pkgSetting =
+                (PackageSettingBase) packageManagerInternal.getPackageSetting(pkg.getPackageName());
         // Allow system apps to redefine non-system permissions
-        if (bp != null && !Objects.equals(bp.sourcePackageName, p.info.packageName)) {
-            final boolean currentOwnerIsSystem = (bp.perm != null
-                    && bp.perm.owner.isSystem());
-            if (p.owner.isSystem()) {
+        if (bp != null && !Objects.equals(bp.sourcePackageName, p.getPackageName())) {
+            final boolean currentOwnerIsSystem;
+            if (bp.perm == null) {
+                currentOwnerIsSystem = false;
+            } else {
+                AndroidPackage currentPackage = packageManagerInternal.getPackage(
+                        bp.perm.getPackageName());
+                if (currentPackage == null) {
+                    currentOwnerIsSystem = false;
+                } else {
+                    currentOwnerIsSystem = currentPackage.isSystem();
+                }
+            }
+
+            if (pkg.isSystem()) {
                 if (bp.type == BasePermission.TYPE_BUILTIN && bp.perm == null) {
                     // It's a built-in permission and no owner, take ownership now
+                    p.flags |= PermissionInfo.FLAG_INSTALLED;
                     bp.sourcePackageSetting = pkgSetting;
                     bp.perm = p;
-                    bp.uid = pkg.applicationInfo.uid;
-                    bp.sourcePackageName = p.info.packageName;
-                    p.info.flags |= PermissionInfo.FLAG_INSTALLED;
+                    bp.uid = pkg.getUid();
+                    bp.sourcePackageName = p.getPackageName();
                 } else if (!currentOwnerIsSystem) {
-                    String msg = "New decl " + p.owner + " of permission  "
-                            + p.info.name + " is system; overriding " + bp.sourcePackageName;
+                    String msg = "New decl " + pkg + " of permission  "
+                            + p.getName() + " is system; overriding " + bp.sourcePackageName;
                     PackageManagerService.reportSettingsProblem(Log.WARN, msg);
                     bp = null;
                 }
             }
         }
         if (bp == null) {
-            bp = new BasePermission(p.info.name, p.info.packageName, TYPE_NORMAL);
+            bp = new BasePermission(p.getName(), p.getPackageName(), TYPE_NORMAL);
         }
         StringBuilder r = null;
         if (bp.perm == null) {
             if (bp.sourcePackageName == null
-                    || bp.sourcePackageName.equals(p.info.packageName)) {
-                final BasePermission tree = findPermissionTree(permissionTrees, p.info.name);
+                    || bp.sourcePackageName.equals(p.getPackageName())) {
+                final BasePermission tree = findPermissionTree(permissionTrees, p.getName());
                 if (tree == null
-                        || tree.sourcePackageName.equals(p.info.packageName)) {
+                        || tree.sourcePackageName.equals(p.getPackageName())) {
+                    p.flags |= PermissionInfo.FLAG_INSTALLED;
                     bp.sourcePackageSetting = pkgSetting;
                     bp.perm = p;
-                    bp.uid = pkg.applicationInfo.uid;
-                    bp.sourcePackageName = p.info.packageName;
-                    p.info.flags |= PermissionInfo.FLAG_INSTALLED;
+                    bp.uid = pkg.getUid();
+                    bp.sourcePackageName = p.getPackageName();
                     if (chatty) {
                         if (r == null) {
                             r = new StringBuilder(256);
                         } else {
                             r.append(' ');
                         }
-                        r.append(p.info.name);
+                        r.append(p.getName());
                     }
                 } else {
-                    Slog.w(TAG, "Permission " + p.info.name + " from package "
-                            + p.info.packageName + " ignored: base tree "
+                    Slog.w(TAG, "Permission " + p.getName() + " from package "
+                            + p.getPackageName() + " ignored: base tree "
                             + tree.name + " is from package "
                             + tree.sourcePackageName);
                 }
             } else {
-                Slog.w(TAG, "Permission " + p.info.name + " from package "
-                        + p.info.packageName + " ignored: original from "
+                Slog.w(TAG, "Permission " + p.getName() + " from package "
+                        + p.getPackageName() + " ignored: original from "
                         + bp.sourcePackageName);
             }
         } else if (chatty) {
@@ -393,10 +404,10 @@
                 r.append(' ');
             }
             r.append("DUP:");
-            r.append(p.info.name);
+            r.append(p.getName());
         }
-        if (bp.perm == p) {
-            bp.protectionLevel = p.info.protectionLevel;
+        if (bp.perm != null && Objects.equals(bp.perm.className, p.className)) {
+            bp.protectionLevel = p.protectionLevel;
         }
         if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) {
             Log.d(TAG, "  Permissions: " + r);
@@ -420,17 +431,17 @@
         throw new SecurityException("No permission tree found for " + permName);
     }
 
-    public void enforceDeclaredUsedAndRuntimeOrDevelopment(PackageParser.Package pkg) {
-        final PackageSetting pkgSetting = (PackageSetting) pkg.mExtras;
+    public void enforceDeclaredUsedAndRuntimeOrDevelopment(AndroidPackage pkg,
+            PackageSetting pkgSetting) {
         final PermissionsState permsState = pkgSetting.getPermissionsState();
-        int index = pkg.requestedPermissions.indexOf(name);
+        int index = pkg.getRequestedPermissions().indexOf(name);
         if (!permsState.hasRequestedPermission(name) && index == -1) {
-            throw new SecurityException("Package " + pkg.packageName
+            throw new SecurityException("Package " + pkg.getPackageName()
                     + " has not requested permission " + name);
         }
         if (!isRuntime() && !isDevelopment()) {
-            throw new SecurityException("Permission " + name
-                    + " requested by " + pkg.packageName + " is not a changeable permission type");
+            throw new SecurityException("Permission " + name + " requested by "
+                    + pkg.getPackageName() + " is not a changeable permission type");
         }
     }
 
@@ -448,12 +459,12 @@
 
     public @Nullable PermissionInfo generatePermissionInfo(@NonNull String groupName, int flags) {
         if (groupName == null) {
-            if (perm == null || perm.info.group == null) {
+            if (perm == null || perm.getGroup() == null) {
                 return generatePermissionInfo(protectionLevel, flags);
             }
         } else {
-            if (perm != null && groupName.equals(perm.info.group)) {
-                return PackageParser.generatePermissionInfo(perm, flags);
+            if (perm != null && groupName.equals(perm.getGroup())) {
+                return PackageInfoUtils.generatePermissionInfo(perm, flags);
             }
         }
         return null;
@@ -463,8 +474,8 @@
         PermissionInfo permissionInfo;
         if (perm != null) {
             final boolean protectionLevelChanged = protectionLevel != adjustedProtectionLevel;
-            permissionInfo = PackageParser.generatePermissionInfo(perm, flags);
-            if (protectionLevelChanged && permissionInfo == perm.info) {
+            permissionInfo = PackageInfoUtils.generatePermissionInfo(perm, flags);
+            if (protectionLevelChanged) {
                 // if we return different protection level, don't use the cached info
                 permissionInfo = new PermissionInfo(permissionInfo);
                 permissionInfo.protectionLevel = adjustedProtectionLevel;
@@ -544,14 +555,18 @@
             serializer.attribute(null, "protection", Integer.toString(protectionLevel));
         }
         if (type == BasePermission.TYPE_DYNAMIC) {
-            final PermissionInfo pi = perm != null ? perm.info : pendingPermissionInfo;
-            if (pi != null) {
+            if (perm != null || pendingPermissionInfo != null) {
                 serializer.attribute(null, "type", "dynamic");
-                if (pi.icon != 0) {
-                    serializer.attribute(null, "icon", Integer.toString(pi.icon));
+                int icon = perm != null ? perm.icon : pendingPermissionInfo.icon;
+                CharSequence nonLocalizedLabel = perm != null
+                        ? perm.nonLocalizedLabel
+                        : pendingPermissionInfo.nonLocalizedLabel;
+
+                if (icon != 0) {
+                    serializer.attribute(null, "icon", Integer.toString(icon));
                 }
-                if (pi.nonLocalizedLabel != null) {
-                    serializer.attribute(null, "label", pi.nonLocalizedLabel.toString());
+                if (nonLocalizedLabel != null) {
+                    serializer.attribute(null, "label", nonLocalizedLabel.toString());
                 }
             }
         }
@@ -571,14 +586,14 @@
         return s1.equals(s2);
     }
 
-    private static boolean comparePermissionInfos(PermissionInfo pi1, PermissionInfo pi2) {
+    private static boolean comparePermissionInfos(ParsedPermission pi1, PermissionInfo pi2) {
         if (pi1.icon != pi2.icon) return false;
         if (pi1.logo != pi2.logo) return false;
         if (pi1.protectionLevel != pi2.protectionLevel) return false;
-        if (!compareStrings(pi1.name, pi2.name)) return false;
+        if (!compareStrings(pi1.getName(), pi2.name)) return false;
         if (!compareStrings(pi1.nonLocalizedLabel, pi2.nonLocalizedLabel)) return false;
         // We'll take care of setting this one.
-        if (!compareStrings(pi1.packageName, pi2.packageName)) return false;
+        if (!compareStrings(pi1.getPackageName(), pi2.packageName)) return false;
         // These are not currently stored in settings.
         //if (!compareStrings(pi1.group, pi2.group)) return false;
         //if (!compareStrings(pi1.nonLocalizedDescription, pi2.nonLocalizedDescription)) return false;
@@ -614,9 +629,9 @@
                 pw.println(PermissionInfo.protectionToString(protectionLevel));
         if (perm != null) {
             pw.print("    perm="); pw.println(perm);
-            if ((perm.info.flags & PermissionInfo.FLAG_INSTALLED) == 0
-                    || (perm.info.flags & PermissionInfo.FLAG_REMOVED) != 0) {
-                pw.print("    flags=0x"); pw.println(Integer.toHexString(perm.info.flags));
+            if ((perm.flags & PermissionInfo.FLAG_INSTALLED) == 0
+                    || (perm.flags & PermissionInfo.FLAG_REMOVED) != 0) {
+                pw.print("    flags=0x"); pw.println(Integer.toHexString(perm.flags));
             }
         }
         if (sourcePackageSetting != null) {
@@ -628,4 +643,20 @@
         }
         return true;
     }
+
+    @Override
+    public String toString() {
+        return "BasePermission{" +
+                "name='" + name + '\'' +
+                ", type=" + type +
+                ", sourcePackageName='" + sourcePackageName + '\'' +
+                ", sourcePackageSetting=" + sourcePackageSetting +
+                ", protectionLevel=" + protectionLevel +
+                ", perm=" + perm +
+                ", pendingPermissionInfo=" + pendingPermissionInfo +
+                ", uid=" + uid +
+                ", gids=" + Arrays.toString(gids) +
+                ", perUser=" + perUser +
+                '}';
+    }
 }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 2ffba45..5adb648 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -63,10 +63,13 @@
 import android.content.pm.PackageManager.PermissionWhitelistFlags;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.Package;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.PermissionGroupInfo;
 import android.content.pm.PermissionInfo;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
+import android.content.pm.parsing.PackageInfoUtils;
 import android.content.pm.permission.SplitPermissionInfoParcelable;
 import android.metrics.LogMaker;
 import android.os.Binder;
@@ -419,7 +422,8 @@
         }
     }
 
-    @Nullable BasePermission getPermission(String permName) {
+    @Nullable
+    BasePermission getPermission(String permName) {
         synchronized (mLock) {
             return mSettings.getPermissionLocked(permName);
         }
@@ -453,10 +457,9 @@
         }
         synchronized (mLock) {
             final int n = mSettings.mPermissionGroups.size();
-            final ArrayList<PermissionGroupInfo> out =
-                    new ArrayList<PermissionGroupInfo>(n);
-            for (PackageParser.PermissionGroup pg : mSettings.mPermissionGroups.values()) {
-                out.add(PackageParser.generatePermissionGroupInfo(pg, flags));
+            final ArrayList<PermissionGroupInfo> out = new ArrayList<>(n);
+            for (ParsedPermissionGroup pg : mSettings.mPermissionGroups.values()) {
+                out.add(PackageInfoUtils.generatePermissionGroupInfo(pg, flags));
             }
             return new ParceledListSlice<>(out);
         }
@@ -472,7 +475,7 @@
             return null;
         }
         synchronized (mLock) {
-            return PackageParser.generatePermissionGroupInfo(
+            return PackageInfoUtils.generatePermissionGroupInfo(
                     mSettings.mPermissionGroups.get(groupName), flags);
         }
     }
@@ -596,8 +599,13 @@
                 false, // requirePermissionWhenSameUser
                 "getPermissionFlags");
 
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
-        if (pkg == null || pkg.mExtras == null) {
+        final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
+        if (pkg == null) {
+            return 0;
+        }
+        final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+                pkg.getPackageName());
+        if (ps == null) {
             return 0;
         }
         synchronized (mLock) {
@@ -608,7 +616,6 @@
         if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
             return 0;
         }
-        final PackageSetting ps = (PackageSetting) pkg.mExtras;
         PermissionsState permissionsState = ps.getPermissionsState();
         return permissionsState.getPermissionFlags(permName, userId);
     }
@@ -695,8 +702,10 @@
             flagValues &= ~PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
         }
 
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
-        if (pkg == null || pkg.mExtras == null) {
+        final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
+        final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+                packageName);
+        if (pkg == null || ps == null) {
             Log.e(TAG, "Unknown package: " + packageName);
             return;
         }
@@ -712,7 +721,6 @@
             throw new IllegalArgumentException("Unknown permission: " + permName);
         }
 
-        final PackageSetting ps = (PackageSetting) pkg.mExtras;
         final PermissionsState permissionsState = ps.getPermissionsState();
         final boolean hadState =
                 permissionsState.getRuntimePermissionState(permName, userId) != null;
@@ -725,11 +733,11 @@
             // Install and runtime permissions are stored in different places,
             // so figure out what permission changed and persist the change.
             if (permissionsState.getInstallPermissionState(permName) != null) {
-                callback.onInstallPermissionUpdatedNotifyListener(pkg.applicationInfo.uid);
+                callback.onInstallPermissionUpdatedNotifyListener(pkg.getUid());
             } else if (permissionsState.getRuntimePermissionState(permName, userId) != null
                     || hadState) {
-                callback.onPermissionUpdatedNotifyListener(new int[] { userId }, false,
-                        pkg.applicationInfo.uid);
+                callback.onPermissionUpdatedNotifyListener(new int[]{userId}, false,
+                        pkg.getUid());
             }
         }
     }
@@ -761,18 +769,16 @@
                 ? flagValues : flagValues & ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
 
         final boolean[] changed = new boolean[1];
-        mPackageManagerInt.forEachPackage(new Consumer<PackageParser.Package>() {
-            @Override
-            public void accept(Package pkg) {
-                final PackageSetting ps = (PackageSetting) pkg.mExtras;
-                if (ps == null) {
-                    return;
-                }
-                final PermissionsState permissionsState = ps.getPermissionsState();
-                changed[0] |= permissionsState.updatePermissionFlagsForAllPermissions(
-                        userId, effectiveFlagMask, effectiveFlagValues);
-                mOnPermissionChangeListeners.onPermissionsChanged(pkg.applicationInfo.uid);
+        mPackageManagerInt.forEachPackage(pkg -> {
+            final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+                    pkg.getPackageName());
+            if (ps == null) {
+                return;
             }
+            final PermissionsState permissionsState = ps.getPermissionsState();
+            changed[0] |= permissionsState.updatePermissionFlagsForAllPermissions(
+                    userId, effectiveFlagMask, effectiveFlagValues);
+            mOnPermissionChangeListeners.onPermissionsChanged(pkg.getUid());
         });
 
         if (changed[0]) {
@@ -802,17 +808,17 @@
     }
 
     private int checkPermissionImpl(String permName, String pkgName, int userId) {
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(pkgName);
+        final AndroidPackage pkg = mPackageManagerInt.getPackage(pkgName);
         if (pkg == null) {
             return PackageManager.PERMISSION_DENIED;
         }
         return checkPermissionInternal(pkg, true, permName, userId);
     }
 
-    private int checkPermissionInternal(@NonNull Package pkg, boolean isPackageExplicit,
+    private int checkPermissionInternal(@NonNull AndroidPackage pkg, boolean isPackageExplicit,
             @NonNull String permissionName, @UserIdInt int userId) {
         final int callingUid = getCallingUid();
-        if (isPackageExplicit || pkg.mSharedUserId == null) {
+        if (isPackageExplicit || pkg.getSharedUserId() == null) {
             if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
                 return PackageManager.PERMISSION_DENIED;
             }
@@ -822,8 +828,9 @@
             }
         }
 
-        final int uid = UserHandle.getUid(userId, pkg.applicationInfo.uid);
-        final PackageSetting ps = (PackageSetting) pkg.mExtras;
+        final int uid = UserHandle.getUid(userId, pkg.getUid());
+        final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+                pkg.getPackageName());
         if (ps == null) {
             return PackageManager.PERMISSION_DENIED;
         }
@@ -878,7 +885,7 @@
     }
 
     private int checkUidPermissionImpl(String permName, int uid) {
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(uid);
+        final AndroidPackage pkg = mPackageManagerInt.getPackage(uid);
         return checkUidPermissionInternal(pkg, uid, permName);
     }
 
@@ -889,7 +896,7 @@
      *
      * @see SystemConfig#getSystemPermissions()
      */
-    private int checkUidPermissionInternal(@Nullable Package pkg, int uid,
+    private int checkUidPermissionInternal(@Nullable AndroidPackage pkg, int uid,
             @NonNull String permissionName) {
         if (pkg != null) {
             final int userId = UserHandle.getUserId(uid);
@@ -953,7 +960,7 @@
                     "getWhitelistedRestrictedPermissions for user " + userId);
         }
 
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+        final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
         if (pkg == null) {
             return null;
         }
@@ -986,7 +993,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             final PermissionsState permissionsState =
-                    PackageManagerServiceUtils.getPermissionsState(pkg);
+                    PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg);
             if (permissionsState == null) {
                 return null;
             }
@@ -1004,9 +1011,9 @@
 
             ArrayList<String> whitelistedPermissions = null;
 
-            final int permissionCount = pkg.requestedPermissions.size();
+            final int permissionCount = ArrayUtils.size(pkg.getRequestedPermissions());
             for (int i = 0; i < permissionCount; i++) {
-                final String permissionName = pkg.requestedPermissions.get(i);
+                final String permissionName = pkg.getRequestedPermissions().get(i);
                 final int currentFlags =
                         permissionsState.getPermissionFlags(permissionName, userId);
                 if ((currentFlags & queryFlags) != 0) {
@@ -1103,7 +1110,7 @@
                     "setWhitelistedRestrictedPermissions for user " + userId);
         }
 
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+        final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
         if (pkg == null) {
             return false;
         }
@@ -1132,7 +1139,7 @@
                         + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
             }
             final List<String> whitelistedPermissions =
-                    getWhitelistedRestrictedPermissions(pkg.packageName, flags, userId);
+                    getWhitelistedRestrictedPermissions(pkg.getPackageName(), flags, userId);
             if (permissions == null || permissions.isEmpty()) {
                 if (whitelistedPermissions == null || whitelistedPermissions.isEmpty()) {
                     return true;
@@ -1206,8 +1213,10 @@
                 false, // requirePermissionWhenSameUser
                 "grantRuntimePermission");
 
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
-        if (pkg == null || pkg.mExtras == null) {
+        final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
+        final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+                packageName);
+        if (pkg == null || ps == null) {
             Log.e(TAG, "Unknown package: " + packageName);
             return;
         }
@@ -1222,21 +1231,19 @@
             throw new IllegalArgumentException("Unknown package: " + packageName);
         }
 
-        bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg);
+        bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, ps);
 
         // If a permission review is required for legacy apps we represent
         // their permissions as always granted runtime ones since we need
         // to keep the review required permission flag per user while an
         // install permission's state is shared across all users.
-        if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
+        if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M
                 && bp.isRuntime()) {
             return;
         }
 
-        final int uid = UserHandle.getUid(userId,
-                UserHandle.getAppId(pkg.applicationInfo.uid));
+        final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.getUid()));
 
-        final PackageSetting ps = (PackageSetting) pkg.mExtras;
         final PermissionsState permissionsState = ps.getPermissionsState();
 
         final int flags = permissionsState.getPermissionFlags(permName, userId);
@@ -1259,7 +1266,8 @@
         }
 
         if (bp.isSoftRestricted() && !SoftRestrictedPermissionPolicy.forPermission(mContext,
-                pkg.applicationInfo, UserHandle.of(userId), permName).mayGrantPermission()) {
+                pkg.toAppInfoWithoutState(), UserHandle.of(userId), permName)
+                .mayGrantPermission()) {
             Log.e(TAG, "Cannot grant soft restricted permission " + permName + " for package "
                     + packageName);
             return;
@@ -1282,7 +1290,7 @@
                     + permName + " for package " + packageName);
         }
 
-        if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+        if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M) {
             Slog.w(TAG, "Cannot grant runtime permission to a legacy app");
             return;
         }
@@ -1295,7 +1303,7 @@
 
             case PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
                 if (callback != null) {
-                    callback.onGidsChanged(UserHandle.getAppId(pkg.applicationInfo.uid), userId);
+                    callback.onGidsChanged(UserHandle.getAppId(pkg.getUid()), userId);
                 }
             }
             break;
@@ -1368,8 +1376,10 @@
                 false, // requirePermissionWhenSameUser
                 "revokeRuntimePermission");
 
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
-        if (pkg == null || pkg.mExtras == null) {
+        final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
+        final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+                packageName);
+        if (pkg == null || ps == null) {
             Log.e(TAG, "Unknown package: " + packageName);
             return;
         }
@@ -1381,18 +1391,17 @@
             throw new IllegalArgumentException("Unknown permission: " + permName);
         }
 
-        bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg);
+        bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, ps);
 
         // If a permission review is required for legacy apps we represent
         // their permissions as always granted runtime ones since we need
         // to keep the review required permission flag per user while an
         // install permission's state is shared across all users.
-        if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
+        if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M
                 && bp.isRuntime()) {
             return;
         }
 
-        final PackageSetting ps = (PackageSetting) pkg.mExtras;
         final PermissionsState permissionsState = ps.getPermissionsState();
 
         final int flags = permissionsState.getPermissionFlags(permName, userId);
@@ -1435,7 +1444,7 @@
 
         if (callback != null) {
             callback.onPermissionRevoked(UserHandle.getUid(userId,
-                    UserHandle.getAppId(pkg.applicationInfo.uid)), userId);
+                    UserHandle.getAppId(pkg.getUid())), userId);
         }
 
         if (bp.isRuntime()) {
@@ -1460,7 +1469,7 @@
                 StorageManager.UUID_PRIVATE_INTERNAL, false, mDefaultPermissionCallback);
         for (final int userId : UserManagerService.getInstance().getUserIds()) {
             mPackageManagerInt.forEachPackage(
-                    (PackageParser.Package pkg) -> resetRuntimePermissionsInternal(pkg, userId));
+                    (AndroidPackage pkg) -> resetRuntimePermissionsInternal(pkg, userId));
         }
     }
 
@@ -1471,9 +1480,9 @@
      * @param userId The device user for which to do a reset.
      */
     @GuardedBy("mLock")
-    private void resetRuntimePermissionsInternal(final PackageParser.Package pkg,
+    private void resetRuntimePermissionsInternal(final AndroidPackage pkg,
             final int userId) {
-        final String packageName = pkg.packageName;
+        final String packageName = pkg.getPackageName();
 
         // These are flags that can change base on user actions.
         final int userSettableMask = FLAG_PERMISSION_USER_SET
@@ -1485,7 +1494,7 @@
                 | FLAG_PERMISSION_POLICY_FIXED;
 
         // Delay and combine non-async permission callbacks
-        final int permissionCount = pkg.requestedPermissions.size();
+        final int permissionCount = ArrayUtils.size(pkg.getRequestedPermissions());
         final boolean[] permissionRemoved = new boolean[1];
         final ArraySet<Long> revokedPermissions = new ArraySet<>();
         final IntArray syncUpdatedUsers = new IntArray(permissionCount);
@@ -1552,7 +1561,7 @@
         };
 
         for (int i = 0; i < permissionCount; i++) {
-            final String permName = pkg.requestedPermissions.get(i);
+            final String permName = pkg.getRequestedPermissions().get(i);
             final BasePermission bp;
             synchronized (mLock) {
                 bp = mSettings.getPermissionLocked(permName);
@@ -1567,7 +1576,7 @@
 
             // If shared user we just reset the state to which only this app contributed.
             final String sharedUserId =
-                    mPackageManagerInt.getSharedUserIdForPackage(pkg.packageName);
+                    mPackageManagerInt.getSharedUserIdForPackage(pkg.getPackageName());
             final String[] pkgNames =
                     mPackageManagerInt.getPackagesForSharedUserId(sharedUserId, userId);
             if (pkgNames != null && pkgNames.length > 0) {
@@ -1575,10 +1584,10 @@
                 final int packageCount = pkgNames.length;
                 for (int j = 0; j < packageCount; j++) {
                     final String sharedPkgName = pkgNames[j];
-                    final PackageParser.Package sharedPkg =
+                    final AndroidPackage sharedPkg =
                             mPackageManagerInt.getPackage(sharedPkgName);
-                    if (sharedPkg != null && !sharedPkg.packageName.equals(packageName)
-                            && sharedPkg.requestedPermissions.contains(permName)) {
+                    if (sharedPkg != null && !sharedPkg.getPackageName().equals(packageName)
+                            && sharedPkg.getRequestedPermissions().contains(permName)) {
                         used = true;
                         break;
                     }
@@ -1999,15 +2008,16 @@
             return protectionLevel;
         }
         // Normalize package name to handle renamed packages and static libs
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+        final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
         if (pkg == null) {
             return protectionLevel;
         }
-        if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
+        if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.O) {
             return protectionLevelMasked;
         }
         // Apps that target O see flags for all protection levels.
-        final PackageSetting ps = (PackageSetting) pkg.mExtras;
+        final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+                pkg.getPackageName());
         if (ps == null) {
             return protectionLevel;
         }
@@ -2028,35 +2038,35 @@
      * @param permissionCallback Callback for permission changed
      */
     private void revokeRuntimePermissionsIfGroupChanged(
-            @NonNull PackageParser.Package newPackage,
-            @NonNull PackageParser.Package oldPackage,
+            @NonNull AndroidPackage newPackage,
+            @NonNull AndroidPackage oldPackage,
             @NonNull ArrayList<String> allPackageNames,
             @NonNull PermissionCallback permissionCallback) {
-        final int numOldPackagePermissions = oldPackage.permissions.size();
+        final int numOldPackagePermissions = ArrayUtils.size(oldPackage.getPermissions());
         final ArrayMap<String, String> oldPermissionNameToGroupName
                 = new ArrayMap<>(numOldPackagePermissions);
 
         for (int i = 0; i < numOldPackagePermissions; i++) {
-            final PackageParser.Permission permission = oldPackage.permissions.get(i);
+            final ParsedPermission permission = oldPackage.getPermissions().get(i);
 
-            if (permission.group != null) {
-                oldPermissionNameToGroupName.put(permission.info.name,
-                        permission.group.info.name);
+            if (permission.parsedPermissionGroup != null) {
+                oldPermissionNameToGroupName.put(permission.getName(),
+                        permission.parsedPermissionGroup.getName());
             }
         }
 
         final int callingUid = Binder.getCallingUid();
-        final int numNewPackagePermissions = newPackage.permissions.size();
+        final int numNewPackagePermissions = ArrayUtils.size(newPackage.getPermissions());
         for (int newPermissionNum = 0; newPermissionNum < numNewPackagePermissions;
                 newPermissionNum++) {
-            final PackageParser.Permission newPermission =
-                    newPackage.permissions.get(newPermissionNum);
-            final int newProtection = newPermission.info.getProtection();
+            final ParsedPermission newPermission =
+                    newPackage.getPermissions().get(newPermissionNum);
+            final int newProtection = newPermission.getProtection();
 
             if ((newProtection & PermissionInfo.PROTECTION_DANGEROUS) != 0) {
-                final String permissionName = newPermission.info.name;
-                final String newPermissionGroupName =
-                        newPermission.group == null ? null : newPermission.group.info.name;
+                final String permissionName = newPermission.getName();
+                final String newPermissionGroupName = newPermission.parsedPermissionGroup == null
+                        ? null : newPermission.parsedPermissionGroup.getName();
                 final String oldPermissionGroupName = oldPermissionNameToGroupName.get(
                         permissionName);
 
@@ -2074,7 +2084,7 @@
                                     userId);
                             if (permissionState == PackageManager.PERMISSION_GRANTED) {
                                 EventLog.writeEvent(0x534e4554, "72710897",
-                                        newPackage.applicationInfo.uid,
+                                        newPackage.getUid(),
                                         "Revoking permission " + permissionName +
                                         " from package " + packageName +
                                         " as the group changed from " + oldPermissionGroupName +
@@ -2095,54 +2105,56 @@
         }
     }
 
-    private void addAllPermissions(PackageParser.Package pkg, boolean chatty) {
-        final int N = pkg.permissions.size();
+    private void addAllPermissions(AndroidPackage pkg, boolean chatty) {
+        final int N = ArrayUtils.size(pkg.getPermissions());
         for (int i=0; i<N; i++) {
-            PackageParser.Permission p = pkg.permissions.get(i);
+            ParsedPermission p = pkg.getPermissions().get(i);
 
             // Assume by default that we did not install this permission into the system.
-            p.info.flags &= ~PermissionInfo.FLAG_INSTALLED;
+            p.flags &= ~PermissionInfo.FLAG_INSTALLED;
 
             synchronized (PermissionManagerService.this.mLock) {
                 // Now that permission groups have a special meaning, we ignore permission
                 // groups for legacy apps to prevent unexpected behavior. In particular,
                 // permissions for one app being granted to someone just because they happen
                 // to be in a group defined by another app (before this had no implications).
-                if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
-                    p.group = mSettings.mPermissionGroups.get(p.info.group);
+                if (pkg.getTargetSdkVersion() > Build.VERSION_CODES.LOLLIPOP_MR1) {
+                    p.parsedPermissionGroup = mSettings.mPermissionGroups.get(p.getGroup());
                     // Warn for a permission in an unknown group.
                     if (DEBUG_PERMISSIONS
-                            && p.info.group != null && p.group == null) {
-                        Slog.i(TAG, "Permission " + p.info.name + " from package "
-                                + p.info.packageName + " in an unknown group " + p.info.group);
+                            && p.getGroup() != null && p.parsedPermissionGroup == null) {
+                        Slog.i(TAG, "Permission " + p.getName() + " from package "
+                                + p.getPackageName() + " in an unknown group " + p.getGroup());
                     }
                 }
 
                 if (p.tree) {
                     final BasePermission bp = BasePermission.createOrUpdate(
-                            mSettings.getPermissionTreeLocked(p.info.name), p, pkg,
+                            mPackageManagerInt,
+                            mSettings.getPermissionTreeLocked(p.getName()), p, pkg,
                             mSettings.getAllPermissionTreesLocked(), chatty);
-                    mSettings.putPermissionTreeLocked(p.info.name, bp);
+                    mSettings.putPermissionTreeLocked(p.getName(), bp);
                 } else {
                     final BasePermission bp = BasePermission.createOrUpdate(
-                            mSettings.getPermissionLocked(p.info.name),
+                            mPackageManagerInt,
+                            mSettings.getPermissionLocked(p.getName()),
                             p, pkg, mSettings.getAllPermissionTreesLocked(), chatty);
-                    mSettings.putPermissionLocked(p.info.name, bp);
+                    mSettings.putPermissionLocked(p.getName(), bp);
                 }
             }
         }
     }
 
-    private void addAllPermissionGroups(PackageParser.Package pkg, boolean chatty) {
-        final int N = pkg.permissionGroups.size();
+    private void addAllPermissionGroups(AndroidPackage pkg, boolean chatty) {
+        final int N = ArrayUtils.size(pkg.getPermissionGroups());
         StringBuilder r = null;
         for (int i=0; i<N; i++) {
-            final PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i);
-            final PackageParser.PermissionGroup cur = mSettings.mPermissionGroups.get(pg.info.name);
-            final String curPackageName = (cur == null) ? null : cur.info.packageName;
-            final boolean isPackageUpdate = pg.info.packageName.equals(curPackageName);
+            final ParsedPermissionGroup pg = pkg.getPermissionGroups().get(i);
+            final ParsedPermissionGroup cur = mSettings.mPermissionGroups.get(pg.getName());
+            final String curPackageName = (cur == null) ? null : cur.getPackageName();
+            final boolean isPackageUpdate = pg.getPackageName().equals(curPackageName);
             if (cur == null || isPackageUpdate) {
-                mSettings.mPermissionGroups.put(pg.info.name, pg);
+                mSettings.mPermissionGroups.put(pg.getName(), pg);
                 if (chatty && DEBUG_PACKAGE_SCANNING) {
                     if (r == null) {
                         r = new StringBuilder(256);
@@ -2152,12 +2164,12 @@
                     if (isPackageUpdate) {
                         r.append("UPD:");
                     }
-                    r.append(pg.info.name);
+                    r.append(pg.getName());
                 }
             } else {
-                Slog.w(TAG, "Permission group " + pg.info.name + " from package "
-                        + pg.info.packageName + " ignored: original from "
-                        + cur.info.packageName);
+                Slog.w(TAG, "Permission group " + pg.getName() + " from package "
+                        + pg.getPackageName() + " ignored: original from "
+                        + cur.getPackageName());
                 if (chatty && DEBUG_PACKAGE_SCANNING) {
                     if (r == null) {
                         r = new StringBuilder(256);
@@ -2165,7 +2177,7 @@
                         r.append(' ');
                     }
                     r.append("DUP:");
-                    r.append(pg.info.name);
+                    r.append(pg.getName());
                 }
             }
         }
@@ -2175,15 +2187,15 @@
 
     }
 
-    private void removeAllPermissions(PackageParser.Package pkg, boolean chatty) {
+    private void removeAllPermissions(AndroidPackage pkg, boolean chatty) {
         synchronized (mLock) {
-            int N = pkg.permissions.size();
+            int N = ArrayUtils.size(pkg.getPermissions());
             StringBuilder r = null;
             for (int i=0; i<N; i++) {
-                PackageParser.Permission p = pkg.permissions.get(i);
-                BasePermission bp = (BasePermission) mSettings.mPermissions.get(p.info.name);
+                ParsedPermission p = pkg.getPermissions().get(i);
+                BasePermission bp = mSettings.mPermissions.get(p.getName());
                 if (bp == null) {
-                    bp = mSettings.mPermissionTrees.get(p.info.name);
+                    bp = mSettings.mPermissionTrees.get(p.getName());
                 }
                 if (bp != null && bp.isPermission(p)) {
                     bp.setPermission(null);
@@ -2193,14 +2205,14 @@
                         } else {
                             r.append(' ');
                         }
-                        r.append(p.info.name);
+                        r.append(p.getName());
                     }
                 }
                 if (p.isAppOp()) {
                     ArraySet<String> appOpPkgs =
-                            mSettings.mAppOpPermissionPackages.get(p.info.name);
+                            mSettings.mAppOpPermissionPackages.get(p.getName());
                     if (appOpPkgs != null) {
-                        appOpPkgs.remove(pkg.packageName);
+                        appOpPkgs.remove(pkg.getPackageName());
                     }
                 }
             }
@@ -2208,14 +2220,14 @@
                 if (DEBUG_REMOVE) Log.d(TAG, "  Permissions: " + r);
             }
 
-            N = pkg.requestedPermissions.size();
+            N = pkg.getRequestedPermissions().size();
             r = null;
             for (int i=0; i<N; i++) {
-                String perm = pkg.requestedPermissions.get(i);
+                String perm = pkg.getRequestedPermissions().get(i);
                 if (mSettings.isPermissionAppOp(perm)) {
                     ArraySet<String> appOpPkgs = mSettings.mAppOpPermissionPackages.get(perm);
                     if (appOpPkgs != null) {
-                        appOpPkgs.remove(pkg.packageName);
+                        appOpPkgs.remove(pkg.getPackageName());
                         if (appOpPkgs.isEmpty()) {
                             mSettings.mAppOpPermissionPackages.remove(perm);
                         }
@@ -2244,7 +2256,7 @@
      * @param packageOfInterest If this is the name of {@code pkg} add extra logging
      * @param callback Result call back
      */
-    private void restorePermissionState(@NonNull PackageParser.Package pkg, boolean replace,
+    private void restorePermissionState(@NonNull AndroidPackage pkg, boolean replace,
             @Nullable String packageOfInterest, @Nullable PermissionCallback callback) {
         // IMPORTANT: There are two types of permissions: install and runtime.
         // Install time permissions are granted when the app is installed to
@@ -2257,7 +2269,8 @@
         // being upgraded to target a newer SDK, in which case dangerous permissions
         // are transformed from install time to runtime ones.
 
-        final PackageSetting ps = (PackageSetting) pkg.mExtras;
+        final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+                pkg.getPackageName());
         if (ps == null) {
             return;
         }
@@ -2298,23 +2311,25 @@
         synchronized (mLock) {
             ArraySet<String> newImplicitPermissions = new ArraySet<>();
 
-            final int N = pkg.requestedPermissions.size();
+            final int N = pkg.getRequestedPermissions().size();
             for (int i = 0; i < N; i++) {
-                final String permName = pkg.requestedPermissions.get(i);
+                final String permName = pkg.getRequestedPermissions().get(i);
                 final BasePermission bp = mSettings.getPermissionLocked(permName);
                 final boolean appSupportsRuntimePermissions =
-                        pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M;
+                        pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M;
                 String upgradedActivityRecognitionPermission = null;
 
                 if (DEBUG_INSTALL) {
-                    Log.i(TAG, "Package " + pkg.packageName + " checking " + permName + ": " + bp);
+                    Log.i(TAG, "Package " + pkg.getPackageName()
+                            + " checking " + permName + ": " + bp);
                 }
 
                 if (bp == null || bp.getSourcePackageSetting() == null) {
-                    if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
+                    if (packageOfInterest == null || packageOfInterest.equals(
+                            pkg.getPackageName())) {
                         if (DEBUG_PERMISSIONS) {
                             Slog.i(TAG, "Unknown permission " + permName
-                                    + " in package " + pkg.packageName);
+                                    + " in package " + pkg.getPackageName());
                         }
                     }
                     continue;
@@ -2323,14 +2338,14 @@
                 // Cache newImplicitPermissions before modifing permissionsState as for the shared
                 // uids the original and new state are the same object
                 if (!origPermissions.hasRequestedPermission(permName)
-                        && (pkg.implicitPermissions.contains(permName)
+                        && (pkg.getImplicitPermissions().contains(permName)
                                 || (permName.equals(Manifest.permission.ACTIVITY_RECOGNITION)))) {
-                    if (pkg.implicitPermissions.contains(permName)) {
+                    if (pkg.getImplicitPermissions().contains(permName)) {
                         // If permName is an implicit permission, try to auto-grant
                         newImplicitPermissions.add(permName);
 
                         if (DEBUG_PERMISSIONS) {
-                            Slog.i(TAG, permName + " is newly added for " + pkg.packageName);
+                            Slog.i(TAG, permName + " is newly added for " + pkg.getPackageName());
                         }
                     } else {
                         // Special case for Activity Recognition permission. Even if AR permission
@@ -2353,7 +2368,7 @@
 
                                 if (DEBUG_PERMISSIONS) {
                                     Slog.i(TAG, permName + " is newly added for "
-                                            + pkg.packageName);
+                                            + pkg.getPackageName());
                                 }
                                 break;
                             }
@@ -2362,10 +2377,10 @@
                 }
 
                 // Limit ephemeral apps to ephemeral allowed permissions.
-                if (pkg.applicationInfo.isInstantApp() && !bp.isInstant()) {
+                if (pkg.isInstantApp() && !bp.isInstant()) {
                     if (DEBUG_PERMISSIONS) {
                         Log.i(TAG, "Denying non-ephemeral permission " + bp.getName()
-                                + " for package " + pkg.packageName);
+                                + " for package " + pkg.getPackageName());
                     }
                     continue;
                 }
@@ -2373,7 +2388,7 @@
                 if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) {
                     if (DEBUG_PERMISSIONS) {
                         Log.i(TAG, "Denying runtime-only permission " + bp.getName()
-                                + " for package " + pkg.packageName);
+                                + " for package " + pkg.getPackageName());
                     }
                     continue;
                 }
@@ -2384,7 +2399,7 @@
 
                 // Keep track of app op permissions.
                 if (bp.isAppOp()) {
-                    mSettings.addAppOpPackage(perm, pkg.packageName);
+                    mSettings.addAppOpPackage(perm, pkg.getPackageName());
                 }
 
                 if (bp.isNormal()) {
@@ -2410,7 +2425,7 @@
 
                 if (DEBUG_PERMISSIONS) {
                     Slog.i(TAG, "Considering granting permission " + perm + " to package "
-                            + pkg.packageName);
+                            + pkg.getPackageName());
                 }
 
                 if (grant != GRANT_DENIED) {
@@ -2696,10 +2711,10 @@
 
                         default: {
                             if (packageOfInterest == null
-                                    || packageOfInterest.equals(pkg.packageName)) {
+                                    || packageOfInterest.equals(pkg.getPackageName())) {
                                 if (DEBUG_PERMISSIONS) {
                                     Slog.i(TAG, "Not granting permission " + perm
-                                            + " to package " + pkg.packageName
+                                            + " to package " + pkg.getPackageName()
                                             + " because it was previously installed without");
                                 }
                             }
@@ -2714,9 +2729,9 @@
                         changedInstallPermission = true;
                         if (DEBUG_PERMISSIONS) {
                             Slog.i(TAG, "Un-granting permission " + perm
-                                    + " from package " + pkg.packageName
+                                    + " from package " + pkg.getPackageName()
                                     + " (protectionLevel=" + bp.getProtectionLevel()
-                                    + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
+                                    + " flags=0x" + Integer.toHexString(pkg.getFlags())
                                     + ")");
                         }
                     } else if (bp.isAppOp()) {
@@ -2724,11 +2739,11 @@
                         // not to be granted, there is a UI for the user to decide.
                         if (DEBUG_PERMISSIONS
                                 && (packageOfInterest == null
-                                        || packageOfInterest.equals(pkg.packageName))) {
+                                        || packageOfInterest.equals(pkg.getPackageName()))) {
                             Slog.i(TAG, "Not granting permission " + perm
-                                    + " to package " + pkg.packageName
+                                    + " to package " + pkg.getPackageName()
                                     + " (protectionLevel=" + bp.getProtectionLevel()
-                                    + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
+                                    + " flags=0x" + Integer.toHexString(pkg.getFlags())
                                     + ")");
                         }
                     }
@@ -2758,7 +2773,7 @@
         }
 
         for (int userId : updatedUserIds) {
-            notifyRuntimePermissionStateChanged(pkg.packageName, userId);
+            notifyRuntimePermissionStateChanged(pkg.getPackageName(), userId);
         }
     }
 
@@ -2774,10 +2789,10 @@
      * @return The updated value of the {@code updatedUserIds} parameter
      */
     private @NonNull int[] revokePermissionsNoLongerImplicitLocked(
-            @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
+            @NonNull PermissionsState ps, @NonNull AndroidPackage pkg,
             @NonNull int[] updatedUserIds) {
-        String pkgName = pkg.packageName;
-        boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion
+        String pkgName = pkg.getPackageName();
+        boolean supportsRuntimePermissions = pkg.getTargetSdkVersion()
                 >= Build.VERSION_CODES.M;
 
         int[] users = UserManagerService.getInstance().getUserIds();
@@ -2786,7 +2801,7 @@
             int userId = users[i];
 
             for (String permission : ps.getPermissions(userId)) {
-                if (!pkg.implicitPermissions.contains(permission)) {
+                if (!pkg.getImplicitPermissions().contains(permission)) {
                     if (!ps.hasInstallPermission(permission)) {
                         int flags = ps.getRuntimePermissionState(permission, userId).getFlags();
 
@@ -2836,9 +2851,9 @@
      */
     private void inheritPermissionStateToNewImplicitPermissionLocked(
             @NonNull ArraySet<String> sourcePerms, @NonNull String newPerm,
-            @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
+            @NonNull PermissionsState ps, @NonNull AndroidPackage pkg,
             @UserIdInt int userId) {
-        String pkgName = pkg.packageName;
+        String pkgName = pkg.getPackageName();
         boolean isGranted = false;
         int flags = 0;
 
@@ -2885,10 +2900,10 @@
      * @return The ids of the users that are changed
      */
     private @NonNull int[] checkIfLegacyStorageOpsNeedToBeUpdated(
-            @NonNull PackageParser.Package pkg, boolean replace, @NonNull int[] updatedUserIds) {
-        if (replace && pkg.applicationInfo.hasRequestedLegacyExternalStorage() && (
-                pkg.requestedPermissions.contains(READ_EXTERNAL_STORAGE)
-                        || pkg.requestedPermissions.contains(WRITE_EXTERNAL_STORAGE))) {
+            @NonNull AndroidPackage pkg, boolean replace, @NonNull int[] updatedUserIds) {
+        if (replace && pkg.hasRequestedLegacyExternalStorage() && (
+                pkg.getRequestedPermissions().contains(READ_EXTERNAL_STORAGE)
+                        || pkg.getRequestedPermissions().contains(WRITE_EXTERNAL_STORAGE))) {
             return UserManagerService.getInstance().getUserIds();
         }
 
@@ -2907,10 +2922,10 @@
      */
     private @NonNull int[] setInitialGrantForNewImplicitPermissionsLocked(
             @NonNull PermissionsState origPs,
-            @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
+            @NonNull PermissionsState ps, @NonNull AndroidPackage pkg,
             @NonNull ArraySet<String> newImplicitPermissions,
             @NonNull int[] updatedUserIds) {
-        String pkgName = pkg.packageName;
+        String pkgName = pkg.getPackageName();
         ArrayMap<String, ArraySet<String>> newToSplitPerms = new ArrayMap<>();
 
         final List<SplitPermissionInfoParcelable> permissionList = getSplitPermissions();
@@ -2990,17 +3005,17 @@
                 SystemConfig.getInstance().getSplitPermissions());
     }
 
-    private boolean isNewPlatformPermissionForPackage(String perm, PackageParser.Package pkg) {
+    private boolean isNewPlatformPermissionForPackage(String perm, AndroidPackage pkg) {
         boolean allowed = false;
         final int NP = PackageParser.NEW_PERMISSIONS.length;
         for (int ip=0; ip<NP; ip++) {
             final PackageParser.NewPermissionInfo npi
                     = PackageParser.NEW_PERMISSIONS[ip];
             if (npi.name.equals(perm)
-                    && pkg.applicationInfo.targetSdkVersion < npi.sdkVersion) {
+                    && pkg.getTargetSdkVersion() < npi.sdkVersion) {
                 allowed = true;
                 Log.i(TAG, "Auto-granting " + perm + " to old pkg "
-                        + pkg.packageName);
+                        + pkg.getPackageName());
                 break;
             }
         }
@@ -3014,29 +3029,26 @@
      *
      * <p>This handles parent/child apps.
      */
-    private boolean hasPrivappWhitelistEntry(String perm, PackageParser.Package pkg) {
-        ArraySet<String> wlPermissions = null;
+    private boolean hasPrivappWhitelistEntry(String perm, AndroidPackage pkg) {
+        ArraySet<String> wlPermissions;
         if (pkg.isVendor()) {
             wlPermissions =
-                    SystemConfig.getInstance().getVendorPrivAppPermissions(pkg.packageName);
+                    SystemConfig.getInstance().getVendorPrivAppPermissions(pkg.getPackageName());
         } else if (pkg.isProduct()) {
             wlPermissions =
-                    SystemConfig.getInstance().getProductPrivAppPermissions(pkg.packageName);
+                    SystemConfig.getInstance().getProductPrivAppPermissions(pkg.getPackageName());
         } else if (pkg.isSystemExt()) {
             wlPermissions =
                     SystemConfig.getInstance().getSystemExtPrivAppPermissions(
-                            pkg.packageName);
+                            pkg.getPackageName());
         } else {
-            wlPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg.packageName);
+            wlPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg.getPackageName());
         }
-        // Let's check if this package is whitelisted...
-        boolean whitelisted = wlPermissions != null && wlPermissions.contains(perm);
-        // If it's not, we'll also tail-recurse to the parent.
-        return whitelisted ||
-                pkg.parentPackage != null && hasPrivappWhitelistEntry(perm, pkg.parentPackage);
+
+        return wlPermissions != null && wlPermissions.contains(perm);
     }
 
-    private boolean grantSignaturePermission(String perm, PackageParser.Package pkg,
+    private boolean grantSignaturePermission(String perm, AndroidPackage pkg,
             BasePermission bp, PermissionsState origPermissions) {
         boolean oemPermission = bp.isOEM();
         boolean vendorPrivilegedPermission = bp.isVendorPrivileged();
@@ -3044,7 +3056,7 @@
         boolean privappPermissionsDisable =
                 RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE;
         boolean platformPermission = PLATFORM_PACKAGE_NAME.equals(bp.getSourcePackageName());
-        boolean platformPackage = PLATFORM_PACKAGE_NAME.equals(pkg.packageName);
+        boolean platformPackage = PLATFORM_PACKAGE_NAME.equals(pkg.getPackageName());
         if (!privappPermissionsDisable && privilegedPermission && pkg.isPrivileged()
                 && !platformPackage && platformPermission) {
             if (!hasPrivappWhitelistEntry(perm, pkg)) {
@@ -3054,22 +3066,22 @@
                     ArraySet<String> deniedPermissions = null;
                     if (pkg.isVendor()) {
                         deniedPermissions = SystemConfig.getInstance()
-                                .getVendorPrivAppDenyPermissions(pkg.packageName);
+                                .getVendorPrivAppDenyPermissions(pkg.getPackageName());
                     } else if (pkg.isProduct()) {
                         deniedPermissions = SystemConfig.getInstance()
-                                .getProductPrivAppDenyPermissions(pkg.packageName);
+                                .getProductPrivAppDenyPermissions(pkg.getPackageName());
                     } else if (pkg.isSystemExt()) {
                         deniedPermissions = SystemConfig.getInstance()
-                                .getSystemExtPrivAppDenyPermissions(pkg.packageName);
+                                .getSystemExtPrivAppDenyPermissions(pkg.getPackageName());
                     } else {
                         deniedPermissions = SystemConfig.getInstance()
-                                .getPrivAppDenyPermissions(pkg.packageName);
+                                .getPrivAppDenyPermissions(pkg.getPackageName());
                     }
                     final boolean permissionViolation =
                             deniedPermissions == null || !deniedPermissions.contains(perm);
                     if (permissionViolation) {
                         Slog.w(TAG, "Privileged permission " + perm + " for package "
-                                + pkg.packageName + " (" + pkg.codePath
+                                + pkg.getPackageName() + " (" + pkg.getCodePath()
                                 + ") not in privapp-permissions whitelist");
 
                         if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) {
@@ -3077,7 +3089,7 @@
                                 mPrivappPermissionsViolations = new ArraySet<>();
                             }
                             mPrivappPermissionsViolations.add(
-                                    pkg.packageName + " (" + pkg.codePath + "): " + perm);
+                                    pkg.getPackageName() + " (" + pkg.getCodePath() + "): " + perm);
                         }
                     } else {
                         return false;
@@ -3091,7 +3103,7 @@
         // expect single system package
         String systemPackageName = ArrayUtils.firstOrNull(mPackageManagerInt.getKnownPackageNames(
                 PackageManagerInternal.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM));
-        final PackageParser.Package systemPackage =
+        final AndroidPackage systemPackage =
                 mPackageManagerInt.getPackage(systemPackageName);
 
         // check if the package is allow to use this signature permission.  A package is allowed to
@@ -3102,24 +3114,23 @@
         //       package, and the defining package still trusts the old certificate for permissions
         //     - or it shares the above relationships with the system package
         boolean allowed =
-                pkg.mSigningDetails.hasAncestorOrSelf(
+                pkg.getSigningDetails().hasAncestorOrSelf(
                         bp.getSourcePackageSetting().getSigningDetails())
                 || bp.getSourcePackageSetting().getSigningDetails().checkCapability(
-                        pkg.mSigningDetails,
+                        pkg.getSigningDetails(),
                         PackageParser.SigningDetails.CertCapabilities.PERMISSION)
-                || pkg.mSigningDetails.hasAncestorOrSelf(systemPackage.mSigningDetails)
-                || systemPackage.mSigningDetails.checkCapability(
-                        pkg.mSigningDetails,
+                || pkg.getSigningDetails().hasAncestorOrSelf(systemPackage.getSigningDetails())
+                || systemPackage.getSigningDetails().checkCapability(
+                        pkg.getSigningDetails(),
                         PackageParser.SigningDetails.CertCapabilities.PERMISSION);
         if (!allowed && (privilegedPermission || oemPermission)) {
             if (pkg.isSystem()) {
                 // For updated system applications, a privileged/oem permission
                 // is granted only if it had been defined by the original application.
                 if (pkg.isUpdatedSystemApp()) {
-                    final PackageParser.Package disabledPkg =
-                            mPackageManagerInt.getDisabledSystemPackage(pkg.packageName);
-                    final PackageSetting disabledPs =
-                            (disabledPkg != null) ? (PackageSetting) disabledPkg.mExtras : null;
+                    final PackageSetting disabledPs = (PackageSetting) mPackageManagerInt
+                            .getDisabledSystemPackage(pkg.getPackageName());
+                    final AndroidPackage disabledPkg = disabledPs == null ? null : disabledPs.pkg;
                     if (disabledPs != null
                             && disabledPs.getPermissionsState().hasInstallPermission(perm)) {
                         // If the original was granted this permission, we take
@@ -3144,40 +3155,10 @@
                                                 && canGrantOemPermission(disabledPs, perm)))) {
                             allowed = true;
                         }
-                        // Also if a privileged parent package on the system image or any of
-                        // its children requested a privileged/oem permission, the updated child
-                        // packages can also get the permission.
-                        if (pkg.parentPackage != null) {
-                            final PackageParser.Package disabledParentPkg = mPackageManagerInt
-                                    .getDisabledSystemPackage(pkg.parentPackage.packageName);
-                            final PackageSetting disabledParentPs = (disabledParentPkg != null)
-                                    ? (PackageSetting) disabledParentPkg.mExtras : null;
-                            if (disabledParentPkg != null
-                                    && ((privilegedPermission && disabledParentPs.isPrivileged())
-                                            || (oemPermission && disabledParentPs.isOem()))) {
-                                if (isPackageRequestingPermission(disabledParentPkg, perm)
-                                        && canGrantOemPermission(disabledParentPs, perm)) {
-                                    allowed = true;
-                                } else if (disabledParentPkg.childPackages != null) {
-                                    for (PackageParser.Package disabledChildPkg
-                                            : disabledParentPkg.childPackages) {
-                                        final PackageSetting disabledChildPs =
-                                                (disabledChildPkg != null)
-                                                        ? (PackageSetting) disabledChildPkg.mExtras
-                                                        : null;
-                                        if (isPackageRequestingPermission(disabledChildPkg, perm)
-                                                && canGrantOemPermission(
-                                                        disabledChildPs, perm)) {
-                                            allowed = true;
-                                            break;
-                                        }
-                                    }
-                                }
-                            }
-                        }
                     }
                 } else {
-                    final PackageSetting ps = (PackageSetting) pkg.mExtras;
+                    final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+                            pkg.getPackageName());
                     allowed = (privilegedPermission && pkg.isPrivileged())
                             || (oemPermission && pkg.isOem()
                                     && canGrantOemPermission(ps, perm));
@@ -3188,7 +3169,8 @@
                 if (allowed && privilegedPermission &&
                         !vendorPrivilegedPermission && pkg.isVendor()) {
                    Slog.w(TAG, "Permission " + perm + " cannot be granted to privileged vendor apk "
-                           + pkg.packageName + " because it isn't a 'vendorPrivileged' permission.");
+                           + pkg.getPackageName()
+                           + " because it isn't a 'vendorPrivileged' permission.");
                    allowed = false;
                 }
             }
@@ -3196,7 +3178,7 @@
         if (!allowed) {
             if (!allowed
                     && bp.isPre23()
-                    && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+                    && pkg.getTargetSdkVersion() < Build.VERSION_CODES.M) {
                 // If this was a previously normal/dangerous permission that got moved
                 // to a system permission as part of the runtime permission redesign, then
                 // we still want to blindly grant it to old apps.
@@ -3208,9 +3190,10 @@
             if (!allowed && bp.isInstaller()
                     && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
                             PackageManagerInternal.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM),
-                    pkg.packageName) || ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
-                            PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER,
-                    UserHandle.USER_SYSTEM), pkg.packageName)) {
+                    pkg.getPackageName()) || ArrayUtils.contains(
+                            mPackageManagerInt.getKnownPackageNames(
+                                    PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER,
+                    UserHandle.USER_SYSTEM), pkg.getPackageName())) {
                 // If this permission is to be granted to the system installer and
                 // this app is an installer, then it gets the permission.
                 allowed = true;
@@ -3218,7 +3201,7 @@
             if (!allowed && bp.isVerifier()
                     && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
                             PackageManagerInternal.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM),
-                    pkg.packageName)) {
+                    pkg.getPackageName())) {
                 // If this permission is to be granted to the system verifier and
                 // this app is a verifier, then it gets the permission.
                 allowed = true;
@@ -3236,7 +3219,7 @@
             if (!allowed && bp.isSetup()
                     && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
                             PackageManagerInternal.PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM),
-                    pkg.packageName)) {
+                    pkg.getPackageName())) {
                 // If this permission is to be granted to the system setup wizard and
                 // this app is a setup wizard, then it gets the permission.
                 allowed = true;
@@ -3244,28 +3227,28 @@
             if (!allowed && bp.isSystemTextClassifier()
                     && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
                             PackageManagerInternal.PACKAGE_SYSTEM_TEXT_CLASSIFIER,
-                    UserHandle.USER_SYSTEM), pkg.packageName)) {
+                    UserHandle.USER_SYSTEM), pkg.getPackageName())) {
                 // Special permissions for the system default text classifier.
                 allowed = true;
             }
             if (!allowed && bp.isConfigurator()
                     && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
                             PackageManagerInternal.PACKAGE_CONFIGURATOR,
-                    UserHandle.USER_SYSTEM), pkg.packageName)) {
+                    UserHandle.USER_SYSTEM), pkg.getPackageName())) {
                 // Special permissions for the device configurator.
                 allowed = true;
             }
             if (!allowed && bp.isWellbeing()
                     && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
                             PackageManagerInternal.PACKAGE_WELLBEING, UserHandle.USER_SYSTEM),
-                    pkg.packageName)) {
+                    pkg.getPackageName())) {
                 // Special permission granted only to the OEM specified wellbeing app
                 allowed = true;
             }
             if (!allowed && bp.isDocumenter()
                     && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
                             PackageManagerInternal.PACKAGE_DOCUMENTER, UserHandle.USER_SYSTEM),
-                    pkg.packageName)) {
+                    pkg.getPackageName())) {
                 // If this permission is to be granted to the documenter and
                 // this app is the documenter, then it gets the permission.
                 allowed = true;
@@ -3273,7 +3256,7 @@
             if (!allowed && bp.isIncidentReportApprover()
                     && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
                             PackageManagerInternal.PACKAGE_INCIDENT_REPORT_APPROVER,
-                    UserHandle.USER_SYSTEM), pkg.packageName)) {
+                    UserHandle.USER_SYSTEM), pkg.getPackageName())) {
                 // If this permission is to be granted to the incident report approver and
                 // this app is the incident report approver, then it gets the permission.
                 allowed = true;
@@ -3281,14 +3264,14 @@
             if (!allowed && bp.isAppPredictor()
                     && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
                             PackageManagerInternal.PACKAGE_APP_PREDICTOR, UserHandle.USER_SYSTEM),
-                    pkg.packageName)) {
+                    pkg.getPackageName())) {
                 // Special permissions for the system app predictor.
                 allowed = true;
             }
             if (!allowed && bp.isTelephony()
                     && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
                         PackageManagerInternal.PACKAGE_TELEPHONY, UserHandle.USER_SYSTEM),
-                    pkg.packageName)) {
+                    pkg.getPackageName())) {
                 // Special permissions for the system telephony apps.
                 allowed = true;
             }
@@ -3310,26 +3293,27 @@
         return Boolean.TRUE == granted;
     }
 
-    private boolean isPermissionsReviewRequired(@NonNull PackageParser.Package pkg,
+    private boolean isPermissionsReviewRequired(@NonNull AndroidPackage pkg,
             @UserIdInt int userId) {
         // Permission review applies only to apps not supporting the new permission model.
-        if (pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M) {
+        if (pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M) {
             return false;
         }
 
         // Legacy apps have the permission and get user consent on launch.
-        if (pkg.mExtras == null) {
+        final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+                pkg.getPackageName());
+        if (ps == null) {
             return false;
         }
-        final PackageSetting ps = (PackageSetting) pkg.mExtras;
         final PermissionsState permissionsState = ps.getPermissionsState();
         return permissionsState.isPermissionReviewRequired(userId);
     }
 
-    private boolean isPackageRequestingPermission(PackageParser.Package pkg, String permission) {
-        final int permCount = pkg.requestedPermissions.size();
+    private boolean isPackageRequestingPermission(AndroidPackage pkg, String permission) {
+        final int permCount = pkg.getRequestedPermissions().size();
         for (int j = 0; j < permCount; j++) {
-            String requestedPermission = pkg.requestedPermissions.get(j);
+            String requestedPermission = pkg.getRequestedPermissions().get(j);
             if (permission.equals(requestedPermission)) {
                 return true;
             }
@@ -3337,41 +3321,7 @@
         return false;
     }
 
-    @GuardedBy("mLock")
-    private void grantRuntimePermissionsGrantedToDisabledPackageLocked(
-            PackageParser.Package pkg, int callingUid, PermissionCallback callback) {
-        if (pkg.parentPackage == null) {
-            return;
-        }
-        if (pkg.requestedPermissions == null) {
-            return;
-        }
-        final PackageParser.Package disabledPkg =
-                mPackageManagerInt.getDisabledSystemPackage(pkg.parentPackage.packageName);
-        if (disabledPkg == null || disabledPkg.mExtras == null) {
-            return;
-        }
-        final PackageSetting disabledPs = (PackageSetting) disabledPkg.mExtras;
-        if (!disabledPs.isPrivileged() || disabledPs.hasChildPackages()) {
-            return;
-        }
-        final int permCount = pkg.requestedPermissions.size();
-        for (int i = 0; i < permCount; i++) {
-            String permission = pkg.requestedPermissions.get(i);
-            BasePermission bp = mSettings.getPermissionLocked(permission);
-            if (bp == null || !(bp.isRuntime() || bp.isDevelopment())) {
-                continue;
-            }
-            for (int userId : mUserManagerInt.getUserIds()) {
-                if (disabledPs.getPermissionsState().hasRuntimePermission(permission, userId)) {
-                    grantRuntimePermissionInternal(
-                            permission, pkg.packageName, false, callingUid, userId, callback);
-                }
-            }
-        }
-    }
-
-    private void grantRequestedRuntimePermissions(PackageParser.Package pkg, int[] userIds,
+    private void grantRequestedRuntimePermissions(AndroidPackage pkg, int[] userIds,
             String[] grantedPermissions, int callingUid, PermissionCallback callback) {
         for (int userId : userIds) {
             grantRequestedRuntimePermissionsForUser(pkg, userId, grantedPermissions, callingUid,
@@ -3379,9 +3329,10 @@
         }
     }
 
-    private void grantRequestedRuntimePermissionsForUser(PackageParser.Package pkg, int userId,
+    private void grantRequestedRuntimePermissionsForUser(AndroidPackage pkg, int userId,
             String[] grantedPermissions, int callingUid, PermissionCallback callback) {
-        PackageSetting ps = (PackageSetting) pkg.mExtras;
+        PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
+                pkg.getPackageName());
         if (ps == null) {
             return;
         }
@@ -3394,12 +3345,12 @@
         final int compatFlags = PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED
                 | PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
 
-        final boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion
+        final boolean supportsRuntimePermissions = pkg.getTargetSdkVersion()
                 >= Build.VERSION_CODES.M;
 
-        final boolean instantApp = mPackageManagerInt.isInstantApp(pkg.packageName, userId);
+        final boolean instantApp = mPackageManagerInt.isInstantApp(pkg.getPackageName(), userId);
 
-        for (String permission : pkg.requestedPermissions) {
+        for (String permission : pkg.getRequestedPermissions()) {
             final BasePermission bp;
             synchronized (mLock) {
                 bp = mSettings.getPermissionLocked(permission);
@@ -3413,14 +3364,14 @@
                 if (supportsRuntimePermissions) {
                     // Installer cannot change immutable permissions.
                     if ((flags & immutableFlags) == 0) {
-                        grantRuntimePermissionInternal(permission, pkg.packageName, false,
+                        grantRuntimePermissionInternal(permission, pkg.getPackageName(), false,
                                 callingUid, userId, callback);
                     }
                 } else {
                     // In permission review mode we clear the review flag and the revoked compat
                     // flag when we are asked to install the app with all permissions granted.
                     if ((flags & compatFlags) != 0) {
-                        updatePermissionFlagsInternal(permission, pkg.packageName, compatFlags,
+                        updatePermissionFlagsInternal(permission, pkg.getPackageName(), compatFlags,
                                 0, callingUid, userId, false, callback);
                     }
                 }
@@ -3428,11 +3379,11 @@
         }
     }
 
-    private void setWhitelistedRestrictedPermissionsForUser(@NonNull PackageParser.Package pkg,
+    private void setWhitelistedRestrictedPermissionsForUser(@NonNull AndroidPackage pkg,
             @UserIdInt int userId, @Nullable List<String> permissions, int callingUid,
             @PermissionWhitelistFlags int whitelistFlags, PermissionCallback callback) {
         final PermissionsState permissionsState =
-                PackageManagerServiceUtils.getPermissionsState(pkg);
+                PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg);
         if (permissionsState == null) {
             return;
         }
@@ -3440,9 +3391,9 @@
         ArraySet<String> oldGrantedRestrictedPermissions = null;
         boolean updatePermissions = false;
 
-        final int permissionCount = pkg.requestedPermissions.size();
+        final int permissionCount = pkg.getRequestedPermissions().size();
         for (int i = 0; i < permissionCount; i++) {
-            final String permissionName = pkg.requestedPermissions.get(i);
+            final String permissionName = pkg.getRequestedPermissions().get(i);
 
             final BasePermission bp = mSettings.getPermissionLocked(permissionName);
 
@@ -3518,19 +3469,19 @@
 
             // If we are whitelisting an app that does not support runtime permissions
             // we need to make sure it goes through the permission review UI at launch.
-            if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
+            if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M
                     && !wasWhitelisted && isWhitelisted) {
                 mask |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
                 newFlags |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
             }
 
-            updatePermissionFlagsInternal(permissionName, pkg.packageName, mask, newFlags,
+            updatePermissionFlagsInternal(permissionName, pkg.getPackageName(), mask, newFlags,
                     callingUid, userId, false, null /*callback*/);
         }
 
         if (updatePermissions) {
             // Update permission of this app to take into account the new whitelist state.
-            restorePermissionState(pkg, false, pkg.packageName, callback);
+            restorePermissionState(pkg, false, pkg.getPackageName(), callback);
 
             // If this resulted in losing a permission we need to kill the app.
             if (oldGrantedRestrictedPermissions != null) {
@@ -3539,9 +3490,9 @@
                     final String permission = oldGrantedRestrictedPermissions.valueAt(i);
                     // Sometimes we create a new permission state instance during update.
                     final PermissionsState newPermissionsState =
-                            PackageManagerServiceUtils.getPermissionsState(pkg);
+                            PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg);
                     if (!newPermissionsState.hasPermission(permission, userId)) {
-                        callback.onPermissionRevoked(pkg.applicationInfo.uid, userId);
+                        callback.onPermissionRevoked(pkg.getUid(), userId);
                         break;
                     }
                 }
@@ -3554,17 +3505,17 @@
             SharedUserSetting suSetting, int[] allUserIds) {
         // Collect all used permissions in the UID
         final ArraySet<String> usedPermissions = new ArraySet<>();
-        final List<PackageParser.Package> pkgList = suSetting.getPackages();
+        final List<AndroidPackage> pkgList = suSetting.getPackages();
         if (pkgList == null || pkgList.size() == 0) {
             return EmptyArray.INT;
         }
-        for (PackageParser.Package pkg : pkgList) {
-            if (pkg.requestedPermissions == null) {
+        for (AndroidPackage pkg : pkgList) {
+            if (pkg.getRequestedPermissions() == null) {
                 continue;
             }
-            final int requestedPermCount = pkg.requestedPermissions.size();
+            final int requestedPermCount = pkg.getRequestedPermissions().size();
             for (int j = 0; j < requestedPermCount; j++) {
-                String permission = pkg.requestedPermissions.get(j);
+                String permission = pkg.getRequestedPermissions().get(j);
                 BasePermission bp = mSettings.getPermissionLocked(permission);
                 if (bp != null) {
                     usedPermissions.add(permission);
@@ -3626,18 +3577,12 @@
      * @param allPackages All currently known packages
      * @param callback Callback to call after permission changes
      */
-    private void updatePermissions(@NonNull String packageName, @Nullable PackageParser.Package pkg,
+    private void updatePermissions(@NonNull String packageName, @Nullable AndroidPackage pkg,
             @NonNull PermissionCallback callback) {
         final int flags =
                 (pkg != null ? UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG : 0);
         updatePermissions(
                 packageName, pkg, getVolumeUuidForPackage(pkg), flags, callback);
-        if (pkg != null && pkg.childPackages != null) {
-            for (PackageParser.Package childPkg : pkg.childPackages) {
-                updatePermissions(childPkg.packageName, childPkg,
-                        getVolumeUuidForPackage(childPkg), flags, callback);
-            }
-        }
     }
 
     /**
@@ -3673,10 +3618,9 @@
                 // Only system declares background permissions, hence mapping does never change.
                 mBackgroundPermissions = new ArrayMap<>();
                 for (BasePermission bp : mSettings.getAllPermissionsLocked()) {
-                    if (bp.perm != null && bp.perm.info != null
-                            && bp.perm.info.backgroundPermission != null) {
+                    if (bp.perm != null && bp.perm.backgroundPermission != null) {
                         String fgPerm = bp.name;
-                        String bgPerm = bp.perm.info.backgroundPermission;
+                        String bgPerm = bp.perm.backgroundPermission;
 
                         List<String> fgPerms = mBackgroundPermissions.get(bgPerm);
                         if (fgPerms == null) {
@@ -3737,7 +3681,7 @@
      * @param callback Callback to call after permission changes
      */
     private void updatePermissions(final @Nullable String changingPkgName,
-            final @Nullable PackageParser.Package changingPkg,
+            final @Nullable AndroidPackage changingPkg,
             final @Nullable String replaceVolumeUuid,
             @UpdatePermissionFlags int flags,
             final @Nullable PermissionCallback callback) {
@@ -3770,7 +3714,7 @@
         // Now update the permissions for all packages.
         if ((flags & UPDATE_PERMISSIONS_ALL) != 0) {
             final boolean replaceAll = ((flags & UPDATE_PERMISSIONS_REPLACE_ALL) != 0);
-            mPackageManagerInt.forEachPackage((Package pkg) -> {
+            mPackageManagerInt.forEachPackage((AndroidPackage pkg) -> {
                 if (pkg == changingPkg) {
                     return;
                 }
@@ -3809,7 +3753,7 @@
      * @return {@code true} if a permission source package might have changed
      */
     private boolean updatePermissionSourcePackage(@Nullable String packageName,
-            @Nullable PackageParser.Package pkg,
+            @Nullable AndroidPackage pkg,
             final @Nullable PermissionCallback callback) {
         boolean changed = false;
 
@@ -3832,8 +3776,8 @@
                             for (int userIdNum = 0; userIdNum < numUserIds; userIdNum++) {
                                 final int userId = userIds[userIdNum];
 
-                                mPackageManagerInt.forEachPackage((Package p) -> {
-                                    final String pName = p.packageName;
+                                mPackageManagerInt.forEachPackage((AndroidPackage p) -> {
+                                    final String pName = p.getPackageName();
                                     final ApplicationInfo appInfo =
                                             mPackageManagerInt.getApplicationInfo(pName, 0,
                                                     Process.SYSTEM_UID, UserHandle.USER_SYSTEM);
@@ -3878,11 +3822,13 @@
         }
         if (needsUpdate != null) {
             for (final BasePermission bp : needsUpdate) {
-                final PackageParser.Package sourcePkg =
+                final AndroidPackage sourcePkg =
                         mPackageManagerInt.getPackage(bp.getSourcePackageName());
+                final PackageSetting sourcePs =
+                        (PackageSetting) mPackageManagerInt.getPackageSetting(
+                                bp.getSourcePackageName());
                 synchronized (mLock) {
-                    if (sourcePkg != null && sourcePkg.mExtras != null) {
-                        final PackageSetting sourcePs = (PackageSetting) sourcePkg.mExtras;
+                    if (sourcePkg != null && sourcePs != null) {
                         if (bp.getSourcePackageSetting() == null) {
                             bp.setSourcePackageSetting(sourcePs);
                         }
@@ -3915,7 +3861,7 @@
      * @return {@code true} if a permission tree ownership might have changed
      */
     private boolean updatePermissionTreeSourcePackage(@Nullable String packageName,
-            @Nullable PackageParser.Package pkg) {
+            @Nullable AndroidPackage pkg) {
         boolean changed = false;
 
         Set<BasePermission> needsUpdate = null;
@@ -3941,11 +3887,13 @@
         }
         if (needsUpdate != null) {
             for (final BasePermission bp : needsUpdate) {
-                final PackageParser.Package sourcePkg =
+                final AndroidPackage sourcePkg =
                         mPackageManagerInt.getPackage(bp.getSourcePackageName());
+                final PackageSetting sourcePs =
+                        (PackageSetting) mPackageManagerInt.getPackageSetting(
+                                bp.getSourcePackageName());
                 synchronized (mLock) {
-                    if (sourcePkg != null && sourcePkg.mExtras != null) {
-                        final PackageSetting sourcePs = (PackageSetting) sourcePkg.mExtras;
+                    if (sourcePkg != null && sourcePs != null) {
                         if (bp.getSourcePackageSetting() == null) {
                             bp.setSourcePackageSetting(sourcePs);
                         }
@@ -4068,24 +4016,28 @@
         }
     }
 
-    private static String getVolumeUuidForPackage(PackageParser.Package pkg) {
+    private static String getVolumeUuidForPackage(AndroidPackage pkg) {
         if (pkg == null) {
             return StorageManager.UUID_PRIVATE_INTERNAL;
         }
         if (pkg.isExternal()) {
-            if (TextUtils.isEmpty(pkg.volumeUuid)) {
+            if (TextUtils.isEmpty(pkg.getVolumeUuid())) {
                 return StorageManager.UUID_PRIMARY_PHYSICAL;
             } else {
-                return pkg.volumeUuid;
+                return pkg.getVolumeUuid();
             }
         } else {
             return StorageManager.UUID_PRIVATE_INTERNAL;
         }
     }
 
-    private static boolean hasPermission(PackageParser.Package pkgInfo, String permName) {
-        for (int i=pkgInfo.permissions.size()-1; i>=0; i--) {
-            if (pkgInfo.permissions.get(i).info.name.equals(permName)) {
+    private static boolean hasPermission(AndroidPackage pkg, String permName) {
+        if (pkg.getPermissions() == null) {
+            return false;
+        }
+
+        for (int i = pkg.getPermissions().size() - 1; i >= 0; i--) {
+            if (pkg.getPermissions().get(i).getName().equals(permName)) {
                 return true;
             }
         }
@@ -4124,37 +4076,39 @@
             PermissionManagerService.this.systemReady();
         }
         @Override
-        public boolean isPermissionsReviewRequired(@NonNull Package pkg, @UserIdInt int userId) {
+        public boolean isPermissionsReviewRequired(@NonNull AndroidPackage pkg,
+                @UserIdInt int userId) {
             return PermissionManagerService.this.isPermissionsReviewRequired(pkg, userId);
         }
+
         @Override
         public void revokeRuntimePermissionsIfGroupChanged(
-                @NonNull PackageParser.Package newPackage,
-                @NonNull PackageParser.Package oldPackage,
+                @NonNull AndroidPackage newPackage,
+                @NonNull AndroidPackage oldPackage,
                 @NonNull ArrayList<String> allPackageNames) {
             PermissionManagerService.this.revokeRuntimePermissionsIfGroupChanged(newPackage,
                     oldPackage, allPackageNames, mDefaultPermissionCallback);
         }
         @Override
-        public void addAllPermissions(Package pkg, boolean chatty) {
+        public void addAllPermissions(AndroidPackage pkg, boolean chatty) {
             PermissionManagerService.this.addAllPermissions(pkg, chatty);
         }
         @Override
-        public void addAllPermissionGroups(Package pkg, boolean chatty) {
+        public void addAllPermissionGroups(AndroidPackage pkg, boolean chatty) {
             PermissionManagerService.this.addAllPermissionGroups(pkg, chatty);
         }
         @Override
-        public void removeAllPermissions(Package pkg, boolean chatty) {
+        public void removeAllPermissions(AndroidPackage pkg, boolean chatty) {
             PermissionManagerService.this.removeAllPermissions(pkg, chatty);
         }
         @Override
-        public void grantRequestedRuntimePermissions(PackageParser.Package pkg, int[] userIds,
+        public void grantRequestedRuntimePermissions(AndroidPackage pkg, int[] userIds,
                 String[] grantedPermissions, int callingUid) {
             PermissionManagerService.this.grantRequestedRuntimePermissions(
                     pkg, userIds, grantedPermissions, callingUid, mDefaultPermissionCallback);
         }
         @Override
-        public void setWhitelistedRestrictedPermissions(@NonNull PackageParser.Package pkg,
+        public void setWhitelistedRestrictedPermissions(@NonNull AndroidPackage pkg,
                 @NonNull int[] userIds, @Nullable List<String> permissions, int callingUid,
                 @PackageManager.PermissionWhitelistFlags int flags) {
             for (int userId : userIds) {
@@ -4169,13 +4123,7 @@
                     packageName, permissions, flags, userId);
         }
         @Override
-        public void grantRuntimePermissionsGrantedToDisabledPackage(PackageParser.Package pkg,
-                int callingUid) {
-            PermissionManagerService.this.grantRuntimePermissionsGrantedToDisabledPackageLocked(
-                    pkg, callingUid, mDefaultPermissionCallback);
-        }
-        @Override
-        public void updatePermissions(@NonNull String packageName, @Nullable Package pkg) {
+        public void updatePermissions(@NonNull String packageName, @Nullable AndroidPackage pkg) {
             PermissionManagerService.this
                     .updatePermissions(packageName, pkg, mDefaultPermissionCallback);
         }
@@ -4185,13 +4133,13 @@
                     .updateAllPermissions(volumeUuid, sdkUpdated, mDefaultPermissionCallback);
         }
         @Override
-        public void resetRuntimePermissions(Package pkg, int userId) {
+        public void resetRuntimePermissions(AndroidPackage pkg, int userId) {
             PermissionManagerService.this.resetRuntimePermissionsInternal(pkg, userId);
         }
         @Override
         public void resetAllRuntimePermissions(final int userId) {
             mPackageManagerInt.forEachPackage(
-                    (PackageParser.Package pkg) -> resetRuntimePermissionsInternal(pkg, userId));
+                    (AndroidPackage pkg) -> resetRuntimePermissionsInternal(pkg, userId));
         }
         @Override
         public String[] getAppOpPermissionPackages(String permName, int callingUid) {
@@ -4237,9 +4185,9 @@
                 for (int i = 0; i < numTotalPermissions; i++) {
                     BasePermission bp = mSettings.mPermissions.valueAt(i);
 
-                    if (bp.perm != null && bp.perm.info != null
-                            && bp.perm.info.getProtection() == protection) {
-                        matchingPermissions.add(bp.perm.info);
+                    if (bp.perm != null && bp.perm.getProtection() == protection) {
+                        matchingPermissions.add(
+                                PackageInfoUtils.generatePermissionInfo(bp.perm, 0));
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index fb5c6fdd..0f22619 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -21,8 +21,8 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
 import android.content.pm.PermissionInfo;
+import android.content.pm.parsing.AndroidPackage;
 import android.permission.PermissionManagerInternal;
 
 import java.util.ArrayList;
@@ -175,16 +175,14 @@
 
     public abstract void systemReady();
 
-    public abstract boolean isPermissionsReviewRequired(@NonNull PackageParser.Package pkg,
+    public abstract boolean isPermissionsReviewRequired(@NonNull AndroidPackage pkg,
             @UserIdInt int userId);
 
-    public abstract void grantRuntimePermissionsGrantedToDisabledPackage(
-            @NonNull PackageParser.Package pkg, int callingUid);
     public abstract void grantRequestedRuntimePermissions(
-            @NonNull PackageParser.Package pkg, @NonNull int[] userIds,
+            @NonNull AndroidPackage pkg, @NonNull int[] userIds,
             @NonNull String[] grantedPermissions, int callingUid);
     public abstract void setWhitelistedRestrictedPermissions(
-            @NonNull PackageParser.Package pkg, @NonNull int[] userIds,
+            @NonNull AndroidPackage pkg, @NonNull int[] userIds,
             @NonNull List<String> permissions, int callingUid,
             @PackageManager.PermissionWhitelistFlags int whitelistFlags);
     /** Sets the whitelisted, restricted permissions for the given package. */
@@ -206,7 +204,7 @@
      * @param callback Callback to call after permission changes
      */
     public abstract void updatePermissions(@NonNull String packageName,
-            @Nullable PackageParser.Package pkg);
+            @Nullable AndroidPackage pkg);
 
     /**
      * Update all permissions for all apps.
@@ -226,7 +224,7 @@
      * Resets any user permission state changes (eg. permissions and flags) of all
      * packages installed for the given user.
      *
-     * @see #resetRuntimePermissions(android.content.pm.PackageParser.Package, int)
+     * @see #resetRuntimePermissions(AndroidPackage, int)
      */
     public abstract void resetAllRuntimePermissions(@UserIdInt int userId);
 
@@ -234,7 +232,7 @@
      * Resets any user permission state changes (eg. permissions and flags) of the
      * specified package for the given user.
      */
-    public abstract void resetRuntimePermissions(@NonNull PackageParser.Package pkg,
+    public abstract void resetRuntimePermissions(@NonNull AndroidPackage pkg,
             @UserIdInt int userId);
 
     /**
@@ -247,8 +245,8 @@
      * @param allPackageNames All packages
      */
     public abstract void revokeRuntimePermissionsIfGroupChanged(
-            @NonNull PackageParser.Package newPackage,
-            @NonNull PackageParser.Package oldPackage,
+            @NonNull AndroidPackage newPackage,
+            @NonNull AndroidPackage oldPackage,
             @NonNull ArrayList<String> allPackageNames);
 
     /**
@@ -257,9 +255,9 @@
      * NOTE: argument {@code groupTEMP} is temporary until mPermissionGroups is moved to
      * the permission settings.
      */
-    public abstract void addAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty);
-    public abstract void addAllPermissionGroups(@NonNull PackageParser.Package pkg, boolean chatty);
-    public abstract void removeAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty);
+    public abstract void addAllPermissions(@NonNull AndroidPackage pkg, boolean chatty);
+    public abstract void addAllPermissionGroups(@NonNull AndroidPackage pkg, boolean chatty);
+    public abstract void removeAllPermissions(@NonNull AndroidPackage pkg, boolean chatty);
 
     /** Retrieve the packages that have requested the given app op permission */
     public abstract @Nullable String[] getAppOpPermissionPackages(
diff --git a/services/core/java/com/android/server/pm/permission/PermissionSettings.java b/services/core/java/com/android/server/pm/permission/PermissionSettings.java
index 3d8cf2d..254b720 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionSettings.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionSettings.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.ComponentParseUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
@@ -65,8 +65,8 @@
      * name to permission group object.
      */
     @GuardedBy("mLock")
-    final ArrayMap<String, PackageParser.PermissionGroup> mPermissionGroups =
-            new ArrayMap<String, PackageParser.PermissionGroup>();
+    final ArrayMap<String, ComponentParseUtils.ParsedPermissionGroup> mPermissionGroups =
+            new ArrayMap<>();
 
     /**
      * Set of packages that request a particular app op. The mapping is from permission
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 3c4e3f6..5f39f51 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -29,18 +29,16 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.AppOpsManager;
-import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageManagerInternal.PackageListObserver;
-import android.content.pm.PackageParser;
 import android.content.pm.PermissionInfo;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.Build;
 import android.os.Process;
 import android.os.RemoteException;
@@ -171,23 +169,6 @@
         } catch (RemoteException doesNotHappen) {
             Slog.wtf(LOG_TAG, "Cannot set up app-ops listener");
         }
-
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
-        intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
-        intentFilter.addDataScheme("package");
-
-        getContext().registerReceiverAsUser(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                UserHandle user =
-                        UserHandle.getUserHandleForUid(intent.getIntExtra(Intent.EXTRA_UID, -1));
-                new PermissionControllerManager(
-                        getUserContext(getContext(), user), FgThread.getHandler())
-                        .updateUserSensitive();
-            }
-        }, UserHandle.ALL, intentFilter, null, null);
-
     }
 
     /**
@@ -376,10 +357,10 @@
                 pkg.sharedUserId, userId);
         if (sharedPkgNames != null) {
             for (String sharedPkgName : sharedPkgNames) {
-                final PackageParser.Package sharedPkg = packageManagerInternal
+                final AndroidPackage sharedPkg = packageManagerInternal
                         .getPackage(sharedPkgName);
                 if (sharedPkg != null) {
-                    synchroniser.addPackage(sharedPkg.packageName);
+                    synchroniser.addPackage(sharedPkg.getPackageName());
                 }
             }
         }
@@ -396,7 +377,8 @@
                 PackageManagerInternal.class);
         final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser(
                 getUserContext(getContext(), UserHandle.of(userId)));
-        packageManagerInternal.forEachPackage((pkg) -> synchronizer.addPackage(pkg.packageName));
+        packageManagerInternal.forEachPackage(
+                (pkg) -> synchronizer.addPackage(pkg.getPackageName()));
         synchronizer.syncPackages();
     }
 
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 3e528f4..8435a82 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -5432,7 +5432,7 @@
     }
 
     @Override
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(ROTATION_MODE, mDefaultDisplayRotation.getUserRotationMode());
         proto.write(ROTATION, mDefaultDisplayRotation.getUserRotation());
@@ -5445,7 +5445,7 @@
         proto.write(KEYGUARD_OCCLUDED_CHANGED, mKeyguardOccludedChanged);
         proto.write(KEYGUARD_OCCLUDED_PENDING, mPendingKeyguardOccluded);
         if (mKeyguardDelegate != null) {
-            mKeyguardDelegate.writeToProto(proto, KEYGUARD_DELEGATE);
+            mKeyguardDelegate.dumpDebug(proto, KEYGUARD_DELEGATE);
         }
         proto.end(token);
     }
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 1f37faf..95a5f52 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -1404,7 +1404,7 @@
      *
      * @param proto The protocol buffer output stream to write to.
      */
-    void writeToProto(ProtoOutputStream proto, long fieldId);
+    void dumpDebug(ProtoOutputStream proto, long fieldId);
 
     /**
      * Returns whether a given window type is considered a top level one.
diff --git a/services/core/java/com/android/server/policy/WindowOrientationListener.java b/services/core/java/com/android/server/policy/WindowOrientationListener.java
index 47370b6..0157706 100644
--- a/services/core/java/com/android/server/policy/WindowOrientationListener.java
+++ b/services/core/java/com/android/server/policy/WindowOrientationListener.java
@@ -259,7 +259,7 @@
      */
     public abstract void onProposedRotationChanged(int rotation);
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         synchronized (mLock) {
             proto.write(ENABLED, mEnabled);
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index c408549..9b67efe 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -413,7 +413,7 @@
         }
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(SHOWING, mKeyguardState.showing);
         proto.write(OCCLUDED, mKeyguardState.occluded);
diff --git a/services/core/java/com/android/server/power/AttentionDetector.java b/services/core/java/com/android/server/power/AttentionDetector.java
index ed7d234..eec0d5f 100644
--- a/services/core/java/com/android/server/power/AttentionDetector.java
+++ b/services/core/java/com/android/server/power/AttentionDetector.java
@@ -16,6 +16,7 @@
 
 package com.android.server.power;
 
+import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE;
 import static android.provider.Settings.System.ADAPTIVE_SLEEP;
 
 import android.Manifest;
@@ -33,6 +34,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.service.attention.AttentionService;
 import android.util.Slog;
@@ -58,6 +60,22 @@
     private static final String TAG = "AttentionDetector";
     private static final boolean DEBUG = false;
 
+    /**
+     * DeviceConfig flag name, describes how much in advance to start checking attention before the
+     * dim event.
+     */
+    static final String KEY_PRE_DIM_CHECK_DURATION_MILLIS = "pre_dim_check_duration_millis";
+
+    /** Default value in absence of {@link DeviceConfig} override. */
+    static final long DEFAULT_PRE_DIM_CHECK_DURATION_MILLIS = 2_000;
+
+    /** DeviceConfig flag name, describes how long to run the check beyond the screen dim event. */
+    static final String KEY_POST_DIM_CHECK_DURATION_MILLIS =
+            "post_dim_check_duration_millis";
+
+    /** Default value in absence of {@link DeviceConfig} override. */
+    static final long DEFAULT_POST_DIM_CHECK_DURATION_MILLIS = 0;
+
     private Context mContext;
 
     private boolean mIsSettingEnabled;
@@ -90,11 +108,6 @@
     protected int mRequestId;
 
     /**
-     * {@link android.service.attention.AttentionService} API timeout.
-     */
-    private long mMaxAttentionApiTimeoutMillis;
-
-    /**
      * Last known user activity.
      */
     private long mLastUserActivityTime;
@@ -124,6 +137,9 @@
     @VisibleForTesting
     AttentionCallbackInternalImpl mCallback;
 
+    /** Keep the last used post dim timeout for the dumpsys. */
+    private long mLastPostDimTimeout;
+
     public AttentionDetector(Runnable onUserAttention, Object lock) {
         mOnUserAttention = onUserAttention;
         mLock = lock;
@@ -149,8 +165,6 @@
         mWindowManager = LocalServices.getService(WindowManagerInternal.class);
         mMaximumExtensionMillis = context.getResources().getInteger(
                 com.android.internal.R.integer.config_attentionMaximumExtension);
-        mMaxAttentionApiTimeoutMillis = context.getResources().getInteger(
-                com.android.internal.R.integer.config_attentionApiTimeout);
 
         try {
             final UserSwitchObserver observer = new UserSwitchObserver();
@@ -169,7 +183,8 @@
                 }, UserHandle.USER_ALL);
     }
 
-    public long updateUserActivity(long nextScreenDimming) {
+    /** To be called in {@link PowerManagerService#updateUserActivitySummaryLocked}. */
+    public long updateUserActivity(long nextScreenDimming, long dimDurationMillis) {
         if (nextScreenDimming == mLastActedOnNextScreenDimming
                 || !mIsSettingEnabled
                 || mWindowManager.isKeyguardShowingAndNotOccluded()) {
@@ -184,7 +199,7 @@
         }
 
         final long now = SystemClock.uptimeMillis();
-        final long whenToCheck = nextScreenDimming - getAttentionTimeout();
+        final long whenToCheck = nextScreenDimming - getPreDimCheckDurationMillis();
         final long whenToStopExtending = mLastUserActivityTime + mMaximumExtensionMillis;
         if (now < whenToCheck) {
             if (DEBUG) {
@@ -213,7 +228,9 @@
         mLastActedOnNextScreenDimming = nextScreenDimming;
         mCallback = new AttentionCallbackInternalImpl(mRequestId);
         Slog.v(TAG, "Checking user attention, ID: " + mRequestId);
-        final boolean sent = mAttentionManager.checkAttention(getAttentionTimeout(), mCallback);
+        final boolean sent = mAttentionManager.checkAttention(
+                getPreDimCheckDurationMillis() + getPostDimCheckDurationMillis(dimDurationMillis),
+                mCallback);
         if (!sent) {
             mRequested.set(false);
         }
@@ -272,11 +289,6 @@
         }
     }
 
-    @VisibleForTesting
-    long getAttentionTimeout() {
-        return mMaxAttentionApiTimeoutMillis;
-    }
-
     /**
      * {@see AttentionManagerInternal#isAttentionServiceSupported}
      */
@@ -301,12 +313,44 @@
         pw.println("AttentionDetector:");
         pw.println(" mIsSettingEnabled=" + mIsSettingEnabled);
         pw.println(" mMaximumExtensionMillis=" + mMaximumExtensionMillis);
-        pw.println(" mMaxAttentionApiTimeoutMillis=" + mMaxAttentionApiTimeoutMillis);
+        pw.println(" preDimCheckDurationMillis=" + getPreDimCheckDurationMillis());
+        pw.println(" postDimCheckDurationMillis=" + mLastPostDimTimeout);
         pw.println(" mLastUserActivityTime(excludingAttention)=" + mLastUserActivityTime);
         pw.println(" mAttentionServiceSupported=" + isAttentionServiceSupported());
         pw.println(" mRequested=" + mRequested);
     }
 
+    /** How long to check <b>before</b> the screen dims, capped at the dim duration. */
+    @VisibleForTesting
+    protected long getPreDimCheckDurationMillis() {
+        final long millis = DeviceConfig.getLong(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_PRE_DIM_CHECK_DURATION_MILLIS,
+                DEFAULT_PRE_DIM_CHECK_DURATION_MILLIS);
+
+        if (millis < 0 || millis > 13_000) {
+            Slog.w(TAG, "Bad flag value supplied for: " + KEY_PRE_DIM_CHECK_DURATION_MILLIS);
+            return DEFAULT_PRE_DIM_CHECK_DURATION_MILLIS;
+        }
+
+        return millis;
+    }
+
+    /** How long to check <b>after</b> the screen dims, capped at the dim duration. */
+    @VisibleForTesting
+    protected long getPostDimCheckDurationMillis(long dimDurationMillis) {
+        final long millis = DeviceConfig.getLong(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_POST_DIM_CHECK_DURATION_MILLIS,
+                DEFAULT_POST_DIM_CHECK_DURATION_MILLIS);
+
+        if (millis < 0 || millis > 10_000) {
+            Slog.w(TAG, "Bad flag value supplied for: " + KEY_POST_DIM_CHECK_DURATION_MILLIS);
+            return DEFAULT_POST_DIM_CHECK_DURATION_MILLIS;
+        }
+
+        mLastPostDimTimeout = Math.min(millis, dimDurationMillis);
+        return mLastPostDimTimeout;
+    }
+
     @VisibleForTesting
     final class AttentionCallbackInternalImpl extends AttentionCallbackInternal {
         private final int mId;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 9cfd095..93d50b8 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -203,8 +203,11 @@
     // System Property indicating that retail demo mode is currently enabled.
     private static final String SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED = "sys.retaildemo.enabled";
 
-    // Possible reasons for shutting down or reboot for use in REBOOT_PROPERTY(sys.boot.reason)
-    // which is set by bootstat
+    // System property for last reboot reason
+    private static final String SYSTEM_PROPERTY_REBOOT_REASON = "sys.boot.reason";
+
+    // Possible reasons for shutting down or reboot for use in
+    // SYSTEM_PROPERTY_REBOOT_REASON(sys.boot.reason) which is set by bootstat
     private static final String REASON_SHUTDOWN = "shutdown";
     private static final String REASON_REBOOT = "reboot";
     private static final String REASON_USERREQUESTED = "shutdown,userrequested";
@@ -225,9 +228,6 @@
     private static final int HALT_MODE_REBOOT = 1;
     private static final int HALT_MODE_REBOOT_SAFE_MODE = 2;
 
-    // property for last reboot reason
-    private static final String REBOOT_PROPERTY = "sys.boot.reason";
-
     private final Context mContext;
     private final ServiceThread mHandlerThread;
     private final PowerManagerHandler mHandler;
@@ -240,6 +240,7 @@
     private final BinderService mBinderService;
     private final LocalService mLocalService;
     private final NativeWrapper mNativeWrapper;
+    private final SystemPropertiesWrapper mSystemProperties;
     private final Injector mInjector;
 
     private LightsManager mLightsManager;
@@ -756,6 +757,20 @@
         InattentiveSleepWarningController createInattentiveSleepWarningController() {
             return new InattentiveSleepWarningController();
         }
+
+        public SystemPropertiesWrapper createSystemPropertiesWrapper() {
+            return new SystemPropertiesWrapper() {
+                @Override
+                public String get(String key, String def) {
+                    return SystemProperties.get(key, def);
+                }
+
+                @Override
+                public void set(String key, String val) {
+                    SystemProperties.set(key, val);
+                }
+            };
+        }
     }
 
     final Constants mConstants;
@@ -781,6 +796,7 @@
         mBinderService = new BinderService();
         mLocalService = new LocalService();
         mNativeWrapper = injector.createNativeWrapper();
+        mSystemProperties = injector.createSystemPropertiesWrapper();
         mInjector = injector;
 
         mHandlerThread = new ServiceThread(TAG,
@@ -816,7 +832,7 @@
             mHalInteractiveModeEnabled = true;
 
             mWakefulness = WAKEFULNESS_AWAKE;
-            sQuiescent = SystemProperties.get(SYSTEM_PROPERTY_QUIESCENT, "0").equals("1");
+            sQuiescent = mSystemProperties.get(SYSTEM_PROPERTY_QUIESCENT, "0").equals("1");
 
             mNativeWrapper.nativeInit(this);
             mNativeWrapper.nativeSetAutoSuspend(false);
@@ -1067,8 +1083,9 @@
         }
 
         final String retailDemoValue = UserManager.isDeviceInDemoMode(mContext) ? "1" : "0";
-        if (!retailDemoValue.equals(SystemProperties.get(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED))) {
-            SystemProperties.set(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, retailDemoValue);
+        if (!retailDemoValue.equals(
+                mSystemProperties.get(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, null))) {
+            mSystemProperties.set(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, retailDemoValue);
         }
 
         mScreenBrightnessModeSetting = Settings.System.getIntForUser(resolver,
@@ -2140,9 +2157,11 @@
                     nextTimeout = -1;
                 }
 
-                if ((mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0
+                if (((mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0
+                        || (mUserActivitySummary & USER_ACTIVITY_SCREEN_DIM) != 0)
                         && (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) == 0) {
-                    nextTimeout = mAttentionDetector.updateUserActivity(nextTimeout);
+                    nextTimeout = mAttentionDetector.updateUserActivity(nextTimeout,
+                            screenDimDuration);
                 }
 
                 if (nextProfileTimeout > 0) {
@@ -4068,20 +4087,20 @@
             mBatterySaverStateMachine.dumpProto(proto,
                     PowerManagerServiceDumpProto.BATTERY_SAVER_STATE_MACHINE);
 
-            mHandler.getLooper().writeToProto(proto, PowerManagerServiceDumpProto.LOOPER);
+            mHandler.getLooper().dumpDebug(proto, PowerManagerServiceDumpProto.LOOPER);
 
             for (WakeLock wl : mWakeLocks) {
-                wl.writeToProto(proto, PowerManagerServiceDumpProto.WAKE_LOCKS);
+                wl.dumpDebug(proto, PowerManagerServiceDumpProto.WAKE_LOCKS);
             }
 
             for (SuspendBlocker sb : mSuspendBlockers) {
-                sb.writeToProto(proto, PowerManagerServiceDumpProto.SUSPEND_BLOCKERS);
+                sb.dumpDebug(proto, PowerManagerServiceDumpProto.SUSPEND_BLOCKERS);
             }
             wcd = mWirelessChargerDetector;
         }
 
         if (wcd != null) {
-            wcd.writeToProto(proto, PowerManagerServiceDumpProto.WIRELESS_CHARGER_DETECTOR);
+            wcd.dumpDebug(proto, PowerManagerServiceDumpProto.WIRELESS_CHARGER_DETECTOR);
         }
         proto.flush();
     }
@@ -4312,7 +4331,7 @@
             return sb.toString();
         }
 
-        public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        public void dumpDebug(ProtoOutputStream proto, long fieldId) {
             final long wakeLockToken = proto.start(fieldId);
             proto.write(WakeLockProto.LOCK_LEVEL, (mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK));
             proto.write(WakeLockProto.TAG, mTag);
@@ -4333,7 +4352,7 @@
             proto.write(WakeLockProto.PID, mOwnerPid);
 
             if (mWorkSource != null) {
-                mWorkSource.writeToProto(proto, WakeLockProto.WORK_SOURCE);
+                mWorkSource.dumpDebug(proto, WakeLockProto.WORK_SOURCE);
             }
             proto.end(wakeLockToken);
         }
@@ -4436,7 +4455,7 @@
             }
         }
 
-        public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        public void dumpDebug(ProtoOutputStream proto, long fieldId) {
             final long sbToken = proto.start(fieldId);
             synchronized (this) {
                 proto.write(SuspendBlockerProto.NAME, mName);
@@ -4818,7 +4837,7 @@
 
             final long ident = Binder.clearCallingIdentity();
             try {
-                return getLastShutdownReasonInternal(REBOOT_PROPERTY);
+                return getLastShutdownReasonInternal();
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -5052,12 +5071,8 @@
     }
 
     @VisibleForTesting
-    // lastRebootReasonProperty argument to permit testing
-    int getLastShutdownReasonInternal(String lastRebootReasonProperty) {
-        String line = SystemProperties.get(lastRebootReasonProperty);
-        if (line == null) {
-            return PowerManager.SHUTDOWN_REASON_UNKNOWN;
-        }
+    int getLastShutdownReasonInternal() {
+        String line = mSystemProperties.get(SYSTEM_PROPERTY_REBOOT_REASON, null);
         switch (line) {
             case REASON_SHUTDOWN:
                 return PowerManager.SHUTDOWN_REASON_SHUTDOWN;
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 0a6b38f..6da8fb4 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -47,8 +47,8 @@
 import android.view.WindowManager;
 
 import com.android.internal.telephony.ITelephony;
-import com.android.server.RescueParty;
 import com.android.server.LocalServices;
+import com.android.server.RescueParty;
 import com.android.server.pm.PackageManagerService;
 import com.android.server.statusbar.StatusBarManagerInternal;
 
@@ -307,7 +307,9 @@
                             com.android.internal.R.string.reboot_to_update_reboot));
             }
         } else if (mReason != null && mReason.equals(PowerManager.REBOOT_RECOVERY)) {
-            if (RescueParty.isAttemptingFactoryReset()) {
+            if (showSysuiReboot()) {
+                return null;
+            } else if (RescueParty.isAttemptingFactoryReset()) {
                 // We're not actually doing a factory reset yet; we're rebooting
                 // to ask the user if they'd like to reset, so give them a less
                 // scary dialog message.
diff --git a/services/core/java/com/android/server/power/SuspendBlocker.java b/services/core/java/com/android/server/power/SuspendBlocker.java
index 30b35f0..565263f 100644
--- a/services/core/java/com/android/server/power/SuspendBlocker.java
+++ b/services/core/java/com/android/server/power/SuspendBlocker.java
@@ -43,5 +43,5 @@
      */
     void release();
 
-    void writeToProto(ProtoOutputStream proto, long fieldId);
+    void dumpDebug(ProtoOutputStream proto, long fieldId);
 }
diff --git a/services/core/java/com/android/server/power/SystemPropertiesWrapper.java b/services/core/java/com/android/server/power/SystemPropertiesWrapper.java
new file mode 100644
index 0000000..1acf798
--- /dev/null
+++ b/services/core/java/com/android/server/power/SystemPropertiesWrapper.java
@@ -0,0 +1,51 @@
+/*
+ * 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.power;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.SystemProperties;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Wrapper interface to access {@link SystemProperties}.
+ *
+ * @hide
+ */
+@VisibleForTesting
+interface SystemPropertiesWrapper {
+    /**
+     * Get the String value for the given {@code key}.
+     *
+     * @param key the key to lookup
+     * @param def the default value in case the property is not set or empty
+     * @return if the {@code key} isn't found, return {@code def} if it isn't null, or an empty
+     * string otherwise
+     */
+    @NonNull
+    String get(@NonNull String key, @Nullable String def);
+
+    /**
+     * Set the value for the given {@code key} to {@code val}.
+     *
+     * @throws IllegalArgumentException if the {@code val} exceeds 91 characters
+     * @throws RuntimeException if the property cannot be set, for example, if it was blocked by
+     * SELinux. libc will log the underlying reason.
+     */
+    void set(@NonNull String key, @Nullable String val);
+}
diff --git a/services/core/java/com/android/server/power/WirelessChargerDetector.java b/services/core/java/com/android/server/power/WirelessChargerDetector.java
index e8e9c67..0d910e4 100644
--- a/services/core/java/com/android/server/power/WirelessChargerDetector.java
+++ b/services/core/java/com/android/server/power/WirelessChargerDetector.java
@@ -170,7 +170,7 @@
         }
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long wcdToken = proto.start(fieldId);
         synchronized (mLock) {
             proto.write(WirelessChargerDetectorProto.IS_POWERED_WIRELESSLY, mPoweredWirelessly);
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index aac0f90..a4eef9b 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -308,12 +308,12 @@
         ByteArrayOutputStream out = new ByteArrayOutputStream();
 
         pm.forEachInstalledPackage(FunctionalUtils.uncheckExceptions(pkg -> {
-            out.write(pkg.packageName.getBytes());
+            out.write(pkg.getPackageName().getBytes());
             out.write(BitUtils.toBytes(pkg.getLongVersionCode()));
-            out.write(pm.getApplicationEnabledState(pkg.packageName, userId));
+            out.write(pm.getApplicationEnabledState(pkg.getPackageName(), userId));
 
             ArraySet<String> enabledComponents =
-                    pm.getEnabledComponents(pkg.packageName, userId);
+                    pm.getEnabledComponents(pkg.getPackageName(), userId);
             int numComponents = CollectionUtils.size(enabledComponents);
             out.write(numComponents);
             for (int i = 0; i < numComponents; i++) {
@@ -321,12 +321,12 @@
             }
 
             ArraySet<String> disabledComponents =
-                    pm.getDisabledComponents(pkg.packageName, userId);
+                    pm.getDisabledComponents(pkg.getPackageName(), userId);
             numComponents = CollectionUtils.size(disabledComponents);
             for (int i = 0; i < numComponents; i++) {
                 out.write(disabledComponents.valueAt(i).getBytes());
             }
-            for (Signature signature : pkg.mSigningDetails.signatures) {
+            for (Signature signature : pkg.getSigningDetails().signatures) {
                 out.write(signature.toByteArray());
             }
         }), userId);
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 01f29dc..3f5e2a4 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -57,6 +57,7 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.LocalServices;
+import com.android.server.PackageWatchdog;
 import com.android.server.Watchdog;
 import com.android.server.pm.Installer;
 
@@ -67,6 +68,7 @@
 import java.time.Instant;
 import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -82,6 +84,7 @@
 class RollbackManagerServiceImpl extends IRollbackManager.Stub {
 
     private static final String TAG = "RollbackManager";
+    private static final boolean LOCAL_LOGV = false;
 
     // Rollbacks expire after 14 days.
     private static final long DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS =
@@ -220,6 +223,9 @@
                 if (Intent.ACTION_CANCEL_ENABLE_ROLLBACK.equals(intent.getAction())) {
                     int token = intent.getIntExtra(
                             PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN, -1);
+                    if (LOCAL_LOGV) {
+                        Slog.v(TAG, "broadcast=ACTION_CANCEL_ENABLE_ROLLBACK token=" + token);
+                    }
                     synchronized (mLock) {
                         for (NewRollback rollback : mNewRollbacks) {
                             if (rollback.hasToken(token)) {
@@ -269,10 +275,17 @@
                 String action = intent.getAction();
                 if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
                     String packageName = intent.getData().getSchemeSpecificPart();
+                    if (LOCAL_LOGV) {
+                        Slog.v(TAG, "broadcast=ACTION_PACKAGE_REPLACED" + " pkg=" + packageName);
+                    }
                     onPackageReplaced(packageName);
                 }
                 if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
                     String packageName = intent.getData().getSchemeSpecificPart();
+                    if (LOCAL_LOGV) {
+                        Slog.v(TAG, "broadcast=ACTION_PACKAGE_FULLY_REMOVED"
+                                + " pkg=" + packageName);
+                    }
                     onPackageFullyRemoved(packageName);
                 }
             }
@@ -359,7 +372,7 @@
      */
     private void commitRollbackInternal(int rollbackId, List<VersionedPackage> causePackages,
             String callerPackageName, IntentSender statusReceiver) {
-        Slog.i(TAG, "Initiating rollback");
+        Slog.i(TAG, "commitRollback id=" + rollbackId + " caller=" + callerPackageName);
 
         Rollback rollback = getRollbackForId(rollbackId);
         if (rollback == null) {
@@ -444,6 +457,9 @@
     }
 
     void onUnlockUser(int userId) {
+        if (LOCAL_LOGV) {
+            Slog.v(TAG, "onUnlockUser id=" + userId);
+        }
         // In order to ensure that no package begins running while a backup or restore is taking
         // place, onUnlockUser must remain blocked until all pending backups and restores have
         // completed.
@@ -611,6 +627,9 @@
                 if (!now.isBefore(
                         rollbackTimestamp
                                 .plusMillis(mRollbackLifetimeDurationInMillis))) {
+                    if (LOCAL_LOGV) {
+                        Slog.v(TAG, "runExpiration id=" + rollback.info.getRollbackId());
+                    }
                     iter.remove();
                     rollback.delete(mAppDataRollbackHelper);
                 } else if (oldest == null || oldest.isAfter(rollbackTimestamp)) {
@@ -675,6 +694,10 @@
      */
     private boolean enableRollback(
             int installFlags, File newPackageCodePath, @UserIdInt int user, int token) {
+        if (LOCAL_LOGV) {
+            Slog.v(TAG, "enableRollback user=" + user + " token=" + token
+                    + " path=" + newPackageCodePath.getAbsolutePath());
+        }
 
         // Find the session id associated with this install.
         // TODO: It would be nice if package manager or package installer told
@@ -838,6 +861,10 @@
     }
 
     private void snapshotUserDataInternal(String packageName, int[] userIds) {
+        if (LOCAL_LOGV) {
+            Slog.v(TAG, "snapshotUserData pkg=" + packageName
+                    + " users=" + Arrays.toString(userIds));
+        }
         synchronized (mLock) {
             // staged installs
             for (int i = 0; i < mRollbacks.size(); i++) {
@@ -854,6 +881,10 @@
 
     private void restoreUserDataInternal(
             String packageName, int[] userIds, int appId, String seInfo) {
+        if (LOCAL_LOGV) {
+            Slog.v(TAG, "restoreUserData pkg=" + packageName
+                    + " users=" + Arrays.toString(userIds));
+        }
         synchronized (mLock) {
             for (int i = 0; i < mRollbacks.size(); ++i) {
                 Rollback rollback = mRollbacks.get(i);
@@ -1041,6 +1072,9 @@
 
         @Override
         public void onFinished(int sessionId, boolean success) {
+            if (LOCAL_LOGV) {
+                Slog.v(TAG, "SessionCallback.onFinished id=" + sessionId + " success=" + success);
+            }
             NewRollback newRollback;
             synchronized (mLock) {
                 newRollback = getNewRollbackForPackageSessionLocked(sessionId);
@@ -1070,6 +1104,10 @@
      */
     private Rollback completeEnableRollback(NewRollback newRollback, boolean success) {
         Rollback rollback = newRollback.rollback;
+        if (LOCAL_LOGV) {
+            Slog.v(TAG, "completeEnableRollback id="
+                    + rollback.info.getRollbackId() + " success=" + success);
+        }
         if (!success) {
             // The install session was aborted, clean up the pending install.
             rollback.delete(mAppDataRollbackHelper);
@@ -1108,6 +1146,9 @@
 
     @GuardedBy("rollback.getLock")
     private void makeRollbackAvailable(Rollback rollback) {
+        if (LOCAL_LOGV) {
+            Slog.v(TAG, "makeRollbackAvailable id=" + rollback.info.getRollbackId());
+        }
         rollback.makeAvailable();
 
         // TODO(zezeozue): Provide API to explicitly start observing instead
@@ -1160,6 +1201,8 @@
             for (Rollback rollback : mRollbacks) {
                 rollback.dump(ipw);
             }
+            ipw.println();
+            PackageWatchdog.getInstance(mContext).dump(ipw);
         }
     }
 
@@ -1280,6 +1323,11 @@
         final Rollback rollback;
         int parentSessionId = parentSession.getSessionId();
 
+        if (LOCAL_LOGV) {
+            Slog.v(TAG, "createNewRollback id=" + rollbackId
+                    + " user=" + userId + " installer=" + installerPackageName);
+        }
+
         if (parentSession.isStaged()) {
             rollback = mRollbackStore.createStagedRollback(rollbackId, parentSessionId, userId,
                     installerPackageName);
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 83891f6..a626166 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -16,6 +16,13 @@
 
 package com.android.server.rollback;
 
+import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_CRASH;
+import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_NOT_RESPONDING;
+import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_EXPLICIT_HEALTH_CHECK;
+import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH;
+import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN;
+
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -41,6 +48,7 @@
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.PackageWatchdog;
+import com.android.server.PackageWatchdog.FailureReasons;
 import com.android.server.PackageWatchdog.PackageHealthObserver;
 import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
 
@@ -106,10 +114,11 @@
     }
 
     @Override
-    public boolean execute(VersionedPackage failedPackage) {
+    public boolean execute(VersionedPackage failedPackage, @FailureReasons int rollbackReason) {
         RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
         VersionedPackage moduleMetadataPackage = getModuleMetadataPackage();
         RollbackInfo rollback = getAvailableRollback(rollbackManager, failedPackage);
+        int reasonToLog = mapFailureReasonToMetric(rollbackReason);
 
         if (rollback == null) {
             Slog.w(TAG, "Expected rollback but no valid rollback found for package: [ "
@@ -119,7 +128,8 @@
         }
 
         logEvent(moduleMetadataPackage,
-                StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE);
+                StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE,
+                reasonToLog, failedPackage.getPackageName());
         LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> {
             int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
                     RollbackManager.STATUS_FAILURE);
@@ -136,11 +146,13 @@
                             moduleMetadataPackage);
                 } else {
                     logEvent(moduleMetadataPackage,
-                            StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS);
+                            StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
+                            reasonToLog, failedPackage.getPackageName());
                 }
             } else {
                 logEvent(moduleMetadataPackage,
-                        StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE);
+                        StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
+                        reasonToLog, failedPackage.getPackageName());
             }
         });
 
@@ -219,12 +231,14 @@
         }
         if (sessionInfo.isStagedSessionApplied()) {
             logEvent(oldModuleMetadataPackage,
-                    StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS);
+                    StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
+                    WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, "");
         } else if (sessionInfo.isStagedSessionReady()) {
             // TODO: What do for staged session ready but not applied
         } else {
             logEvent(oldModuleMetadataPackage,
-                    StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE);
+                    StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
+                    WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, "");
         }
     }
 
@@ -303,12 +317,16 @@
                     saveLastStagedRollbackId(rollbackId);
                     logEvent(moduleMetadataPackage,
                             StatsLog
-                            .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED);
+                            .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED,
+                            WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN,
+                            "");
                     mContext.getSystemService(PowerManager.class).reboot("Rollback staged install");
                 } else if (sessionInfo.isStagedSessionFailed()
                         && markStagedSessionHandled(rollbackId)) {
                     logEvent(moduleMetadataPackage,
-                            StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE);
+                            StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
+                            WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN,
+                            "");
                     mContext.unregisterReceiver(listener);
                 }
             }
@@ -355,11 +373,12 @@
         return rollbackId;
     }
 
-    private static void logEvent(@Nullable VersionedPackage moduleMetadataPackage, int type) {
+    private static void logEvent(@Nullable VersionedPackage moduleMetadataPackage, int type,
+            int rollbackReason, @NonNull String failingPackageName) {
         Slog.i(TAG, "Watchdog event occurred of type: " + type);
         if (moduleMetadataPackage != null) {
             StatsLog.logWatchdogRollbackOccurred(type, moduleMetadataPackage.getPackageName(),
-                    moduleMetadataPackage.getVersionCode());
+                    moduleMetadataPackage.getVersionCode(), rollbackReason, failingPackageName);
         }
     }
 
@@ -371,7 +390,7 @@
         mNumberOfNativeCrashPollsRemaining--;
         // Check if native watchdog reported a crash
         if ("1".equals(SystemProperties.get("sys.init.updatable_crashing"))) {
-            execute(getModuleMetadataPackage());
+            execute(getModuleMetadataPackage(), PackageWatchdog.FAILURE_REASON_NATIVE_CRASH);
             // we stop polling after an attempt to execute rollback, regardless of whether the
             // attempt succeeds or not
         } else {
@@ -392,4 +411,20 @@
                 + "and mitigate native crashes");
         mHandler.post(()->checkAndMitigateNativeCrashes());
     }
+
+    private int mapFailureReasonToMetric(@FailureReasons int failureReason) {
+        switch (failureReason) {
+            case PackageWatchdog.FAILURE_REASON_NATIVE_CRASH:
+                return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH;
+            case PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK:
+                return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_EXPLICIT_HEALTH_CHECK;
+            case PackageWatchdog.FAILURE_REASON_APP_CRASH:
+                return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_CRASH;
+            case PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING:
+                return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_NOT_RESPONDING;
+            default:
+                return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN;
+        }
+    }
+
 }
diff --git a/services/core/java/com/android/server/testharness/TestHarnessModeService.java b/services/core/java/com/android/server/testharness/TestHarnessModeService.java
index fcf87ee..7786833 100644
--- a/services/core/java/com/android/server/testharness/TestHarnessModeService.java
+++ b/services/core/java/com/android/server/testharness/TestHarnessModeService.java
@@ -165,7 +165,7 @@
         Settings.Global.putLong(cr, Settings.Global.ADB_ALLOWED_CONNECTION_TIME, 0);
         Settings.Global.putInt(cr, Settings.Global.ADB_ENABLED, 1);
         Settings.Global.putInt(cr, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
-        Settings.Global.putInt(cr, Settings.Global.PACKAGE_VERIFIER_ENABLE, 0);
+        Settings.Global.putInt(cr, Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, 0);
         Settings.Global.putInt(
                 cr,
                 Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
diff --git a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
index 9dbbf16..4e8ba07 100644
--- a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
@@ -16,35 +16,59 @@
 
 package com.android.server.timedetector;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AlarmManager;
+import android.app.timedetector.ManualTimeSuggestion;
 import android.app.timedetector.PhoneTimeSuggestion;
 import android.content.Intent;
+import android.util.LocalLog;
 import android.util.Slog;
 import android.util.TimestampedValue;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 /**
  * An implementation of TimeDetectorStrategy that passes only NITZ suggestions to
- * {@link AlarmManager}. The TimeDetectorService handles thread safety: all calls to
- * this class can be assumed to be single threaded (though the thread used may vary).
+ * {@link AlarmManager}.
+ *
+ * <p>Most public methods are marked synchronized to ensure thread safety around internal state.
  */
-// @NotThreadSafe
 public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
 
-    private final static String TAG = "timedetector.SimpleTimeDetectorStrategy";
+    private static final boolean DBG = false;
+    private static final String LOG_TAG = "SimpleTimeDetectorStrategy";
+
+    @IntDef({ ORIGIN_PHONE, ORIGIN_MANUAL })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Origin {}
+
+    /** Used when a time value originated from a telephony signal. */
+    @Origin
+    private static final int ORIGIN_PHONE = 1;
+
+    /** Used when a time value originated from a user / manual settings. */
+    @Origin
+    private static final int ORIGIN_MANUAL = 2;
 
     /**
      * CLOCK_PARANOIA: The maximum difference allowed between the expected system clock time and the
      * actual system clock time before a warning is logged. Used to help identify situations where
-     * there is something other than this class setting the system clock.
+     * there is something other than this class setting the system clock automatically.
      */
     private static final long SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS = 2 * 1000;
 
+    // A log for changes made to the system clock and why.
+    @NonNull
+    private final LocalLog mTimeChangesLog = new LocalLog(30, false /* useLocalTimestamps */);
+
     // @NonNull after initialize()
     private Callback mCallback;
 
@@ -52,11 +76,11 @@
     @Nullable private PhoneTimeSuggestion mLastPhoneSuggestion;
 
     // Information about the last time signal received: Used when toggling auto-time.
-    @Nullable private TimestampedValue<Long> mLastSystemClockTime;
-    private boolean mLastSystemClockTimeSendNetworkBroadcast;
+    @Nullable private TimestampedValue<Long> mLastAutoSystemClockTime;
+    private boolean mLastAutoSystemClockTimeSendNetworkBroadcast;
 
     // System clock state.
-    @Nullable private TimestampedValue<Long> mLastSystemClockTimeSet;
+    @Nullable private TimestampedValue<Long> mLastAutoSystemClockTimeSet;
 
     @Override
     public void initialize(@NonNull Callback callback) {
@@ -64,26 +88,32 @@
     }
 
     @Override
-    public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
+    public synchronized void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
         // NITZ logic
 
+        // Empty suggestions are just ignored as we don't currently keep track of suggestion origin.
+        if (timeSuggestion.getUtcTime() == null) {
+            return;
+        }
+
         boolean timeSuggestionIsValid =
                 validateNewPhoneSuggestion(timeSuggestion, mLastPhoneSuggestion);
         if (!timeSuggestionIsValid) {
             return;
         }
         // Always store the last NITZ value received, regardless of whether we go on to use it to
-        // update the system clock. This is so that we can validate future NITZ signals.
+        // update the system clock. This is so that we can validate future phone suggestions.
         mLastPhoneSuggestion = timeSuggestion;
 
         // System clock update logic.
-
-        // Historically, Android has sent a telephony broadcast only when setting the time using
-        // NITZ.
-        final boolean sendNetworkBroadcast = true;
-
         final TimestampedValue<Long> newUtcTime = timeSuggestion.getUtcTime();
-        setSystemClockIfRequired(newUtcTime, sendNetworkBroadcast);
+        setSystemClockIfRequired(ORIGIN_PHONE, newUtcTime, timeSuggestion);
+    }
+
+    @Override
+    public synchronized void suggestManualTime(ManualTimeSuggestion timeSuggestion) {
+        final TimestampedValue<Long> newUtcTime = timeSuggestion.getUtcTime();
+        setSystemClockIfRequired(ORIGIN_MANUAL, newUtcTime, timeSuggestion);
     }
 
     private static boolean validateNewPhoneSuggestion(@NonNull PhoneTimeSuggestion newSuggestion,
@@ -94,7 +124,7 @@
                     newSuggestion.getUtcTime(), lastSuggestion.getUtcTime());
             if (referenceTimeDifference < 0 || referenceTimeDifference > Integer.MAX_VALUE) {
                 // Out of order or bogus.
-                Slog.w(TAG, "validateNewNitzTime: Bad NITZ signal received."
+                Slog.w(LOG_TAG, "Bad NITZ signal received."
                         + " referenceTimeDifference=" + referenceTimeDifference
                         + " lastSuggestion=" + lastSuggestion
                         + " newSuggestion=" + newSuggestion);
@@ -104,17 +134,39 @@
         return true;
     }
 
+    @GuardedBy("this")
     private void setSystemClockIfRequired(
-            TimestampedValue<Long> time, boolean sendNetworkBroadcast) {
+            @Origin int origin, TimestampedValue<Long> time, Object cause) {
+        // Historically, Android has sent a TelephonyIntents.ACTION_NETWORK_SET_TIME broadcast only
+        // when setting the time using NITZ.
+        boolean sendNetworkBroadcast = origin == ORIGIN_PHONE;
 
-        // Store the last candidate we've seen in all cases so we can set the system clock
-        // when/if time detection is enabled.
-        mLastSystemClockTime = time;
-        mLastSystemClockTimeSendNetworkBroadcast = sendNetworkBroadcast;
+        boolean isOriginAutomatic = isOriginAutomatic(origin);
+        if (isOriginAutomatic) {
+            // Store the last auto time candidate we've seen in all cases so we can set the system
+            // clock when/if time detection is off but later enabled.
+            mLastAutoSystemClockTime = time;
+            mLastAutoSystemClockTimeSendNetworkBroadcast = sendNetworkBroadcast;
 
-        if (!mCallback.isTimeDetectionEnabled()) {
-            Slog.d(TAG, "setSystemClockIfRequired: Time detection is not enabled. time=" + time);
-            return;
+            if (!mCallback.isAutoTimeDetectionEnabled()) {
+                if (DBG) {
+                    Slog.d(LOG_TAG, "Auto time detection is not enabled."
+                            + " origin=" + origin
+                            + ", time=" + time
+                            + ", cause=" + cause);
+                }
+                return;
+            }
+        } else {
+            if (mCallback.isAutoTimeDetectionEnabled()) {
+                if (DBG) {
+                    Slog.d(LOG_TAG, "Auto time detection is enabled."
+                            + " origin=" + origin
+                            + ", time=" + time
+                            + ", cause=" + cause);
+                }
+                return;
+            }
         }
 
         mCallback.acquireWakeLock();
@@ -122,37 +174,45 @@
             long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis();
             long actualTimeMillis = mCallback.systemClockMillis();
 
-            // CLOCK_PARANOIA : Check to see if this class owns the clock or if something else
-            // may be setting the clock.
-            if (mLastSystemClockTimeSet != null) {
-                long expectedTimeMillis = TimeDetectorStrategy.getTimeAt(
-                        mLastSystemClockTimeSet, elapsedRealtimeMillis);
-                long absSystemClockDifference = Math.abs(expectedTimeMillis - actualTimeMillis);
-                if (absSystemClockDifference > SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS) {
-                    Slog.w(TAG, "System clock has not tracked elapsed real time clock. A clock may"
-                            + " be inaccurate or something unexpectedly set the system clock."
-                            + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
-                            + " expectedTimeMillis=" + expectedTimeMillis
-                            + " actualTimeMillis=" + actualTimeMillis);
+            if (isOriginAutomatic) {
+                // CLOCK_PARANOIA : Check to see if this class owns the clock or if something else
+                // may be setting the clock.
+                if (mLastAutoSystemClockTimeSet != null) {
+                    long expectedTimeMillis = TimeDetectorStrategy.getTimeAt(
+                            mLastAutoSystemClockTimeSet, elapsedRealtimeMillis);
+                    long absSystemClockDifference = Math.abs(expectedTimeMillis - actualTimeMillis);
+                    if (absSystemClockDifference > SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS) {
+                        Slog.w(LOG_TAG,
+                                "System clock has not tracked elapsed real time clock. A clock may"
+                                        + " be inaccurate or something unexpectedly set the system"
+                                        + " clock."
+                                        + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+                                        + " expectedTimeMillis=" + expectedTimeMillis
+                                        + " actualTimeMillis=" + actualTimeMillis);
+                    }
                 }
             }
 
-            final String reason = "New time signal";
             adjustAndSetDeviceSystemClock(
-                    time, sendNetworkBroadcast, elapsedRealtimeMillis, actualTimeMillis, reason);
+                    time, sendNetworkBroadcast, elapsedRealtimeMillis, actualTimeMillis, cause);
         } finally {
             mCallback.releaseWakeLock();
         }
     }
 
+    private static boolean isOriginAutomatic(@Origin int origin) {
+        return origin == ORIGIN_PHONE;
+    }
+
     @Override
-    public void handleAutoTimeDetectionToggle(boolean enabled) {
+    public synchronized void handleAutoTimeDetectionChanged() {
         // If automatic time detection is enabled we update the system clock instantly if we can.
         // Conversely, if automatic time detection is disabled we leave the clock as it is.
+        boolean enabled = mCallback.isAutoTimeDetectionEnabled();
         if (enabled) {
-            if (mLastSystemClockTime != null) {
+            if (mLastAutoSystemClockTime != null) {
                 // Only send the network broadcast if the last candidate would have caused one.
-                final boolean sendNetworkBroadcast = mLastSystemClockTimeSendNetworkBroadcast;
+                final boolean sendNetworkBroadcast = mLastAutoSystemClockTimeSendNetworkBroadcast;
 
                 mCallback.acquireWakeLock();
                 try {
@@ -160,7 +220,7 @@
                     long actualTimeMillis = mCallback.systemClockMillis();
 
                     final String reason = "Automatic time detection enabled.";
-                    adjustAndSetDeviceSystemClock(mLastSystemClockTime, sendNetworkBroadcast,
+                    adjustAndSetDeviceSystemClock(mLastAutoSystemClockTime, sendNetworkBroadcast,
                             elapsedRealtimeMillis, actualTimeMillis, reason);
                 } finally {
                     mCallback.releaseWakeLock();
@@ -169,22 +229,36 @@
         } else {
             // CLOCK_PARANOIA: We are losing "control" of the system clock so we cannot predict what
             // it should be in future.
-            mLastSystemClockTimeSet = null;
+            mLastAutoSystemClockTimeSet = null;
         }
     }
 
     @Override
-    public void dump(@NonNull PrintWriter pw, @Nullable String[] args) {
-        pw.println("mLastPhoneSuggestion=" + mLastPhoneSuggestion);
-        pw.println("mLastSystemClockTimeSet=" + mLastSystemClockTimeSet);
-        pw.println("mLastSystemClockTime=" + mLastSystemClockTime);
-        pw.println("mLastSystemClockTimeSendNetworkBroadcast="
-                + mLastSystemClockTimeSendNetworkBroadcast);
+    public synchronized void dump(@NonNull PrintWriter pw, @Nullable String[] args) {
+        IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+        ipw.println("TimeDetectorStrategy:");
+        ipw.increaseIndent(); // level 1
+
+        ipw.println("mLastPhoneSuggestion=" + mLastPhoneSuggestion);
+        ipw.println("mLastAutoSystemClockTimeSet=" + mLastAutoSystemClockTimeSet);
+        ipw.println("mLastAutoSystemClockTime=" + mLastAutoSystemClockTime);
+        ipw.println("mLastAutoSystemClockTimeSendNetworkBroadcast="
+                + mLastAutoSystemClockTimeSendNetworkBroadcast);
+
+
+        ipw.println("Time change log:");
+        ipw.increaseIndent(); // level 2
+        mTimeChangesLog.dump(ipw);
+        ipw.decreaseIndent(); // level 2
+
+        ipw.decreaseIndent(); // level 1
+        ipw.flush();
     }
 
+    @GuardedBy("this")
     private void adjustAndSetDeviceSystemClock(
             TimestampedValue<Long> newTime, boolean sendNetworkBroadcast,
-            long elapsedRealtimeMillis, long actualSystemClockMillis, String reason) {
+            long elapsedRealtimeMillis, long actualSystemClockMillis, Object cause) {
 
         // Adjust for the time that has elapsed since the signal was received.
         long newSystemClockMillis = TimeDetectorStrategy.getTimeAt(newTime, elapsedRealtimeMillis);
@@ -194,24 +268,30 @@
         long absTimeDifference = Math.abs(newSystemClockMillis - actualSystemClockMillis);
         long systemClockUpdateThreshold = mCallback.systemClockUpdateThresholdMillis();
         if (absTimeDifference < systemClockUpdateThreshold) {
-            Slog.d(TAG, "adjustAndSetDeviceSystemClock: Not setting system clock. New time and"
-                    + " system clock are close enough."
-                    + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
-                    + " newTime=" + newTime
-                    + " reason=" + reason
-                    + " systemClockUpdateThreshold=" + systemClockUpdateThreshold
-                    + " absTimeDifference=" + absTimeDifference);
+            if (DBG) {
+                Slog.d(LOG_TAG, "Not setting system clock. New time and"
+                        + " system clock are close enough."
+                        + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+                        + " newTime=" + newTime
+                        + " cause=" + cause
+                        + " systemClockUpdateThreshold=" + systemClockUpdateThreshold
+                        + " absTimeDifference=" + absTimeDifference);
+            }
             return;
         }
 
-        Slog.d(TAG, "Setting system clock using time=" + newTime
-                + " reason=" + reason
-                + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
-                + " newTimeMillis=" + newSystemClockMillis);
         mCallback.setSystemClock(newSystemClockMillis);
+        String logMsg = "Set system clock using time=" + newTime
+                + " cause=" + cause
+                + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+                + " newSystemClockMillis=" + newSystemClockMillis;
+        if (DBG) {
+            Slog.d(LOG_TAG, logMsg);
+        }
+        mTimeChangesLog.log(logMsg);
 
         // CLOCK_PARANOIA : Record the last time this class set the system clock.
-        mLastSystemClockTimeSet = newTime;
+        mLastAutoSystemClockTimeSet = newTime;
 
         if (sendNetworkBroadcast) {
             // Send a broadcast that telephony code used to send after setting the clock.
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index ee42279..34400ff 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -19,14 +19,14 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.timedetector.ITimeDetectorService;
+import android.app.timedetector.ManualTimeSuggestion;
 import android.app.timedetector.PhoneTimeSuggestion;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.database.ContentObserver;
-import android.os.Binder;
+import android.os.Handler;
 import android.provider.Settings;
 
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.DumpUtils;
 import com.android.server.FgThread;
@@ -38,7 +38,7 @@
 import java.util.Objects;
 
 public final class TimeDetectorService extends ITimeDetectorService.Stub {
-    private static final String TAG = "timedetector.TimeDetectorService";
+    private static final String TAG = "TimeDetectorService";
 
     public static class Lifecycle extends SystemService {
 
@@ -56,29 +56,25 @@
         }
     }
 
+    @NonNull private final Handler mHandler;
     @NonNull private final Context mContext;
     @NonNull private final Callback mCallback;
-
-    // The lock used when call the strategy to ensure thread safety.
-    @NonNull private final Object mStrategyLock = new Object();
-
-    @GuardedBy("mStrategyLock")
     @NonNull private final TimeDetectorStrategy mTimeDetectorStrategy;
 
     private static TimeDetectorService create(@NonNull Context context) {
-        final TimeDetectorStrategy timeDetector = new SimpleTimeDetectorStrategy();
-        final TimeDetectorStrategyCallbackImpl callback =
-                new TimeDetectorStrategyCallbackImpl(context);
+        TimeDetectorStrategy timeDetector = new SimpleTimeDetectorStrategy();
+        TimeDetectorStrategyCallbackImpl callback = new TimeDetectorStrategyCallbackImpl(context);
         timeDetector.initialize(callback);
 
+        Handler handler = FgThread.getHandler();
         TimeDetectorService timeDetectorService =
-                new TimeDetectorService(context, callback, timeDetector);
+                new TimeDetectorService(context, handler, callback, timeDetector);
 
         // Wire up event listening.
         ContentResolver contentResolver = context.getContentResolver();
         contentResolver.registerContentObserver(
                 Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true,
-                new ContentObserver(FgThread.getHandler()) {
+                new ContentObserver(handler) {
                     public void onChange(boolean selfChange) {
                         timeDetectorService.handleAutoTimeDetectionToggle();
                     }
@@ -88,34 +84,33 @@
     }
 
     @VisibleForTesting
-    public TimeDetectorService(@NonNull Context context, @NonNull Callback callback,
-            @NonNull TimeDetectorStrategy timeDetectorStrategy) {
+    public TimeDetectorService(@NonNull Context context, @NonNull Handler handler,
+            @NonNull Callback callback, @NonNull TimeDetectorStrategy timeDetectorStrategy) {
         mContext = Objects.requireNonNull(context);
+        mHandler = Objects.requireNonNull(handler);
         mCallback = Objects.requireNonNull(callback);
         mTimeDetectorStrategy = Objects.requireNonNull(timeDetectorStrategy);
     }
 
     @Override
     public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSignal) {
-        enforceSetTimePermission();
+        enforceSuggestPhoneTimePermission();
         Objects.requireNonNull(timeSignal);
 
-        long idToken = Binder.clearCallingIdentity();
-        try {
-            synchronized (mStrategyLock) {
-                mTimeDetectorStrategy.suggestPhoneTime(timeSignal);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(idToken);
-        }
+        mHandler.post(() -> mTimeDetectorStrategy.suggestPhoneTime(timeSignal));
+    }
+
+    @Override
+    public void suggestManualTime(@NonNull ManualTimeSuggestion timeSignal) {
+        enforceSuggestManualTimePermission();
+        Objects.requireNonNull(timeSignal);
+
+        mHandler.post(() -> mTimeDetectorStrategy.suggestManualTime(timeSignal));
     }
 
     @VisibleForTesting
     public void handleAutoTimeDetectionToggle() {
-        synchronized (mStrategyLock) {
-            final boolean timeDetectionEnabled = mCallback.isTimeDetectionEnabled();
-            mTimeDetectorStrategy.handleAutoTimeDetectionToggle(timeDetectionEnabled);
-        }
+        mHandler.post(mTimeDetectorStrategy::handleAutoTimeDetectionChanged);
     }
 
     @Override
@@ -123,12 +118,14 @@
             @Nullable String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
 
-        synchronized (mStrategyLock) {
-            mTimeDetectorStrategy.dump(pw, args);
-        }
+        mTimeDetectorStrategy.dump(pw, args);
     }
 
-    private void enforceSetTimePermission() {
+    private void enforceSuggestPhoneTimePermission() {
         mContext.enforceCallingPermission(android.Manifest.permission.SET_TIME, "set time");
     }
-}
\ No newline at end of file
+
+    private void enforceSuggestManualTimePermission() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SET_TIME, "set time");
+    }
+}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index 7c2a945..0a6c2e7 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.timedetector.ManualTimeSuggestion;
 import android.app.timedetector.PhoneTimeSuggestion;
 import android.content.Intent;
 import android.util.TimestampedValue;
@@ -26,16 +27,24 @@
 
 /**
  * The interface for classes that implement the time detection algorithm used by the
- * TimeDetectorService. The TimeDetectorService handles thread safety: all calls to implementations
- * of this interface can be assumed to be single threaded (though the thread used may vary).
+ * TimeDetectorService.
+ *
+ * <p>Most calls will be handled by a single thread but that is not true for all calls. For example
+ * {@link #dump(PrintWriter, String[])}) may be called on a different thread so implementations must
+ * handle thread safety.
  *
  * @hide
  */
-// @NotThreadSafe
 public interface TimeDetectorStrategy {
 
     /**
      * The interface used by the strategy to interact with the surrounding service.
+     *
+     * <p>Note: Because the system properties-derived value {@link #isAutoTimeDetectionEnabled()}
+     * can be modified independently and from different threads (and processes!). its use is prone
+     * to race conditions. That will be true until the responsibility for setting their values is
+     * moved to {@link TimeDetectorStrategy}. There are similar issues with
+     * {@link #systemClockMillis()} while any process can modify the system clock.
      */
     interface Callback {
 
@@ -47,7 +56,7 @@
         int systemClockUpdateThresholdMillis();
 
         /** Returns true if automatic time detection is enabled. */
-        boolean isTimeDetectionEnabled();
+        boolean isAutoTimeDetectionEnabled();
 
         /** Acquire a suitable wake lock. Must be followed by {@link #releaseWakeLock()} */
         void acquireWakeLock();
@@ -71,11 +80,14 @@
     /** Initialize the strategy. */
     void initialize(@NonNull Callback callback);
 
-    /** Process the suggested time. */
+    /** Process the suggested time from telephony sources. */
     void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion);
 
+    /** Process the suggested manually entered time. */
+    void suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion);
+
     /** Handle the auto-time setting being toggled on or off. */
-    void handleAutoTimeDetectionToggle(boolean enabled);
+    void handleAutoTimeDetectionChanged();
 
     /** Dump debug information. */
     void dump(@NonNull PrintWriter pw, @Nullable String[] args);
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
index 77b9e62..42d59d5 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
@@ -72,7 +72,7 @@
     }
 
     @Override
-    public boolean isTimeDetectionEnabled() {
+    public boolean isAutoTimeDetectionEnabled() {
         try {
             return Settings.Global.getInt(mContentResolver, Settings.Global.AUTO_TIME) != 0;
         } catch (Settings.SettingNotFoundException snfe) {
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
new file mode 100644
index 0000000..adf6d7e
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector;
+
+import android.annotation.Nullable;
+import android.app.AlarmManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.SystemProperties;
+import android.provider.Settings;
+
+/**
+ * The real implementation of {@link TimeZoneDetectorStrategy.Callback}.
+ */
+public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrategy.Callback {
+
+    private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
+
+    private final Context mContext;
+    private final ContentResolver mCr;
+
+    TimeZoneDetectorCallbackImpl(Context context) {
+        mContext = context;
+        mCr = context.getContentResolver();
+    }
+
+    @Override
+    public boolean isAutoTimeZoneDetectionEnabled() {
+        return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0;
+    }
+
+    @Override
+    public boolean isDeviceTimeZoneInitialized() {
+        // timezone.equals("GMT") will be true and only true if the time zone was
+        // set to a default value by the system server (when starting, system server
+        // sets the persist.sys.timezone to "GMT" if it's not set). "GMT" is not used by
+        // any code that sets it explicitly (in case where something sets GMT explicitly,
+        // "Etc/GMT" Olson ID would be used).
+
+        String timeZoneId = getDeviceTimeZone();
+        return timeZoneId != null && timeZoneId.length() > 0 && !timeZoneId.equals("GMT");
+    }
+
+    @Override
+    @Nullable
+    public String getDeviceTimeZone() {
+        return SystemProperties.get(TIMEZONE_PROPERTY);
+    }
+
+    @Override
+    public void setDeviceTimeZone(String zoneId) {
+        AlarmManager alarmManager = mContext.getSystemService(AlarmManager.class);
+        alarmManager.setTimeZone(zoneId);
+    }
+}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
new file mode 100644
index 0000000..9a1fe65
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -0,0 +1,127 @@
+/*
+ * 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.timezonedetector;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.timezonedetector.ITimeZoneDetectorService;
+import android.app.timezonedetector.ManualTimeZoneSuggestion;
+import android.app.timezonedetector.PhoneTimeZoneSuggestion;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.provider.Settings;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.DumpUtils;
+import com.android.server.FgThread;
+import com.android.server.SystemService;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Objects;
+
+/**
+ * The implementation of ITimeZoneDetectorService.aidl.
+ */
+public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub {
+    private static final String TAG = "TimeZoneDetectorService";
+
+    /**
+     * Handles the lifecycle for {@link TimeZoneDetectorService}.
+     */
+    public static class Lifecycle extends SystemService {
+
+        public Lifecycle(@NonNull Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onStart() {
+            TimeZoneDetectorService service = TimeZoneDetectorService.create(getContext());
+
+            // Publish the binder service so it can be accessed from other (appropriately
+            // permissioned) processes.
+            publishBinderService(Context.TIME_ZONE_DETECTOR_SERVICE, service);
+        }
+    }
+
+    @NonNull private final Context mContext;
+    @NonNull private final Handler mHandler;
+    @NonNull private final TimeZoneDetectorStrategy mTimeZoneDetectorStrategy;
+
+    private static TimeZoneDetectorService create(@NonNull Context context) {
+        final TimeZoneDetectorStrategy timeZoneDetectorStrategy =
+                TimeZoneDetectorStrategy.create(context);
+
+        Handler handler = FgThread.getHandler();
+        ContentResolver contentResolver = context.getContentResolver();
+        contentResolver.registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true,
+                new ContentObserver(handler) {
+                    public void onChange(boolean selfChange) {
+                        timeZoneDetectorStrategy.handleAutoTimeZoneDetectionChange();
+                    }
+                });
+
+        return new TimeZoneDetectorService(context, handler, timeZoneDetectorStrategy);
+    }
+
+    @VisibleForTesting
+    public TimeZoneDetectorService(@NonNull Context context, @NonNull Handler handler,
+            @NonNull TimeZoneDetectorStrategy timeZoneDetectorStrategy) {
+        mContext = Objects.requireNonNull(context);
+        mHandler = Objects.requireNonNull(handler);
+        mTimeZoneDetectorStrategy = Objects.requireNonNull(timeZoneDetectorStrategy);
+    }
+
+    @Override
+    public void suggestManualTimeZone(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion) {
+        enforceSuggestManualTimeZonePermission();
+        Objects.requireNonNull(timeZoneSuggestion);
+
+        mHandler.post(() -> mTimeZoneDetectorStrategy.suggestManualTimeZone(timeZoneSuggestion));
+    }
+
+    @Override
+    public void suggestPhoneTimeZone(@NonNull PhoneTimeZoneSuggestion timeZoneSuggestion) {
+        enforceSuggestPhoneTimeZonePermission();
+        Objects.requireNonNull(timeZoneSuggestion);
+
+        mHandler.post(() -> mTimeZoneDetectorStrategy.suggestPhoneTimeZone(timeZoneSuggestion));
+    }
+
+    @Override
+    protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw,
+            @Nullable String[] args) {
+        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+
+        mTimeZoneDetectorStrategy.dumpState(pw, args);
+    }
+
+    private void enforceSuggestPhoneTimeZonePermission() {
+        mContext.enforceCallingPermission(
+                android.Manifest.permission.SET_TIME_ZONE, "set time zone");
+    }
+
+    private void enforceSuggestManualTimeZonePermission() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.SET_TIME_ZONE, "set time zone");
+    }
+}
+
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
new file mode 100644
index 0000000..b4d8053
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
@@ -0,0 +1,553 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.timezonedetector;
+
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.timezonedetector.ManualTimeZoneSuggestion;
+import android.app.timezonedetector.PhoneTimeZoneSuggestion;
+import android.content.Context;
+import android.util.ArrayMap;
+import android.util.LocalLog;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * A singleton, stateful time zone detection strategy that is aware of user (manual) suggestions and
+ * suggestions from multiple phone devices. Suggestions are acted on or ignored as needed, dependent
+ * on the current "auto time zone detection" setting.
+ *
+ * <p>For automatic detection it keeps track of the most recent suggestion from each phone it uses
+ * the best suggestion based on a scoring algorithm. If several phones provide the same score then
+ * the phone with the lowest numeric ID "wins". If the situation changes and it is no longer
+ * possible to be confident about the time zone, phones must submit an empty suggestion in order to
+ * "withdraw" their previous suggestion.
+ */
+public class TimeZoneDetectorStrategy {
+
+    /**
+     * Used by {@link TimeZoneDetectorStrategy} to interact with the surrounding service. It can be
+     * faked for tests.
+     *
+     * <p>Note: Because the system properties-derived values like
+     * {@link #isAutoTimeZoneDetectionEnabled()}, {@link #isAutoTimeZoneDetectionEnabled()},
+     * {@link #getDeviceTimeZone()} can be modified independently and from different threads (and
+     * processes!), their use are prone to race conditions. That will be true until the
+     * responsibility for setting their values is moved to {@link TimeZoneDetectorStrategy}.
+     */
+    @VisibleForTesting
+    public interface Callback {
+
+        /**
+         * Returns true if automatic time zone detection is enabled in settings.
+         */
+        boolean isAutoTimeZoneDetectionEnabled();
+
+        /**
+         * Returns true if the device has had an explicit time zone set.
+         */
+        boolean isDeviceTimeZoneInitialized();
+
+        /**
+         * Returns the device's currently configured time zone.
+         */
+        String getDeviceTimeZone();
+
+        /**
+         * Sets the device's time zone.
+         */
+        void setDeviceTimeZone(@NonNull String zoneId);
+    }
+
+    private static final String LOG_TAG = "TimeZoneDetectorStrategy";
+    private static final boolean DBG = false;
+
+    @IntDef({ ORIGIN_PHONE, ORIGIN_MANUAL })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Origin {}
+
+    /** Used when a time value originated from a telephony signal. */
+    @Origin
+    private static final int ORIGIN_PHONE = 1;
+
+    /** Used when a time value originated from a user / manual settings. */
+    @Origin
+    private static final int ORIGIN_MANUAL = 2;
+
+    /**
+     * The abstract score for an empty or invalid phone suggestion.
+     *
+     * Used to score phone suggestions where there is no zone.
+     */
+    @VisibleForTesting
+    public static final int PHONE_SCORE_NONE = 0;
+
+    /**
+     * The abstract score for a low quality phone suggestion.
+     *
+     * Used to score suggestions where:
+     * The suggested zone ID is one of several possibilities, and the possibilities have different
+     * offsets.
+     *
+     * You would have to be quite desperate to want to use this choice.
+     */
+    @VisibleForTesting
+    public static final int PHONE_SCORE_LOW = 1;
+
+    /**
+     * The abstract score for a medium quality phone suggestion.
+     *
+     * Used for:
+     * The suggested zone ID is one of several possibilities but at least the possibilities have the
+     * same offset. Users would get the correct time but for the wrong reason. i.e. their device may
+     * switch to DST at the wrong time and (for example) their calendar events.
+     */
+    @VisibleForTesting
+    public static final int PHONE_SCORE_MEDIUM = 2;
+
+    /**
+     * The abstract score for a high quality phone suggestion.
+     *
+     * Used for:
+     * The suggestion was for one zone ID and the answer was unambiguous and likely correct given
+     * the info available.
+     */
+    @VisibleForTesting
+    public static final int PHONE_SCORE_HIGH = 3;
+
+    /**
+     * The abstract score for a highest quality phone suggestion.
+     *
+     * Used for:
+     * Suggestions that must "win" because they constitute test or emulator zone ID.
+     */
+    @VisibleForTesting
+    public static final int PHONE_SCORE_HIGHEST = 4;
+
+    /**
+     * The threshold at which phone suggestions are good enough to use to set the device's time
+     * zone.
+     */
+    @VisibleForTesting
+    public static final int PHONE_SCORE_USAGE_THRESHOLD = PHONE_SCORE_MEDIUM;
+
+    /** The number of previous phone suggestions to keep for each ID (for use during debugging). */
+    private static final int KEEP_PHONE_SUGGESTION_HISTORY_SIZE = 30;
+
+    @NonNull
+    private final Callback mCallback;
+
+    /**
+     * A log that records the decisions / decision metadata that affected the device's time zone
+     * (for use during debugging).
+     */
+    @NonNull
+    private final LocalLog mTimeZoneChangesLog = new LocalLog(30, false /* useLocalTimestamps */);
+
+    /**
+     * A mapping from phoneId to a linked list of phone time zone suggestions (the head being the
+     * latest). We typically expect one or two entries in this Map: devices will have a small number
+     * of telephony devices and phoneIds are assumed to be stable. The LinkedList associated with
+     * the ID will not exceed {@link #KEEP_PHONE_SUGGESTION_HISTORY_SIZE} in size.
+     */
+    @GuardedBy("this")
+    private ArrayMap<Integer, LinkedList<QualifiedPhoneTimeZoneSuggestion>> mSuggestionByPhoneId =
+            new ArrayMap<>();
+
+    /**
+     * Creates a new instance of {@link TimeZoneDetectorStrategy}.
+     */
+    public static TimeZoneDetectorStrategy create(Context context) {
+        Callback timeZoneDetectionServiceHelper = new TimeZoneDetectorCallbackImpl(context);
+        return new TimeZoneDetectorStrategy(timeZoneDetectionServiceHelper);
+    }
+
+    @VisibleForTesting
+    public TimeZoneDetectorStrategy(Callback callback) {
+        mCallback = Objects.requireNonNull(callback);
+    }
+
+    /** Process the suggested manually- / user-entered time zone. */
+    public synchronized void suggestManualTimeZone(@NonNull ManualTimeZoneSuggestion suggestion) {
+        Objects.requireNonNull(suggestion);
+
+        String timeZoneId = suggestion.getZoneId();
+        String cause = "Manual time suggestion received: suggestion=" + suggestion;
+        setDeviceTimeZoneIfRequired(ORIGIN_MANUAL, timeZoneId, cause);
+    }
+
+    /**
+     * Suggests a time zone for the device, or withdraws a previous suggestion if
+     * {@link PhoneTimeZoneSuggestion#getZoneId()} is {@code null}. The suggestion is scoped to a
+     * specific {@link PhoneTimeZoneSuggestion#getPhoneId() phone}.
+     * See {@link PhoneTimeZoneSuggestion} for an explanation of the metadata associated with a
+     * suggestion. The strategy uses suggestions to decide whether to modify the device's time zone
+     * setting and what to set it to.
+     */
+    public synchronized void suggestPhoneTimeZone(@NonNull PhoneTimeZoneSuggestion suggestion) {
+        if (DBG) {
+            Slog.d(LOG_TAG, "Phone suggestion received. newSuggestion=" + suggestion);
+        }
+        Objects.requireNonNull(suggestion);
+
+        // Score the suggestion.
+        int score = scorePhoneSuggestion(suggestion);
+        QualifiedPhoneTimeZoneSuggestion scoredSuggestion =
+                new QualifiedPhoneTimeZoneSuggestion(suggestion, score);
+
+        // Store the suggestion against the correct phoneId.
+        LinkedList<QualifiedPhoneTimeZoneSuggestion> suggestions =
+                mSuggestionByPhoneId.get(suggestion.getPhoneId());
+        if (suggestions == null) {
+            suggestions = new LinkedList<>();
+            mSuggestionByPhoneId.put(suggestion.getPhoneId(), suggestions);
+        }
+        suggestions.addFirst(scoredSuggestion);
+        if (suggestions.size() > KEEP_PHONE_SUGGESTION_HISTORY_SIZE) {
+            suggestions.removeLast();
+        }
+
+        // Now perform auto time zone detection. The new suggestion may be used to modify the time
+        // zone setting.
+        String reason = "New phone time suggested. suggestion=" + suggestion;
+        doAutoTimeZoneDetection(reason);
+    }
+
+    private static int scorePhoneSuggestion(@NonNull PhoneTimeZoneSuggestion suggestion) {
+        int score;
+        if (suggestion.getZoneId() == null) {
+            score = PHONE_SCORE_NONE;
+        } else if (suggestion.getMatchType() == MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY
+                || suggestion.getMatchType() == MATCH_TYPE_EMULATOR_ZONE_ID) {
+            // Handle emulator / test cases : These suggestions should always just be used.
+            score = PHONE_SCORE_HIGHEST;
+        } else if (suggestion.getQuality() == QUALITY_SINGLE_ZONE) {
+            score = PHONE_SCORE_HIGH;
+        } else if (suggestion.getQuality() == QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET) {
+            // The suggestion may be wrong, but at least the offset should be correct.
+            score = PHONE_SCORE_MEDIUM;
+        } else if (suggestion.getQuality() == QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS) {
+            // The suggestion has a good chance of being wrong.
+            score = PHONE_SCORE_LOW;
+        } else {
+            throw new AssertionError();
+        }
+        return score;
+    }
+
+    /**
+     * Finds the best available time zone suggestion from all phones. If it is high-enough quality
+     * and automatic time zone detection is enabled then it will be set on the device. The outcome
+     * can be that this strategy becomes / remains un-opinionated and nothing is set.
+     */
+    @GuardedBy("this")
+    private void doAutoTimeZoneDetection(@NonNull String detectionReason) {
+        if (!mCallback.isAutoTimeZoneDetectionEnabled()) {
+            // Avoid doing unnecessary work with this (race-prone) check.
+            return;
+        }
+
+        QualifiedPhoneTimeZoneSuggestion bestPhoneSuggestion = findBestPhoneSuggestion();
+
+        // Work out what to do with the best suggestion.
+        if (bestPhoneSuggestion == null) {
+            // There is no phone suggestion available at all. Become un-opinionated.
+            if (DBG) {
+                Slog.d(LOG_TAG, "Could not determine time zone: No best phone suggestion."
+                        + " detectionReason=" + detectionReason);
+            }
+            return;
+        }
+
+        // Special case handling for uninitialized devices. This should only happen once.
+        String newZoneId = bestPhoneSuggestion.suggestion.getZoneId();
+        if (newZoneId != null && !mCallback.isDeviceTimeZoneInitialized()) {
+            String cause = "Device has no time zone set. Attempting to set the device to the best"
+                    + " available suggestion."
+                    + " bestPhoneSuggestion=" + bestPhoneSuggestion
+                    + ", detectionReason=" + detectionReason;
+            Slog.i(LOG_TAG, cause);
+            setDeviceTimeZoneIfRequired(ORIGIN_PHONE, newZoneId, cause);
+            return;
+        }
+
+        boolean suggestionGoodEnough = bestPhoneSuggestion.score >= PHONE_SCORE_USAGE_THRESHOLD;
+        if (!suggestionGoodEnough) {
+            if (DBG) {
+                Slog.d(LOG_TAG, "Best suggestion not good enough."
+                        + " bestPhoneSuggestion=" + bestPhoneSuggestion
+                        + ", detectionReason=" + detectionReason);
+            }
+            return;
+        }
+
+        // Paranoia: Every suggestion above the SCORE_USAGE_THRESHOLD should have a non-null time
+        // zone ID.
+        if (newZoneId == null) {
+            Slog.w(LOG_TAG, "Empty zone suggestion scored higher than expected. This is an error:"
+                    + " bestPhoneSuggestion=" + bestPhoneSuggestion
+                    + " detectionReason=" + detectionReason);
+            return;
+        }
+
+        String zoneId = bestPhoneSuggestion.suggestion.getZoneId();
+        String cause = "Found good suggestion."
+                + ", bestPhoneSuggestion=" + bestPhoneSuggestion
+                + ", detectionReason=" + detectionReason;
+        setDeviceTimeZoneIfRequired(ORIGIN_PHONE, zoneId, cause);
+    }
+
+    @GuardedBy("this")
+    private void setDeviceTimeZoneIfRequired(
+            @Origin int origin, @NonNull String newZoneId, @NonNull String cause) {
+        Objects.requireNonNull(newZoneId);
+        Objects.requireNonNull(cause);
+
+        boolean isOriginAutomatic = isOriginAutomatic(origin);
+        if (isOriginAutomatic) {
+            if (!mCallback.isAutoTimeZoneDetectionEnabled()) {
+                if (DBG) {
+                    Slog.d(LOG_TAG, "Auto time zone detection is not enabled."
+                            + " origin=" + origin
+                            + ", newZoneId=" + newZoneId
+                            + ", cause=" + cause);
+                }
+                return;
+            }
+        } else {
+            if (mCallback.isAutoTimeZoneDetectionEnabled()) {
+                if (DBG) {
+                    Slog.d(LOG_TAG, "Auto time zone detection is enabled."
+                            + " origin=" + origin
+                            + ", newZoneId=" + newZoneId
+                            + ", cause=" + cause);
+                }
+                return;
+            }
+        }
+
+        String currentZoneId = mCallback.getDeviceTimeZone();
+
+        // Avoid unnecessary changes / intents.
+        if (newZoneId.equals(currentZoneId)) {
+            // No need to set the device time zone - the setting is already what we would be
+            // suggesting.
+            if (DBG) {
+                Slog.d(LOG_TAG, "No need to change the time zone;"
+                        + " device is already set to the suggested zone."
+                        + " origin=" + origin
+                        + ", newZoneId=" + newZoneId
+                        + ", cause=" + cause);
+            }
+            return;
+        }
+
+        mCallback.setDeviceTimeZone(newZoneId);
+        String msg = "Set device time zone."
+                + " origin=" + origin
+                + ", currentZoneId=" + currentZoneId
+                + ", newZoneId=" + newZoneId
+                + ", cause=" + cause;
+        if (DBG) {
+            Slog.d(LOG_TAG, msg);
+        }
+        mTimeZoneChangesLog.log(msg);
+    }
+
+    private static boolean isOriginAutomatic(@Origin int origin) {
+        return origin == ORIGIN_PHONE;
+    }
+
+    @GuardedBy("this")
+    @Nullable
+    private QualifiedPhoneTimeZoneSuggestion findBestPhoneSuggestion() {
+        QualifiedPhoneTimeZoneSuggestion bestSuggestion = null;
+
+        // Iterate over the latest QualifiedPhoneTimeZoneSuggestion objects received for each phone
+        // and find the best. Note that we deliberately do not look at age: the caller can
+        // rate-limit so age is not a strong indicator of confidence. Instead, the callers are
+        // expected to withdraw suggestions they no longer have confidence in.
+        for (int i = 0; i < mSuggestionByPhoneId.size(); i++) {
+            LinkedList<QualifiedPhoneTimeZoneSuggestion> phoneSuggestions =
+                    mSuggestionByPhoneId.valueAt(i);
+            if (phoneSuggestions == null) {
+                // Unexpected
+                continue;
+            }
+            QualifiedPhoneTimeZoneSuggestion candidateSuggestion = phoneSuggestions.getFirst();
+            if (candidateSuggestion == null) {
+                // Unexpected
+                continue;
+            }
+
+            if (bestSuggestion == null) {
+                bestSuggestion = candidateSuggestion;
+            } else if (candidateSuggestion.score > bestSuggestion.score) {
+                bestSuggestion = candidateSuggestion;
+            } else if (candidateSuggestion.score == bestSuggestion.score) {
+                // Tie! Use the suggestion with the lowest phoneId.
+                int candidatePhoneId = candidateSuggestion.suggestion.getPhoneId();
+                int bestPhoneId = bestSuggestion.suggestion.getPhoneId();
+                if (candidatePhoneId < bestPhoneId) {
+                    bestSuggestion = candidateSuggestion;
+                }
+            }
+        }
+        return bestSuggestion;
+    }
+
+    /**
+     * Returns the current best phone suggestion. Not intended for general use: it is used during
+     * tests to check strategy behavior.
+     */
+    @VisibleForTesting
+    @Nullable
+    public synchronized QualifiedPhoneTimeZoneSuggestion findBestPhoneSuggestionForTests() {
+        return findBestPhoneSuggestion();
+    }
+
+    /**
+     * Called when there has been a change to the automatic time zone detection setting.
+     */
+    @VisibleForTesting
+    public synchronized void handleAutoTimeZoneDetectionChange() {
+        if (DBG) {
+            Slog.d(LOG_TAG, "handleTimeZoneDetectionChange() called");
+        }
+        if (mCallback.isAutoTimeZoneDetectionEnabled()) {
+            // When the user enabled time zone detection, run the time zone detection and change the
+            // device time zone if possible.
+            String reason = "Auto time zone detection setting enabled.";
+            doAutoTimeZoneDetection(reason);
+        }
+    }
+
+    /**
+     * Dumps internal state such as field values.
+     */
+    public synchronized void dumpState(PrintWriter pw, String[] args) {
+        pw.println("TimeZoneDetectorStrategy:");
+        pw.println("mCallback.isTimeZoneDetectionEnabled()="
+                + mCallback.isAutoTimeZoneDetectionEnabled());
+        pw.println("mCallback.isDeviceTimeZoneInitialized()="
+                + mCallback.isDeviceTimeZoneInitialized());
+        pw.println("mCallback.getDeviceTimeZone()="
+                + mCallback.getDeviceTimeZone());
+
+        IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+        ipw.println("Time zone change log:");
+        ipw.increaseIndent(); // level 2
+        mTimeZoneChangesLog.dump(ipw);
+        ipw.decreaseIndent(); // level 2
+
+        ipw.println("Phone suggestion history:");
+        ipw.increaseIndent(); // level 2
+        for (Map.Entry<Integer, LinkedList<QualifiedPhoneTimeZoneSuggestion>> entry
+                : mSuggestionByPhoneId.entrySet()) {
+            ipw.println("Phone " + entry.getKey());
+
+            ipw.increaseIndent(); // level 3
+            for (QualifiedPhoneTimeZoneSuggestion suggestion : entry.getValue()) {
+                ipw.println(suggestion);
+            }
+            ipw.decreaseIndent(); // level 3
+        }
+        ipw.decreaseIndent(); // level 2
+        ipw.decreaseIndent(); // level 1
+        ipw.flush();
+
+        pw.flush();
+    }
+
+    /**
+     * A method used to inspect strategy state during tests. Not intended for general use.
+     */
+    @VisibleForTesting
+    public synchronized QualifiedPhoneTimeZoneSuggestion getLatestPhoneSuggestion(int phoneId) {
+        LinkedList<QualifiedPhoneTimeZoneSuggestion> suggestions =
+                mSuggestionByPhoneId.get(phoneId);
+        if (suggestions == null) {
+            return null;
+        }
+        return suggestions.getFirst();
+    }
+
+    /**
+     * A {@link PhoneTimeZoneSuggestion} with additional qualifying metadata.
+     */
+    @VisibleForTesting
+    public static class QualifiedPhoneTimeZoneSuggestion {
+
+        @VisibleForTesting
+        public final PhoneTimeZoneSuggestion suggestion;
+
+        /**
+         * The score the suggestion has been given. This can be used to rank against other
+         * suggestions of the same type.
+         */
+        @VisibleForTesting
+        public final int score;
+
+        @VisibleForTesting
+        public QualifiedPhoneTimeZoneSuggestion(PhoneTimeZoneSuggestion suggestion, int score) {
+            this.suggestion = suggestion;
+            this.score = score;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            QualifiedPhoneTimeZoneSuggestion that = (QualifiedPhoneTimeZoneSuggestion) o;
+            return score == that.score
+                    && suggestion.equals(that.suggestion);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(score, suggestion);
+        }
+
+        @Override
+        public String toString() {
+            return "QualifiedPhoneTimeZoneSuggestion{"
+                    + "suggestion=" + suggestion
+                    + ", score=" + score
+                    + '}';
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/uri/GrantUri.java b/services/core/java/com/android/server/uri/GrantUri.java
index c694264..1571575 100644
--- a/services/core/java/com/android/server/uri/GrantUri.java
+++ b/services/core/java/com/android/server/uri/GrantUri.java
@@ -67,7 +67,7 @@
         return result;
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         long token = proto.start(fieldId);
         proto.write(GrantUriProto.URI, uri.toString());
         proto.write(GrantUriProto.SOURCE_USER_ID, sourceUserId);
diff --git a/services/core/java/com/android/server/uri/NeededUriGrants.java b/services/core/java/com/android/server/uri/NeededUriGrants.java
index 87a2641..0120394 100644
--- a/services/core/java/com/android/server/uri/NeededUriGrants.java
+++ b/services/core/java/com/android/server/uri/NeededUriGrants.java
@@ -34,7 +34,7 @@
         this.flags = flags;
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         long token = proto.start(fieldId);
         proto.write(NeededUriGrantsProto.TARGET_PACKAGE, targetPkg);
         proto.write(NeededUriGrantsProto.TARGET_UID, targetUid);
@@ -42,7 +42,7 @@
 
         final int N = this.size();
         for (int i = 0; i < N; i++) {
-            this.get(i).writeToProto(proto, NeededUriGrantsProto.GRANTS);
+            this.get(i).dumpDebug(proto, NeededUriGrantsProto.GRANTS);
         }
         proto.end(token);
     }
diff --git a/services/core/java/com/android/server/uri/UriPermissionOwner.java b/services/core/java/com/android/server/uri/UriPermissionOwner.java
index f814dc6..f2c06cd 100644
--- a/services/core/java/com/android/server/uri/UriPermissionOwner.java
+++ b/services/core/java/com/android/server/uri/UriPermissionOwner.java
@@ -141,20 +141,20 @@
         }
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         long token = proto.start(fieldId);
         proto.write(UriPermissionOwnerProto.OWNER, mOwner.toString());
         if (mReadPerms != null) {
             synchronized (mReadPerms) {
                 for (UriPermission p : mReadPerms) {
-                    p.uri.writeToProto(proto, UriPermissionOwnerProto.READ_PERMS);
+                    p.uri.dumpDebug(proto, UriPermissionOwnerProto.READ_PERMS);
                 }
             }
         }
         if (mWritePerms != null) {
             synchronized (mWritePerms) {
                 for (UriPermission p : mWritePerms) {
-                    p.uri.writeToProto(proto, UriPermissionOwnerProto.WRITE_PERMS);
+                    p.uri.dumpDebug(proto, UriPermissionOwnerProto.WRITE_PERMS);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java b/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
index 03c96e9..6bdb5ce 100644
--- a/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
+++ b/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
@@ -55,7 +55,16 @@
      * Default constructor using {@code system_server} tags.
      */
     public TimingsTraceAndSlog() {
-        this(SYSTEM_SERVER_TIMING_TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
+        this(SYSTEM_SERVER_TIMING_TAG);
+    }
+
+    /**
+     * Custom constructor using {@code system_server} trace tag.
+     *
+     * @param tag {@code logcat} tag
+     */
+    public TimingsTraceAndSlog(@NonNull String tag) {
+        this(tag, Trace.TRACE_TAG_SYSTEM_SERVER);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index d66aa18..03139d2e 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -104,6 +104,7 @@
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.utils.TimingsTraceAndSlog;
 import com.android.server.wm.WindowManagerInternal;
 
 import libcore.io.IoUtils;
@@ -1785,25 +1786,26 @@
 
     @Override
     public void onUnlockUser(final int userId) {
-        synchronized (mLock) {
-            if (mCurrentUserId == userId) {
-                if (mWaitingForUnlock) {
-                    // the desired wallpaper is not direct-boot aware, load it now
-                    final WallpaperData systemWallpaper =
-                            getWallpaperSafeLocked(userId, FLAG_SYSTEM);
-                    switchWallpaper(systemWallpaper, null);
-                    notifyCallbacksLocked(systemWallpaper);
-                }
+        TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG);
+        t.traceBegin("on-unlock-user-" + userId);
+        try {
+            synchronized (mLock) {
+                if (mCurrentUserId == userId) {
+                    if (mWaitingForUnlock) {
+                        // the desired wallpaper is not direct-boot aware, load it now
+                        final WallpaperData systemWallpaper =
+                                getWallpaperSafeLocked(userId, FLAG_SYSTEM);
+                        switchWallpaper(systemWallpaper, null);
+                        notifyCallbacksLocked(systemWallpaper);
+                    }
 
-                // Make sure that the SELinux labeling of all the relevant files is correct.
-                // This corrects for mislabeling bugs that might have arisen from move-to
-                // operations involving the wallpaper files.  This isn't timing-critical,
-                // so we do it in the background to avoid holding up the user unlock operation.
-                if (!mUserRestorecon.get(userId)) {
-                    mUserRestorecon.put(userId, true);
-                    Runnable relabeler = new Runnable() {
-                        @Override
-                        public void run() {
+                    // Make sure that the SELinux labeling of all the relevant files is correct.
+                    // This corrects for mislabeling bugs that might have arisen from move-to
+                    // operations involving the wallpaper files.  This isn't timing-critical,
+                    // so we do it in the background to avoid holding up the user unlock operation.
+                    if (!mUserRestorecon.get(userId)) {
+                        mUserRestorecon.put(userId, true);
+                        Runnable relabeler = () -> {
                             final File wallpaperDir = getWallpaperDir(userId);
                             for (String filename : sPerUserFiles) {
                                 File f = new File(wallpaperDir, filename);
@@ -1811,11 +1813,13 @@
                                     SELinux.restorecon(f);
                                 }
                             }
-                        }
-                    };
-                    BackgroundThread.getHandler().post(relabeler);
+                        };
+                        BackgroundThread.getHandler().post(relabeler);
+                    }
                 }
             }
+        } finally {
+            t.traceEnd();
         }
     }
 
@@ -1833,31 +1837,37 @@
     }
 
     void switchUser(int userId, IRemoteCallback reply) {
-        final WallpaperData systemWallpaper;
-        final WallpaperData lockWallpaper;
-        synchronized (mLock) {
-            if (mCurrentUserId == userId) {
-                return;
+        TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG);
+        t.traceBegin("switch-user-" + userId);
+        try {
+            final WallpaperData systemWallpaper;
+            final WallpaperData lockWallpaper;
+            synchronized (mLock) {
+                if (mCurrentUserId == userId) {
+                    return;
+                }
+                mCurrentUserId = userId;
+                systemWallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
+                final WallpaperData tmpLockWallpaper = mLockWallpaperMap.get(userId);
+                lockWallpaper = tmpLockWallpaper == null ? systemWallpaper : tmpLockWallpaper;
+                // Not started watching yet, in case wallpaper data was loaded for other reasons.
+                if (systemWallpaper.wallpaperObserver == null) {
+                    systemWallpaper.wallpaperObserver = new WallpaperObserver(systemWallpaper);
+                    systemWallpaper.wallpaperObserver.startWatching();
+                }
+                switchWallpaper(systemWallpaper, reply);
             }
-            mCurrentUserId = userId;
-            systemWallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
-            final WallpaperData tmpLockWallpaper = mLockWallpaperMap.get(userId);
-            lockWallpaper = tmpLockWallpaper == null ? systemWallpaper : tmpLockWallpaper;
-            // Not started watching yet, in case wallpaper data was loaded for other reasons.
-            if (systemWallpaper.wallpaperObserver == null) {
-                systemWallpaper.wallpaperObserver = new WallpaperObserver(systemWallpaper);
-                systemWallpaper.wallpaperObserver.startWatching();
-            }
-            switchWallpaper(systemWallpaper, reply);
-        }
 
-        // Offload color extraction to another thread since switchUser will be called
-        // from the main thread.
-        FgThread.getHandler().post(() -> {
-            notifyWallpaperColorsChanged(systemWallpaper, FLAG_SYSTEM);
-            notifyWallpaperColorsChanged(lockWallpaper, FLAG_LOCK);
-            notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM);
-        });
+            // Offload color extraction to another thread since switchUser will be called
+            // from the main thread.
+            FgThread.getHandler().post(() -> {
+                notifyWallpaperColorsChanged(systemWallpaper, FLAG_SYSTEM);
+                notifyWallpaperColorsChanged(lockWallpaper, FLAG_LOCK);
+                notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM);
+            });
+        } finally {
+            t.traceEnd();
+        }
     }
 
     void switchWallpaper(WallpaperData wallpaper, IRemoteCallback reply) {
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index be7dfe5..84152e8 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -17,8 +17,6 @@
 package com.android.server.wm;
 
 import static android.app.ActivityTaskManager.INVALID_STACK_ID;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
@@ -34,7 +32,7 @@
 import static android.view.Display.FLAG_PRIVATE;
 import static android.view.Display.REMOVE_MODE_DESTROY_CONTENT;
 
-import static com.android.server.am.ActivityDisplayProto.CONFIGURATION_CONTAINER;
+import static com.android.server.am.ActivityDisplayProto.DISPLAY;
 import static com.android.server.am.ActivityDisplayProto.FOCUSED_STACK_ID;
 import static com.android.server.am.ActivityDisplayProto.ID;
 import static com.android.server.am.ActivityDisplayProto.RESUMED_ACTIVITY;
@@ -52,6 +50,7 @@
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
 import static com.android.server.wm.RootActivityContainer.FindTaskResult;
 import static com.android.server.wm.RootActivityContainer.TAG_STATES;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
 
@@ -73,8 +72,9 @@
 import android.view.Display;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.function.pooled.PooledConsumer;
 import com.android.internal.util.function.pooled.PooledLambda;
-import com.android.server.am.EventLogTags;
+import com.android.internal.util.function.pooled.PooledPredicate;
 import com.android.server.protolog.common.ProtoLog;
 
 import java.io.PrintWriter;
@@ -84,23 +84,19 @@
  * Exactly one of these classes per Display in the system. Capable of holding zero or more
  * attached {@link ActivityStack}s.
  */
-class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
+class ActivityDisplay extends DisplayContent {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityDisplay" : TAG_ATM;
     private static final String TAG_STACK = TAG + POSTFIX_STACK;
 
     static final int POSITION_TOP = Integer.MAX_VALUE;
     static final int POSITION_BOTTOM = Integer.MIN_VALUE;
 
-
     /**
      * Counter for next free stack ID to use for dynamic activity stacks. Unique across displays.
      */
     private static int sNextFreeStackId = 0;
 
-    private ActivityTaskManagerService mService;
     private RootActivityContainer mRootActivityContainer;
-    // TODO: Remove once unification is complete.
-    DisplayContent mDisplayContent;
     /** Actual Display this object tracks. */
     int mDisplayId;
     Display mDisplay;
@@ -110,7 +106,6 @@
      * stacks, bottommost behind. Accessed directly by ActivityManager package classes. Any calls
      * changing the list should also call {@link #onStackOrderChanged()}.
      */
-    private final ArrayList<ActivityStack> mStacks = new ArrayList<>();
     private ArrayList<OnStackOrderChangedListener> mStackOrderChangedCallbacks = new ArrayList<>();
 
     /** Array of all UIDs that are present on the display. */
@@ -156,13 +151,6 @@
      */
     private ActivityStack mLastFocusedStack;
 
-    // Cached reference to some special stacks we tend to get a lot so we don't need to loop
-    // through the list to find them.
-    private ActivityStack mHomeStack = null;
-    private ActivityStack mRecentsStack = null;
-    private ActivityStack mPinnedStack = null;
-    private ActivityStack mSplitScreenPrimaryStack = null;
-
     // Used in updating the display size
     private Point mTmpDisplaySize = new Point();
 
@@ -172,15 +160,24 @@
     private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
 
     ActivityDisplay(RootActivityContainer root, Display display) {
+        super(display, root.mWindowManager);
         mRootActivityContainer = root;
-        mService = root.mService;
         mDisplayId = display.getDisplayId();
         mDisplay = display;
-        mDisplayContent = mService.mWindowManager.mRoot.createDisplayContent(mDisplay, this);
-        mDisplayContent.reconfigureDisplayLocked();
-        onRequestedOverrideConfigurationChanged(
-                mDisplayContent.getRequestedOverrideConfiguration());
-        mService.mWindowManager.mDisplayNotificationController.dispatchDisplayAdded(this);
+
+        if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Adding display=" + display);
+
+        mWmService.mDisplayWindowSettings.applySettingsToDisplayLocked(this);
+
+        if (mWmService.mDisplayManagerInternal != null) {
+            mWmService.mDisplayManagerInternal
+                .setDisplayInfoOverrideFromWindowManager(mDisplayId, getDisplayInfo());
+            configureDisplayPolicy();
+        }
+
+        reconfigureDisplayLocked();
+        onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration());
+        mWmService.mDisplayNotificationController.dispatchDisplayAdded(this);
     }
 
     void onDisplayChanged() {
@@ -189,7 +186,7 @@
         if (displayId != DEFAULT_DISPLAY) {
             final int displayState = mDisplay.getState();
             if (displayState == Display.STATE_OFF && mOffToken == null) {
-                mOffToken = mService.acquireSleepToken("Display-off", displayId);
+                mOffToken = mAtmService.acquireSleepToken("Display-off", displayId);
             } else if (displayState == Display.STATE_ON && mOffToken != null) {
                 mOffToken.release();
                 mOffToken = null;
@@ -198,98 +195,72 @@
 
         mDisplay.getRealSize(mTmpDisplaySize);
         setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
-        if (mDisplayContent != null) {
-            mDisplayContent.updateDisplayInfo();
-            mService.mWindowManager.requestTraversal();
-        }
+        updateDisplayInfo();
+        mWmService.requestTraversal();
     }
 
-    // TODO(display-unify): Merge with addChild below.
-    void addChild(ActivityStack stack, int position) {
-        addChild(stack, position, false /*fromDc*/);
+    void addStack(ActivityStack stack, int position) {
+        setStackOnDisplay(stack, position);
+        positionStackAt(stack, position);
+        mAtmService.updateSleepIfNeededLocked();
     }
 
-    void addChild(ActivityStack stack, int position, boolean fromDc) {
-        boolean toTop = position == POSITION_TOP;
-        if (position == POSITION_BOTTOM) {
-            position = 0;
-        } else if (toTop) {
-            position = getChildCount();
+    void onStackRemoved(ActivityStack stack) {
+        if (DEBUG_STACK) {
+            Slog.v(TAG_STACK, "removeStack: detaching " + stack + " from displayId=" + mDisplayId);
         }
-        if (DEBUG_STACK) Slog.v(TAG_STACK, "addChild: attaching " + stack
-                + " to displayId=" + mDisplayId + " position=" + position);
-        addStackReferenceIfNeeded(stack);
-        if (!fromDc) {
-            mDisplayContent.setStackOnDisplay(stack, position);
-        }
-        positionChildAt(stack, position);
-        mService.updateSleepIfNeededLocked();
-    }
-
-    // TODO(display-unify): Merge with removeChild below.
-    void onChildRemoved(ActivityStack stack) {
-        if (!mStacks.remove(stack)) {
-            // Stack no longer here!
-            return;
-        }
-
-        if (DEBUG_STACK) Slog.v(TAG_STACK, "removeChild: detaching " + stack
-                + " from displayId=" + mDisplayId);
         if (mPreferredTopFocusableStack == stack) {
             mPreferredTopFocusableStack = null;
         }
-        removeStackReferenceIfNeeded(stack);
         releaseSelfIfNeeded();
-        mService.updateSleepIfNeededLocked();
+        mAtmService.updateSleepIfNeededLocked();
         onStackOrderChanged(stack);
     }
 
-    void removeChild(ActivityStack stack) {
-        mDisplayContent.removeStackFromDisplay(stack);
+    void positionStackAtTop(ActivityStack stack, boolean includingParents) {
+        positionStackAtTop(stack, includingParents, null /* updateLastFocusedStackReason */);
     }
 
-    void positionChildAtTop(ActivityStack stack, boolean includingParents) {
-        positionChildAtTop(stack, includingParents, null /* updateLastFocusedStackReason */);
-    }
-
-    void positionChildAtTop(ActivityStack stack, boolean includingParents,
+    void positionStackAtTop(ActivityStack stack, boolean includingParents,
             String updateLastFocusedStackReason) {
-        positionChildAt(stack, getChildCount(), includingParents, updateLastFocusedStackReason);
+        positionStackAt(stack, getStackCount(), includingParents, updateLastFocusedStackReason);
     }
 
-    void positionChildAtBottom(ActivityStack stack) {
-        positionChildAtBottom(stack, null /* updateLastFocusedStackReason */);
+    void positionStackAtBottom(ActivityStack stack) {
+        positionStackAtBottom(stack, null /* updateLastFocusedStackReason */);
     }
 
-    void positionChildAtBottom(ActivityStack stack, String updateLastFocusedStackReason) {
-        positionChildAt(stack, 0, false /* includingParents */, updateLastFocusedStackReason);
+    void positionStackAtBottom(ActivityStack stack, String updateLastFocusedStackReason) {
+        positionStackAt(stack, 0, false /* includingParents */, updateLastFocusedStackReason);
     }
 
-    private void positionChildAt(ActivityStack stack, int position) {
-        positionChildAt(stack, position, false /* includingParents */,
+    private void positionStackAt(ActivityStack stack, int position) {
+        positionStackAt(stack, position, false /* includingParents */,
                 null /* updateLastFocusedStackReason */);
     }
 
-    private void positionChildAt(ActivityStack stack, int position, boolean includingParents,
+    private void positionStackAt(ActivityStack stack, int position, boolean includingParents,
             String updateLastFocusedStackReason) {
         // TODO: Keep in sync with WindowContainer.positionChildAt(), once we change that to adjust
         //       the position internally, also update the logic here
         final ActivityStack prevFocusedStack = updateLastFocusedStackReason != null
                 ? getFocusedStack() : null;
-        final boolean wasContained = mStacks.remove(stack);
-        if (mSingleTaskInstance && getChildCount() > 0) {
+        final boolean wasContained = getIndexOf(stack) >= 0;
+        if (mSingleTaskInstance && getStackCount() == 1 && !wasContained) {
             throw new IllegalStateException(
-                    "positionChildAt: Can only have one child on display=" + this);
+                    "positionStackAt: Can only have one task on display=" + this);
         }
-        final int insertPosition = getTopInsertPosition(stack, position);
-        mStacks.add(insertPosition, stack);
+
+        // Since positionChildAt() is called during the creation process of pinned stacks,
+        // ActivityStack#getStack() can be null.
+        positionStackAt(position, stack, includingParents);
 
         // The insert position may be adjusted to non-top when there is always-on-top stack. Since
         // the original position is preferred to be top, the stack should have higher priority when
         // we are looking for top focusable stack. The condition {@code wasContained} restricts the
         // preferred stack is set only when moving an existing stack to top instead of adding a new
         // stack that may be too early (e.g. in the middle of launching or reparenting).
-        if (wasContained && position >= getChildCount() - 1 && stack.isFocusableAndVisible()) {
+        if (wasContained && position >= getStackCount() - 1 && stack.isFocusableAndVisible()) {
             mPreferredTopFocusableStack = stack;
         } else if (mPreferredTopFocusableStack == stack) {
             mPreferredTopFocusableStack = null;
@@ -299,74 +270,21 @@
             final ActivityStack currentFocusedStack = getFocusedStack();
             if (currentFocusedStack != prevFocusedStack) {
                 mLastFocusedStack = prevFocusedStack;
-                EventLogTags.writeAmFocusedStack(mRootActivityContainer.mCurrentUser, mDisplayId,
+                EventLogTags.writeWmFocusedStack(mRootActivityContainer.mCurrentUser, mDisplayId,
                         currentFocusedStack == null ? -1 : currentFocusedStack.getStackId(),
                         mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(),
                         updateLastFocusedStackReason);
             }
         }
 
-        // Since positionChildAt() is called during the creation process of pinned stacks,
-        // ActivityStack#getStack() can be null.
-        if (mDisplayContent != null) {
-            mDisplayContent.positionStackAt(insertPosition, stack, includingParents);
-        }
         onStackOrderChanged(stack);
     }
 
-    private int getTopInsertPosition(ActivityStack stack, int candidatePosition) {
-        int position = getChildCount();
-        if (stack.inPinnedWindowingMode()) {
-            // Stack in pinned windowing mode is z-ordered on-top of all other stacks so okay to
-            // just return the candidate position.
-            return Math.min(position, candidatePosition);
-        }
-        while (position > 0) {
-            final ActivityStack targetStack = getChildAt(position - 1);
-            if (!targetStack.isAlwaysOnTop()) {
-                // We reached a stack that isn't always-on-top.
-                break;
-            }
-            if (stack.isAlwaysOnTop() && !targetStack.inPinnedWindowingMode()) {
-                // Always on-top non-pinned windowing mode stacks can go anywhere below pinned stack.
-                break;
-            }
-            position--;
-        }
-        return Math.min(position, candidatePosition);
-    }
-
-    <T extends ActivityStack> T getStack(int stackId) {
-        for (int i = getChildCount() - 1; i >= 0; --i) {
-            final ActivityStack stack = getChildAt(i);
+    ActivityStack getStack(int stackId) {
+        for (int i = getStackCount() - 1; i >= 0; --i) {
+            final ActivityStack stack = getStackAt(i);
             if (stack.mStackId == stackId) {
-                return (T) stack;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * @return the topmost stack on the display that is compatible with the input windowing mode and
-     * activity type. {@code null} means no compatible stack on the display.
-     * @see ConfigurationContainer#isCompatible(int, int)
-     */
-    <T extends ActivityStack> T getStack(int windowingMode, int activityType) {
-        if (activityType == ACTIVITY_TYPE_HOME) {
-            return (T) mHomeStack;
-        } else if (activityType == ACTIVITY_TYPE_RECENTS) {
-            return (T) mRecentsStack;
-        }
-        if (windowingMode == WINDOWING_MODE_PINNED) {
-            return (T) mPinnedStack;
-        } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
-            return (T) mSplitScreenPrimaryStack;
-        }
-
-        for (int i = getChildCount() - 1; i >= 0; --i) {
-            final ActivityStack stack = getChildAt(i);
-            if (stack.isCompatible(windowingMode, activityType)) {
-                return (T) stack;
+                return stack;
             }
         }
         return null;
@@ -387,10 +305,10 @@
      * @see #getStack(int, int)
      * @see #createStack(int, int, boolean)
      */
-    <T extends ActivityStack> T getOrCreateStack(int windowingMode, int activityType,
+    ActivityStack getOrCreateStack(int windowingMode, int activityType,
             boolean onTop) {
         if (!alwaysCreateStack(windowingMode, activityType)) {
-            T stack = getStack(windowingMode, activityType);
+            ActivityStack stack = getStack(windowingMode, activityType);
             if (stack != null) {
                 return stack;
             }
@@ -403,7 +321,7 @@
      * if a compatible stack doesn't exist.
      * @see #getOrCreateStack(int, int, boolean)
      */
-    <T extends ActivityStack> T getOrCreateStack(@Nullable ActivityRecord r,
+    ActivityStack getOrCreateStack(@Nullable ActivityRecord r,
             @Nullable ActivityOptions options, @Nullable Task candidateTask, int activityType,
             boolean onTop) {
         // First preference is the windowing mode in the activity options if set.
@@ -432,9 +350,9 @@
      * @param onTop If true the stack will be created at the top of the display, else at the bottom.
      * @return The newly created stack.
      */
-    <T extends ActivityStack> T createStack(int windowingMode, int activityType, boolean onTop) {
+    ActivityStack createStack(int windowingMode, int activityType, boolean onTop) {
 
-        if (mSingleTaskInstance && getChildCount() > 0) {
+        if (mSingleTaskInstance && getStackCount() > 0) {
             // Create stack on default display instead since this display can only contain 1 stack.
             // TODO: Kinda a hack, but better that having the decision at each call point. Hoping
             // this goes away once ActivityView is no longer using virtual displays.
@@ -451,17 +369,17 @@
         if (activityType != ACTIVITY_TYPE_STANDARD) {
             // For now there can be only one stack of a particular non-standard activity type on a
             // display. So, get that ignoring whatever windowing mode it is currently in.
-            T stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
+            ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
             if (stack != null) {
                 throw new IllegalArgumentException("Stack=" + stack + " of activityType="
                         + activityType + " already on display=" + this + ". Can't have multiple.");
             }
         }
 
-        if (!isWindowingModeSupported(windowingMode, mService.mSupportsMultiWindow,
-                mService.mSupportsSplitScreenMultiWindow,
-                mService.mSupportsFreeformWindowManagement, mService.mSupportsPictureInPicture,
-                activityType)) {
+        if (!isWindowingModeSupported(windowingMode, mAtmService.mSupportsMultiWindow,
+                mAtmService.mSupportsSplitScreenMultiWindow,
+                mAtmService.mSupportsFreeformWindowManagement,
+                mAtmService.mSupportsPictureInPicture, activityType)) {
             throw new IllegalArgumentException("Can't create stack for unsupported windowingMode="
                     + windowingMode);
         }
@@ -471,13 +389,13 @@
     }
 
     @VisibleForTesting
-    <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType,
+    ActivityStack createStackUnchecked(int windowingMode, int activityType,
             int stackId, boolean onTop) {
         if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) {
             throw new IllegalArgumentException("Stack with windowing mode cannot with non standard "
                     + "activity type.");
         }
-        return (T) new ActivityStack(this, stackId,
+        return new ActivityStack(this, stackId,
                 mRootActivityContainer.mStackSupervisor, windowingMode, activityType, onTop);
     }
 
@@ -490,8 +408,8 @@
             return mPreferredTopFocusableStack;
         }
 
-        for (int i = getChildCount() - 1; i >= 0; --i) {
-            final ActivityStack stack = getChildAt(i);
+        for (int i = getStackCount() - 1; i >= 0; --i) {
+            final ActivityStack stack = getStackAt(i);
             if (stack.isFocusableAndVisible()) {
                 return stack;
             }
@@ -505,8 +423,8 @@
                 ? currentFocus.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
 
         ActivityStack candidate = null;
-        for (int i = getChildCount() - 1; i >= 0; --i) {
-            final ActivityStack stack = getChildAt(i);
+        for (int i = getStackCount() - 1; i >= 0; --i) {
+            final ActivityStack stack = getStackAt(i);
             if (ignoreCurrent && stack == currentFocus) {
                 continue;
             }
@@ -561,8 +479,8 @@
     }
 
     boolean allResumedActivitiesComplete() {
-        for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityRecord r = getChildAt(stackNdx).getResumedActivity();
+        for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityRecord r = getStackAt(stackNdx).getResumedActivity();
             if (r != null && !r.isState(RESUMED)) {
                 return false;
             }
@@ -588,8 +506,8 @@
      */
     boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming) {
         boolean someActivityPaused = false;
-        for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = getChildAt(stackNdx);
+        for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = getStackAt(stackNdx);
             final ActivityRecord resumedActivity = stack.getResumedActivity();
             if (resumedActivity != null
                     && (stack.getVisibility(resuming) != STACK_VISIBILITY_VISIBLE
@@ -609,8 +527,8 @@
     void findTaskLocked(final ActivityRecord r, final boolean isPreferredDisplay,
             FindTaskResult result) {
         mTmpFindTaskResult.clear();
-        for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = getChildAt(stackNdx);
+        for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = getStackAt(stackNdx);
             if (!r.hasCompatibleActivityType(stack)) {
                 if (DEBUG_TASKS) {
                     Slog.d(TAG_TASKS, "Skipping stack: (mismatch activity/stack) " + stack);
@@ -618,7 +536,7 @@
                 continue;
             }
 
-            stack.findTaskLocked(r, mTmpFindTaskResult);
+            mTmpFindTaskResult.process(r, stack);
             // It is possible to have tasks in multiple stacks with the same root affinity, so
             // we should keep looking after finding an affinity match to see if there is a
             // better match in another stack. Also, task affinity isn't a good enough reason
@@ -653,8 +571,8 @@
         final ArrayList<ActivityStack> stacks = new ArrayList<>();
         for (int j = windowingModes.length - 1 ; j >= 0; --j) {
             final int windowingMode = windowingModes[j];
-            for (int i = getChildCount() - 1; i >= 0; --i) {
-                final ActivityStack stack = getChildAt(i);
+            for (int i = getStackCount() - 1; i >= 0; --i) {
+                final ActivityStack stack = getStackAt(i);
                 if (!stack.isActivityTypeStandardOrUndefined()) {
                     continue;
                 }
@@ -681,8 +599,8 @@
         final ArrayList<ActivityStack> stacks = new ArrayList<>();
         for (int j = activityTypes.length - 1 ; j >= 0; --j) {
             final int activityType = activityTypes[j];
-            for (int i = getChildCount() - 1; i >= 0; --i) {
-                final ActivityStack stack = getChildAt(i);
+            for (int i = getStackCount() - 1; i >= 0; --i) {
+                final ActivityStack stack = getStackAt(i);
                 if (stack.getActivityType() == activityType) {
                     stacks.add(stack);
                 }
@@ -694,67 +612,12 @@
         }
     }
 
-    void onStackWindowingModeChanged(ActivityStack stack) {
-        removeStackReferenceIfNeeded(stack);
-        addStackReferenceIfNeeded(stack);
-    }
-
-    private void addStackReferenceIfNeeded(ActivityStack stack) {
-        final int activityType = stack.getActivityType();
-        final int windowingMode = stack.getWindowingMode();
-
-        if (activityType == ACTIVITY_TYPE_HOME) {
-            if (mHomeStack != null && mHomeStack != stack) {
-                throw new IllegalArgumentException("addStackReferenceIfNeeded: home stack="
-                        + mHomeStack + " already exist on display=" + this + " stack=" + stack);
-            }
-            mHomeStack = stack;
-        } else if (activityType == ACTIVITY_TYPE_RECENTS) {
-            if (mRecentsStack != null && mRecentsStack != stack) {
-                throw new IllegalArgumentException("addStackReferenceIfNeeded: recents stack="
-                        + mRecentsStack + " already exist on display=" + this + " stack=" + stack);
-            }
-            mRecentsStack = stack;
-        }
-        if (windowingMode == WINDOWING_MODE_PINNED) {
-            if (mPinnedStack != null && mPinnedStack != stack) {
-                throw new IllegalArgumentException("addStackReferenceIfNeeded: pinned stack="
-                        + mPinnedStack + " already exist on display=" + this
-                        + " stack=" + stack);
-            }
-            mPinnedStack = stack;
-        } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
-            if (mSplitScreenPrimaryStack != null && mSplitScreenPrimaryStack != stack) {
-                throw new IllegalArgumentException("addStackReferenceIfNeeded:"
-                        + " split-screen-primary" + " stack=" + mSplitScreenPrimaryStack
-                        + " already exist on display=" + this + " stack=" + stack);
-            }
-            mSplitScreenPrimaryStack = stack;
-            onSplitScreenModeActivated();
-        }
-    }
-
-    private void removeStackReferenceIfNeeded(ActivityStack stack) {
-        if (stack == mHomeStack) {
-            mHomeStack = null;
-        } else if (stack == mRecentsStack) {
-            mRecentsStack = null;
-        } else if (stack == mPinnedStack) {
-            mPinnedStack = null;
-        } else if (stack == mSplitScreenPrimaryStack) {
-            mSplitScreenPrimaryStack = null;
-            // Inform the reset of the system that split-screen mode was dismissed so things like
-            // resizing all the other stacks can take place.
-            onSplitScreenModeDismissed();
-        }
-    }
-
-    private void onSplitScreenModeDismissed() {
-        mService.deferWindowLayout();
+    void onSplitScreenModeDismissed() {
+        mAtmService.deferWindowLayout();
         try {
             // Adjust the windowing mode of any stack in secondary split-screen to fullscreen.
-            for (int i = getChildCount() - 1; i >= 0; --i) {
-                final ActivityStack otherStack = getChildAt(i);
+            for (int i = getStackCount() - 1; i >= 0; --i) {
+                final ActivityStack otherStack = getStackAt(i);
                 if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
                     continue;
                 }
@@ -765,26 +628,28 @@
         } finally {
             final ActivityStack topFullscreenStack =
                     getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
-            if (topFullscreenStack != null && mHomeStack != null && !isTopStack(mHomeStack)) {
+            final ActivityStack homeStack = getHomeStack();
+            if (topFullscreenStack != null && homeStack != null && !isTopStack(homeStack)) {
                 // Whenever split-screen is dismissed we want the home stack directly behind the
                 // current top fullscreen stack so it shows up when the top stack is finished.
                 // TODO: Would be better to use ActivityDisplay.positionChildAt() for this, however
                 // ActivityDisplay doesn't have a direct controller to WM side yet. We can switch
                 // once we have that.
-                mHomeStack.moveToFront("onSplitScreenModeDismissed");
+                homeStack.moveToFront("onSplitScreenModeDismissed");
                 topFullscreenStack.moveToFront("onSplitScreenModeDismissed");
             }
-            mService.continueWindowLayout();
+            mAtmService.continueWindowLayout();
         }
     }
 
-    private void onSplitScreenModeActivated() {
-        mService.deferWindowLayout();
+    void onSplitScreenModeActivated() {
+        mAtmService.deferWindowLayout();
         try {
             // Adjust the windowing mode of any affected by split-screen to split-screen secondary.
-            for (int i = getChildCount() - 1; i >= 0; --i) {
-                final ActivityStack otherStack = getChildAt(i);
-                if (otherStack == mSplitScreenPrimaryStack
+            final ActivityStack splitScreenPrimaryStack = getSplitScreenPrimaryStack();
+            for (int i = getStackCount() - 1; i >= 0; --i) {
+                final ActivityStack otherStack = getStackAt(i);
+                if (otherStack == splitScreenPrimaryStack
                         || !otherStack.affectedBySplitScreenResize()) {
                     continue;
                 }
@@ -794,7 +659,7 @@
                         false /* creating */);
             }
         } finally {
-            mService.continueWindowLayout();
+            mAtmService.continueWindowLayout();
         }
     }
 
@@ -889,10 +754,10 @@
     int validateWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task,
             int activityType) {
         // Make sure the windowing mode we are trying to use makes sense for what is supported.
-        boolean supportsMultiWindow = mService.mSupportsMultiWindow;
-        boolean supportsSplitScreen = mService.mSupportsSplitScreenMultiWindow;
-        boolean supportsFreeform = mService.mSupportsFreeformWindowManagement;
-        boolean supportsPip = mService.mSupportsPictureInPicture;
+        boolean supportsMultiWindow = mAtmService.mSupportsMultiWindow;
+        boolean supportsSplitScreen = mAtmService.mSupportsSplitScreenMultiWindow;
+        boolean supportsFreeform = mAtmService.mSupportsFreeformWindowManagement;
+        boolean supportsPip = mAtmService.mSupportsPictureInPicture;
         if (supportsMultiWindow) {
             if (task != null) {
                 supportsMultiWindow = task.isResizeable();
@@ -926,21 +791,13 @@
         return WINDOWING_MODE_UNDEFINED;
     }
 
-    /**
-     * Get the topmost stack on the display. It may be different from focused stack, because
-     * some stacks are not focusable (e.g. PiP).
-     */
-    ActivityStack getTopStack() {
-        return mStacks.isEmpty() ? null : getChildAt(getChildCount() - 1);
-    }
-
     boolean isTopStack(ActivityStack stack) {
         return stack == getTopStack();
     }
 
     boolean isTopNotPinnedStack(ActivityStack stack) {
-        for (int i = getChildCount() - 1; i >= 0; --i) {
-            final ActivityStack current = getChildAt(i);
+        for (int i = getStackCount() - 1; i >= 0; --i) {
+            final ActivityStack current = getStackAt(i);
             if (!current.inPinnedWindowingMode()) {
                 return current == stack;
             }
@@ -949,8 +806,8 @@
     }
 
     ActivityStack getTopStackInWindowingMode(int windowingMode) {
-        for (int i = getChildCount() - 1; i >= 0; --i) {
-            final ActivityStack current = getChildAt(i);
+        for (int i = getStackCount() - 1; i >= 0; --i) {
+            final ActivityStack current = getStackAt(i);
             if (windowingMode == current.getWindowingMode()) {
                 return current;
             }
@@ -980,8 +837,8 @@
 
         // Look in other focusable stacks.
         if (topRunning == null) {
-            for (int i = getChildCount() - 1; i >= 0; --i) {
-                final ActivityStack stack = getChildAt(i);
+            for (int i = getStackCount() - 1; i >= 0; --i) {
+                final ActivityStack stack = getStackAt(i);
                 // Only consider focusable stacks other than the current focused one.
                 if (stack == focusedStack || !stack.isFocusable()) {
                     continue;
@@ -1004,22 +861,18 @@
         return topRunning;
     }
 
-    int getIndexOf(ActivityStack stack) {
-        return mStacks.indexOf(stack);
-    }
-
     boolean updateDisplayOverrideConfigurationLocked() {
         Configuration values = new Configuration();
-        mDisplayContent.computeScreenConfiguration(values);
+        computeScreenConfiguration(values);
 
-        mService.mH.sendMessage(PooledLambda.obtainMessage(
-                ActivityManagerInternal::updateOomLevelsForDisplay, mService.mAmInternal,
+        mAtmService.mH.sendMessage(PooledLambda.obtainMessage(
+                ActivityManagerInternal::updateOomLevelsForDisplay, mAtmService.mAmInternal,
                 mDisplayId));
 
         Settings.System.clearConfiguration(values);
         updateDisplayOverrideConfigurationLocked(values, null /* starting */,
-                false /* deferResume */, mService.mTmpUpdateConfigurationResult);
-        return mService.mTmpUpdateConfigurationResult.changes != 0;
+                false /* deferResume */, mAtmService.mTmpUpdateConfigurationResult);
+        return mAtmService.mTmpUpdateConfigurationResult.changes != 0;
     }
 
     /**
@@ -1033,14 +886,14 @@
         int changes = 0;
         boolean kept = true;
 
-        mService.deferWindowLayout();
+        mAtmService.deferWindowLayout();
         try {
             if (values != null) {
                 if (mDisplayId == DEFAULT_DISPLAY) {
                     // Override configuration of the default display duplicates global config, so
                     // we're calling global config update instead for default display. It will also
                     // apply the correct override config.
-                    changes = mService.updateGlobalConfigurationLocked(values,
+                    changes = mAtmService.updateGlobalConfigurationLocked(values,
                             false /* initLocale */, false /* persistent */,
                             UserHandle.USER_NULL /* userId */, deferResume);
                 } else {
@@ -1048,9 +901,9 @@
                 }
             }
 
-            kept = mService.ensureConfigAndVisibilityAfterUpdate(starting, changes);
+            kept = mAtmService.ensureConfigAndVisibilityAfterUpdate(starting, changes);
         } finally {
-            mService.continueWindowLayout();
+            mAtmService.continueWindowLayout();
         }
 
         if (result != null) {
@@ -1070,17 +923,17 @@
 
             final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
             if (isDensityChange && mDisplayId == DEFAULT_DISPLAY) {
-                mService.mAppWarnings.onDensityChanged();
+                mAtmService.mAppWarnings.onDensityChanged();
 
                 // Post message to start process to avoid possible deadlock of calling into AMS with
                 // the ATMS lock held.
                 final Message msg = PooledLambda.obtainMessage(
                         ActivityManagerInternal::killAllBackgroundProcessesExcept,
-                        mService.mAmInternal, N,
+                        mAtmService.mAmInternal, N,
                         ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
-                mService.mH.sendMessage(msg);
+                mAtmService.mH.sendMessage(msg);
             }
-            mService.mWindowManager.mDisplayNotificationController.dispatchDisplayChanged(
+            mWmService.mDisplayNotificationController.dispatchDisplayChanged(
                     this, getConfiguration());
         }
         return changes;
@@ -1091,43 +944,29 @@
         final int currRotation =
                 getRequestedOverrideConfiguration().windowConfiguration.getRotation();
         if (currRotation != ROTATION_UNDEFINED
-                && currRotation != overrideConfiguration.windowConfiguration.getRotation()
-                && mDisplayContent != null) {
-            mDisplayContent.applyRotationLocked(currRotation,
+                && currRotation != overrideConfiguration.windowConfiguration.getRotation()) {
+            applyRotationLocked(currRotation,
                     overrideConfiguration.windowConfiguration.getRotation());
         }
         super.onRequestedOverrideConfigurationChanged(overrideConfiguration);
-        if (mDisplayContent != null) {
-            mService.mWindowManager.setNewDisplayOverrideConfiguration(
-                    overrideConfiguration, mDisplayContent);
-        }
-        mService.addWindowLayoutReasons(
+        mWmService.setNewDisplayOverrideConfiguration(overrideConfiguration, this);
+        mAtmService.addWindowLayoutReasons(
                 ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED);
     }
 
     @Override
     public void onConfigurationChanged(Configuration newParentConfig) {
         // update resources before cascade so that docked/pinned stacks use the correct info
-        if (mDisplayContent != null) {
-            mDisplayContent.preOnConfigurationChanged();
-        }
+        preOnConfigurationChanged();
         super.onConfigurationChanged(newParentConfig);
     }
 
     void onLockTaskPackagesUpdated() {
-        for (int i = getChildCount() - 1; i >= 0; --i) {
-            getChildAt(i).onLockTaskPackagesUpdated();
+        for (int i = getStackCount() - 1; i >= 0; --i) {
+            getStackAt(i).onLockTaskPackagesUpdated();
         }
     }
 
-    /** We are in the process of exiting split-screen mode. */
-    void onExitingSplitScreenMode() {
-        // Remove reference to the primary-split-screen stack so it no longer has any effect on the
-        // display. For example, we want to be able to create fullscreen stack for standard activity
-        // types when exiting split-screen mode.
-        mSplitScreenPrimaryStack = null;
-    }
-
     /** Checks whether the given activity is in size compatibility mode and notifies the change. */
     void handleActivitySizeCompatModeIfNeeded(ActivityRecord r) {
         if (!r.isState(RESUMED) || r.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
@@ -1136,7 +975,7 @@
         }
         if (!r.inSizeCompatMode()) {
             if (mLastCompatModeActivity != null) {
-                mService.getTaskChangeNotificationController()
+                mAtmService.getTaskChangeNotificationController()
                         .notifySizeCompatModeActivityChanged(mDisplayId, null /* activityToken */);
             }
             mLastCompatModeActivity = null;
@@ -1146,44 +985,13 @@
             return;
         }
         mLastCompatModeActivity = r;
-        mService.getTaskChangeNotificationController()
+        mAtmService.getTaskChangeNotificationController()
                 .notifySizeCompatModeActivityChanged(mDisplayId, r.appToken);
     }
 
-    ActivityStack getSplitScreenPrimaryStack() {
-        return mSplitScreenPrimaryStack;
-    }
-
-    boolean hasSplitScreenPrimaryStack() {
-        return mSplitScreenPrimaryStack != null;
-    }
-
-    ActivityStack getPinnedStack() {
-        return mPinnedStack;
-    }
-
-    boolean hasPinnedStack() {
-        return mPinnedStack != null;
-    }
-
     @Override
     public String toString() {
-        return "ActivityDisplay={" + mDisplayId + " numStacks=" + getChildCount() + "}";
-    }
-
-    @Override
-    protected int getChildCount() {
-        return mStacks.size();
-    }
-
-    @Override
-    protected ActivityStack getChildAt(int index) {
-        return mStacks.get(index);
-    }
-
-    @Override
-    protected ConfigurationContainer getParent() {
-        return mRootActivityContainer;
+        return "ActivityDisplay={" + mDisplayId + " numStacks=" + getStackCount() + "}";
     }
 
     boolean isPrivate() {
@@ -1191,12 +999,11 @@
     }
 
     boolean isUidPresent(int uid) {
-        for (ActivityStack stack : mStacks) {
-            if (stack.isUidPresent(uid)) {
-                return true;
-            }
-        }
-        return false;
+        final PooledPredicate p = PooledLambda.obtainPredicate(
+                ActivityRecord::isUid, PooledLambda.__(ActivityRecord.class), uid);
+        final boolean isUidPresent = mDisplayContent.getActivity(p) != null;
+        p.recycle();
+        return isUidPresent;
     }
 
     /**
@@ -1227,10 +1034,10 @@
         final ActivityDisplay toDisplay = mRootActivityContainer.getDefaultDisplay();
         mRootActivityContainer.mStackSupervisor.beginDeferResume();
         try {
-            int numStacks = getChildCount();
+            int numStacks = getStackCount();
             // Keep the order from bottom to top.
             for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
-                final ActivityStack stack = getChildAt(stackNdx);
+                final ActivityStack stack = getStackAt(stackNdx);
                 // Always finish non-standard type stacks.
                 if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
                     stack.finishAllActivitiesImmediately();
@@ -1241,14 +1048,14 @@
                     final int windowingMode = toDisplay.hasSplitScreenPrimaryStack()
                             ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
                             : WINDOWING_MODE_UNDEFINED;
-                    stack.reparent(toDisplay.mDisplayContent, true /* onTop */);
+                    stack.reparent(toDisplay, true /* onTop */);
                     stack.setWindowingMode(windowingMode);
                     lastReparentedStack = stack;
                 }
                 // Stacks may be removed from this display. Ensure each stack will be processed and
                 // the loop will end.
-                stackNdx -= numStacks - getChildCount();
-                numStacks = getChildCount();
+                stackNdx -= numStacks - getStackCount();
+                numStacks = getStackCount();
             }
         } finally {
             mRootActivityContainer.mStackSupervisor.endDeferResume();
@@ -1265,24 +1072,23 @@
         if (!mAllSleepTokens.isEmpty()) {
             mRootActivityContainer.mSleepTokens.removeAll(mAllSleepTokens);
             mAllSleepTokens.clear();
-            mService.updateSleepIfNeededLocked();
+            mAtmService.updateSleepIfNeededLocked();
         }
     }
 
     private void releaseSelfIfNeeded() {
-        if (!mRemoved || mDisplayContent == null) {
+        if (!mRemoved) {
             return;
         }
 
-        final ActivityStack stack = getChildCount() == 1 ? getChildAt(0) : null;
+        final ActivityStack stack = getStackCount() == 1 ? getStackAt(0) : null;
         if (stack != null && stack.isActivityTypeHome() && stack.getAllTasks().isEmpty()) {
             // Release this display if an empty home stack is the only thing left.
             // Since it is the last stack, this display will be released along with the stack
             // removal.
             stack.removeIfPossible();
-        } else if (mStacks.isEmpty()) {
-            mDisplayContent.removeIfPossible();
-            mDisplayContent = null;
+        } else if (getTopStack() == null) {
+            removeIfPossible();
             mRootActivityContainer.removeChild(this);
             mRootActivityContainer.mStackSupervisor
                     .getKeyguardController().onDisplayRemoved(mDisplayId);
@@ -1292,19 +1098,15 @@
     /** Update and get all UIDs that are present on the display and have access to it. */
     IntArray getPresentUIDs() {
         mDisplayAccessUIDs.clear();
-        for (ActivityStack stack : mStacks) {
-            stack.getPresentUIDs(mDisplayAccessUIDs);
-        }
+        final PooledConsumer c = PooledLambda.obtainConsumer(ActivityDisplay::addActivityUid,
+                PooledLambda.__(ActivityRecord.class), mDisplayAccessUIDs);
+        mDisplayContent.forAllActivities(c);
+        c.recycle();
         return mDisplayAccessUIDs;
     }
 
-    /**
-     * Checks if system decorations should be shown on this display.
-     *
-     * @see Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
-     */
-    boolean supportsSystemDecorations() {
-        return mDisplayContent.supportsSystemDecorations();
+    private static void addActivityUid(ActivityRecord r, IntArray uids) {
+        uids.add(r.getUid());
     }
 
     @VisibleForTesting
@@ -1313,14 +1115,11 @@
     }
 
     boolean shouldSleep() {
-        return (mStacks.isEmpty() || !mAllSleepTokens.isEmpty())
-                && (mService.mRunningVoice == null);
+        return (getStackCount() == 0 || !mAllSleepTokens.isEmpty())
+                && (mAtmService.mRunningVoice == null);
     }
 
     void setFocusedApp(ActivityRecord r, boolean moveFocusNow) {
-        if (mDisplayContent == null) {
-            return;
-        }
         final ActivityRecord newFocus;
         final IBinder token = r.appToken;
         if (token == null) {
@@ -1328,7 +1127,7 @@
                     mDisplayId);
             newFocus = null;
         } else {
-            newFocus = mService.mWindowManager.mRoot.getActivityRecord(token);
+            newFocus = mWmService.mRoot.getActivityRecord(token);
             if (newFocus == null) {
                 Slog.w(TAG_WM, "Attempted to set focus to non-existing app token: " + token
                         + ", displayId=" + mDisplayId);
@@ -1338,9 +1137,9 @@
                             moveFocusNow, mDisplayId);
         }
 
-        final boolean changed = mDisplayContent.setFocusedApp(newFocus);
+        final boolean changed = setFocusedApp(newFocus);
         if (moveFocusNow && changed) {
-            mService.mWindowManager.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
+            mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
                     true /*updateInputWindows*/);
         }
     }
@@ -1350,8 +1149,8 @@
      *         already top-most.
      */
     ActivityStack getStackAbove(ActivityStack stack) {
-        final int stackIndex = mStacks.indexOf(stack) + 1;
-        return (stackIndex < getChildCount()) ? getChildAt(stackIndex) : null;
+        final int stackIndex = getIndexOf(stack) + 1;
+        return (stackIndex < getStackCount()) ? getStackAt(stackIndex) : null;
     }
 
     /**
@@ -1365,12 +1164,12 @@
         }
 
         // Move the stack to the bottom to not affect the following visibility checks
-        positionChildAtBottom(stack);
+        positionStackAtBottom(stack);
 
         // Find the next position where the stack should be placed
-        final int numStacks = getChildCount();
+        final int numStacks = getStackCount();
         for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
-            final ActivityStack s = getChildAt(stackNdx);
+            final ActivityStack s = getStackAt(stackNdx);
             if (s == stack) {
                 continue;
             }
@@ -1379,7 +1178,7 @@
                     winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
             if (s.shouldBeVisible(null) && isValidWindowingMode) {
                 // Move the provided stack to behind this stack
-                positionChildAt(stack, Math.max(0, stackNdx - 1));
+                positionStackAt(stack, Math.max(0, stackNdx - 1));
                 break;
             }
         }
@@ -1399,25 +1198,26 @@
         // list, so we need to adjust the insertion index to account for the removed index
         // TODO: Remove this logic when WindowContainer.positionChildAt() is updated to adjust the
         //       position internally
-        final int stackIndex = mStacks.indexOf(stack);
-        final int behindStackIndex = mStacks.indexOf(behindStack);
+        final int stackIndex = getIndexOf(stack);
+        final int behindStackIndex = getIndexOf(behindStack);
         final int insertIndex = stackIndex <= behindStackIndex
                 ? behindStackIndex - 1 : behindStackIndex;
-        positionChildAt(stack, Math.max(0, insertIndex));
+        positionStackAt(stack, Math.max(0, insertIndex));
     }
 
     void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
             boolean preserveWindows, boolean notifyClients) {
-        for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = getChildAt(stackNdx);
+        for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = getStackAt(stackNdx);
             stack.ensureActivitiesVisible(starting, configChanges, preserveWindows,
                     notifyClients);
         }
     }
 
     void moveHomeStackToFront(String reason) {
-        if (mHomeStack != null) {
-            mHomeStack.moveToFront(reason);
+        final ActivityStack homeStack = getHomeStack();
+        if (homeStack != null) {
+            homeStack.moveToFront(reason);
         }
     }
 
@@ -1435,37 +1235,27 @@
     }
 
     @Nullable
-    ActivityStack getHomeStack() {
-        return mHomeStack;
-    }
-
-    @Nullable
     ActivityRecord getHomeActivity() {
         return getHomeActivityForUser(mRootActivityContainer.mCurrentUser);
     }
 
     @Nullable
     ActivityRecord getHomeActivityForUser(int userId) {
-        if (mHomeStack == null) {
+        final ActivityStack homeStack = getHomeStack();
+        if (homeStack == null) {
             return null;
         }
 
-        final ArrayList<Task> tasks = mHomeStack.getAllTasks();
-        for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = tasks.get(taskNdx);
-            if (!task.isActivityTypeHome()) {
-                continue;
-            }
+        final PooledPredicate p = PooledLambda.obtainPredicate(
+                ActivityDisplay::isHomeActivityForUser, PooledLambda.__(ActivityRecord.class),
+                userId);
+        final ActivityRecord r = homeStack.getActivity(p);
+        p.recycle();
+        return r;
+    }
 
-            for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = task.getChildAt(activityNdx);
-                if (r.isActivityTypeHome()
-                        && ((userId == UserHandle.USER_ALL) || (r.mUserId == userId))) {
-                    return r;
-                }
-            }
-        }
-        return null;
+    private static boolean isHomeActivityForUser(ActivityRecord r, int userId) {
+        return r.isActivityTypeHome() && (userId == UserHandle.USER_ALL || r.mUserId == userId);
     }
 
     boolean isSleeping() {
@@ -1504,32 +1294,14 @@
         }
     }
 
-    /**
-     * See {@link DisplayContent#deferUpdateImeTarget()}
-     */
-    public void deferUpdateImeTarget() {
-        if (mDisplayContent != null) {
-            mDisplayContent.deferUpdateImeTarget();
-        }
-    }
-
-    /**
-     * See {@link DisplayContent#deferUpdateImeTarget()}
-     */
-    public void continueUpdateImeTarget() {
-        if (mDisplayContent != null) {
-            mDisplayContent.continueUpdateImeTarget();
-        }
-    }
-
     void setDisplayToSingleTaskInstance() {
-        final int childCount = getChildCount();
+        final int childCount = getStackCount();
         if (childCount > 1) {
             throw new IllegalArgumentException("Display already has multiple stacks. display="
                     + this);
         }
         if (childCount > 0) {
-            final ActivityStack stack = getChildAt(0);
+            final ActivityStack stack = getStackAt(0);
             if (stack.getChildCount() > 1) {
                 throw new IllegalArgumentException("Display stack already has multiple tasks."
                         + " display=" + this + " stack=" + stack);
@@ -1546,8 +1318,8 @@
 
     @VisibleForTesting
     void removeAllTasks() {
-        for (int i = getChildCount() - 1; i >= 0; --i) {
-            final ActivityStack stack = getChildAt(i);
+        for (int i = getStackCount() - 1; i >= 0; --i) {
+            final ActivityStack stack = getStackAt(i);
             final ArrayList<Task> tasks = stack.getAllTasks();
             for (int j = tasks.size() - 1; j >= 0; --j) {
                 stack.removeChild(tasks.get(j), "removeAllTasks");
@@ -1556,20 +1328,24 @@
     }
 
     public void dump(PrintWriter pw, String prefix) {
-        pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + getChildCount()
+        pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + getStackCount()
                 + (mSingleTaskInstance ? " mSingleTaskInstance" : ""));
         final String myPrefix = prefix + " ";
-        if (mHomeStack != null) {
-            pw.println(myPrefix + "mHomeStack=" + mHomeStack);
+        ActivityStack stack = getHomeStack();
+        if (stack != null) {
+            pw.println(myPrefix + "mHomeStack=" + stack);
         }
-        if (mRecentsStack != null) {
-            pw.println(myPrefix + "mRecentsStack=" + mRecentsStack);
+        stack = getRecentsStack();
+        if (stack != null) {
+            pw.println(myPrefix + "mRecentsStack=" + stack);
         }
-        if (mPinnedStack != null) {
-            pw.println(myPrefix + "mPinnedStack=" + mPinnedStack);
+        stack = getPinnedStack();
+        if (stack != null) {
+            pw.println(myPrefix + "mPinnedStack=" + stack);
         }
-        if (mSplitScreenPrimaryStack != null) {
-            pw.println(myPrefix + "mSplitScreenPrimaryStack=" + mSplitScreenPrimaryStack);
+        stack = getSplitScreenPrimaryStack();
+        if (stack != null) {
+            pw.println(myPrefix + "mSplitScreenPrimaryStack=" + stack);
         }
         if (mPreferredTopFocusableStack != null) {
             pw.println(myPrefix + "mPreferredTopFocusableStack=" + mPreferredTopFocusableStack);
@@ -1580,18 +1356,18 @@
     }
 
     public void dumpStacks(PrintWriter pw) {
-        for (int i = getChildCount() - 1; i >= 0; --i) {
-            pw.print(getChildAt(i).mStackId);
+        for (int i = getStackCount() - 1; i >= 0; --i) {
+            pw.print(getStackAt(i).mStackId);
             if (i > 0) {
                 pw.print(",");
             }
         }
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId,
+    public void dumpDebug(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
         final long token = proto.start(fieldId);
-        super.writeToProto(proto, CONFIGURATION_CONTAINER, logLevel);
+        dumpDebugInner(proto, DISPLAY, logLevel);
         proto.write(ID, mDisplayId);
         proto.write(SINGLE_TASK_INSTANCE, mSingleTaskInstance);
         final ActivityStack focusedStack = getFocusedStack();
@@ -1604,9 +1380,9 @@
         } else {
             proto.write(FOCUSED_STACK_ID, INVALID_STACK_ID);
         }
-        for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = getChildAt(stackNdx);
-            stack.writeToProto(proto, STACKS, logLevel);
+        for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = getStackAt(stackNdx);
+            stack.dumpDebug(proto, STACKS, logLevel);
         }
         proto.end(token);
     }
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 0a861ad..20d1d1c 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -56,33 +56,32 @@
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_WARM_LAUNCH;
-import static com.android.server.am.EventLogTags.AM_ACTIVITY_LAUNCH_TIME;
 import static com.android.server.am.MemoryStatUtil.MemoryStat;
 import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_METRICS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_TIMEOUT;
+import static com.android.server.wm.EventLogTags.WM_ACTIVITY_LAUNCH_TIME;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.WaitResult;
 import android.app.WindowConfiguration.WindowingMode;
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.dex.ArtManagerInternal;
 import android.content.pm.dex.PackageOptimizationInfo;
 import android.metrics.LogMaker;
-import android.os.Handler;
+import android.os.Binder;
 import android.os.Looper;
-import android.os.Message;
 import android.os.SystemClock;
 import android.os.Trace;
+import android.util.ArrayMap;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
 import android.util.StatsLog;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
@@ -90,16 +89,23 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.os.BackgroundThread;
-import com.android.internal.os.SomeArgs;
+import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.LocalServices;
 
+import java.util.ArrayList;
+import java.util.LinkedList;
 import java.util.concurrent.TimeUnit;
 
 /**
  * Listens to activity launches, transitions, visibility changes and window drawn callbacks to
  * determine app launch times and draw delays. Source of truth for activity metrics and provides
  * data for Tron, logcat, event logs and {@link android.app.WaitResult}.
- *
+ * <p>
+ * A typical sequence of a launch event could be:
+ * {@link #notifyActivityLaunching}, {@link #notifyActivityLaunched},
+ * {@link #notifyStartingWindowDrawn} (optional), {@link #notifyTransitionStarting}
+ * {@link #notifyWindowsDrawn}.
+ * <p>
  * Tests:
  * atest CtsWindowManagerDeviceTestCases:ActivityMetricsLoggerTests
  */
@@ -115,12 +121,14 @@
     private static final int WINDOW_STATE_ASSISTANT = 3;
     private static final int WINDOW_STATE_INVALID = -1;
 
-    private static final long INVALID_START_TIME = -1;
+    /**
+     * The flag for {@link #notifyActivityLaunching} to skip associating a new launch with an active
+     * transition, in the case the launch is standalone (e.g. from recents).
+     */
+    private static final int IGNORE_CALLER = -1;
     private static final int INVALID_DELAY = -1;
     private static final int INVALID_TRANSITION_TYPE = -1;
 
-    private static final int MSG_CHECK_VISIBILITY = 0;
-
     // Preallocated strings we are sending to tron, so we don't have to allocate a new one every
     // time we log.
     private static final String[] TRON_WINDOW_STATE_VARZ_STRINGS = {
@@ -129,27 +137,12 @@
     private int mWindowState = WINDOW_STATE_STANDARD;
     private long mLastLogTimeSecs;
     private final ActivityStackSupervisor mSupervisor;
-    private final Context mContext;
     private final MetricsLogger mMetricsLogger = new MetricsLogger();
 
-    // set to INVALID_START_TIME in reset.
-    // set to valid value in notifyActivityLaunching
-    private long mCurrentTransitionStartTimeNs = INVALID_START_TIME;
-    private long mLastTransitionStartTimeNs = INVALID_START_TIME;
-
-    private int mCurrentTransitionDeviceUptime;
-    private int mCurrentTransitionDelayMs;
-
-    /** If the any app transitions have been logged as starting, after the latest reset. */
-    private boolean mLoggedTransitionStarting;
-
-    /** Map : @WindowingMode int => WindowingModeTransitionInfo */
-    private final SparseArray<WindowingModeTransitionInfo> mWindowingModeTransitionInfo =
-            new SparseArray<>();
-    /** Map : @WindowingMode int => WindowingModeTransitionInfo */
-    private final SparseArray<WindowingModeTransitionInfo> mLastWindowingModeTransitionInfo =
-            new SparseArray<>();
-    private final H mHandler;
+    /** All active transitions. */
+    private final ArrayList<TransitionInfo> mTransitionInfoList = new ArrayList<>();
+    /** Map : Last launched activity => {@link TransitionInfo} */
+    private final ArrayMap<ActivityRecord, TransitionInfo> mLastTransitionInfo = new ArrayMap<>();
 
     private ArtManagerInternal mArtManagerInternal;
     private final StringBuilder mStringBuilder = new StringBuilder();
@@ -161,54 +154,151 @@
     private final LaunchObserverRegistryImpl mLaunchObserver;
     @VisibleForTesting static final int LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE = 512;
 
-    private final class H extends Handler {
+    /**
+     * The information created when an intent is incoming but we do not yet know whether it will be
+     * launched successfully.
+     */
+    static final class LaunchingState {
+        /** The timestamp of {@link #notifyActivityLaunching}. */
+        private long mCurrentTransitionStartTimeNs;
+        /** Non-null when a {@link TransitionInfo} is created for this state. */
+        private TransitionInfo mAssociatedTransitionInfo;
 
-        public H(Looper looper) {
-            super(looper);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_CHECK_VISIBILITY:
-                    final SomeArgs args = (SomeArgs) msg.obj;
-                    checkVisibility((Task) args.arg1, (ActivityRecord) args.arg2);
-                    break;
-            }
+        @VisibleForTesting
+        boolean allDrawn() {
+            return mAssociatedTransitionInfo != null && mAssociatedTransitionInfo.allDrawn();
         }
     }
 
-    private final class WindowingModeTransitionInfo {
+    /** The information created when an activity is confirmed to be launched. */
+    private static final class TransitionInfo {
+        /**
+         * The field to lookup and update an existing transition efficiently between
+         * {@link #notifyActivityLaunching} and {@link #notifyActivityLaunched}.
+         *
+         * @see LaunchingState#mAssociatedTransitionInfo
+         */
+        final LaunchingState mLaunchingState;
+        /**
+         * The timestamp of the first {@link #notifyActivityLaunching}. It can be used as a key for
+         * observer to identify which callbacks belong to a launch event.
+         */
+        final long mTransitionStartTimeNs;
+        /** The device uptime in seconds when this transition info is created. */
+        final int mCurrentTransitionDeviceUptime;
+        /** The type can be cold (new process), warm (new activity), or hot (bring to front). */
+        final int mTransitionType;
+        /** Whether the process was already running when the transition started. */
+        final boolean mProcessRunning;
+        /** The activities that should be drawn. */
+        final LinkedList<ActivityRecord> mPendingDrawActivities = new LinkedList<>();
         /** The latest activity to have been launched. */
-        private ActivityRecord launchedActivity;
-        private int startResult;
-        private boolean currentTransitionProcessRunning;
+        @NonNull ActivityRecord mLastLaunchedActivity;
+
+        /** The time from {@link #mTransitionStartTimeNs} to {@link #notifyTransitionStarting}. */
+        int mCurrentTransitionDelayMs;
+        /** The time from {@link #mTransitionStartTimeNs} to {@link #notifyStartingWindowDrawn}. */
+        int mStartingWindowDelayMs = INVALID_DELAY;
+        /** The time from {@link #mTransitionStartTimeNs} to {@link #notifyBindApplication}. */
+        int mBindApplicationDelayMs = INVALID_DELAY;
         /** Elapsed time from when we launch an activity to when its windows are drawn. */
-        private int windowsDrawnDelayMs;
-        private int startingWindowDelayMs = INVALID_DELAY;
-        private int bindApplicationDelayMs = INVALID_DELAY;
-        private int reason = APP_TRANSITION_TIMEOUT;
-        // TODO(b/132736359) The number may need to consider the visibility change.
-        private int numUndrawnActivities = 1;
+        int mWindowsDrawnDelayMs;
+        /** The reason why the transition started (see ActivityManagerInternal.APP_TRANSITION_*). */
+        int mReason = APP_TRANSITION_TIMEOUT;
+        /** The flag ensures that {@link #mStartingWindowDelayMs} is only set once. */
+        boolean mLoggedStartingWindowDrawn;
+        /** If the any app transitions have been logged as starting. */
+        boolean mLoggedTransitionStarting;
+
         /** Non-null if the application has reported drawn but its window hasn't. */
-        private Runnable pendingFullyDrawn;
-        private boolean loggedStartingWindowDrawn;
-        private boolean launchTraceActive;
+        @Nullable Runnable mPendingFullyDrawn;
+        /** Non-null if the trace is active. */
+        @Nullable String mLaunchTraceName;
+
+        /** @return Non-null if there will be a window drawn event for the launch. */
+        @Nullable
+        static TransitionInfo create(@NonNull ActivityRecord r,
+                @NonNull LaunchingState launchingState, boolean processRunning, int startResult) {
+            int transitionType = INVALID_TRANSITION_TYPE;
+            if (processRunning) {
+                if (startResult == START_SUCCESS) {
+                    transitionType = TYPE_TRANSITION_WARM_LAUNCH;
+                } else if (startResult == START_TASK_TO_FRONT) {
+                    transitionType = TYPE_TRANSITION_HOT_LAUNCH;
+                }
+            } else if (startResult == START_SUCCESS || startResult == START_TASK_TO_FRONT) {
+                // Task may still exist when cold launching an activity and the start result will be
+                // set to START_TASK_TO_FRONT. Treat this as a COLD launch.
+                transitionType = TYPE_TRANSITION_COLD_LAUNCH;
+            }
+            if (transitionType == INVALID_TRANSITION_TYPE) {
+                // That means the startResult is neither START_SUCCESS nor START_TASK_TO_FRONT.
+                return null;
+            }
+            return new TransitionInfo(r, launchingState, transitionType, processRunning);
+        }
+
+        /** Use {@link TransitionInfo#create} instead to ensure the transition type is valid. */
+        private TransitionInfo(ActivityRecord r, LaunchingState launchingState, int transitionType,
+                boolean processRunning) {
+            mLaunchingState = launchingState;
+            mTransitionStartTimeNs = launchingState.mCurrentTransitionStartTimeNs;
+            mTransitionType = transitionType;
+            mProcessRunning = processRunning;
+            mCurrentTransitionDeviceUptime =
+                    (int) TimeUnit.MILLISECONDS.toSeconds(SystemClock.uptimeMillis());
+            setLatestLaunchedActivity(r);
+            launchingState.mAssociatedTransitionInfo = this;
+        }
 
         /**
          * Remembers the latest launched activity to represent the final transition. This also
-         * increments the number of activities that should be drawn, so a consecutive launching
-         * sequence can be coalesced as one event.
+         * tracks the activities that should be drawn, so a consecutive launching sequence can be
+         * coalesced as one event.
          */
         void setLatestLaunchedActivity(ActivityRecord r) {
-            if (launchedActivity == r) {
+            if (mLastLaunchedActivity == r) {
                 return;
             }
-            launchedActivity = r;
+            mLastLaunchedActivity = r;
+            if (!r.noDisplay) {
+                if (DEBUG_METRICS) Slog.i(TAG, "Add pending draw " + r);
+                mPendingDrawActivities.add(r);
+            }
+        }
+
+        /** @return {@code true} if the activity matches a launched activity in this transition. */
+        boolean contains(ActivityRecord r) {
+            return r == mLastLaunchedActivity || mPendingDrawActivities.contains(r);
+        }
+
+        /** Called when the activity is drawn or won't be drawn. */
+        void removePendingDrawActivity(ActivityRecord r) {
+            if (DEBUG_METRICS) Slog.i(TAG, "Remove pending draw " + r);
+            mPendingDrawActivities.remove(r);
+        }
+
+        boolean allDrawn() {
+            return mPendingDrawActivities.isEmpty();
+        }
+
+        int calculateCurrentDelay() {
+            return calculateDelay(SystemClock.elapsedRealtimeNanos());
+        }
+
+        int calculateDelay(long timestampNs) {
+            // Shouldn't take more than 25 days to launch an app, so int is fine here.
+            return (int) TimeUnit.NANOSECONDS.toMillis(timestampNs - mTransitionStartTimeNs);
+        }
+
+        @Override
+        public String toString() {
+            return "TransitionInfo{" + Integer.toHexString(System.identityHashCode(this))
+                    + " a=" + mLastLaunchedActivity + " ua=" + mPendingDrawActivities + "}";
         }
     }
 
-    final class WindowingModeTransitionInfoSnapshot {
+    static final class TransitionInfoSnapshot {
         final private ApplicationInfo applicationInfo;
         final private WindowProcessController processRecord;
         final String packageName;
@@ -231,17 +321,12 @@
         final int windowsFullyDrawnDelayMs;
         final int activityRecordIdHashCode;
 
-        private WindowingModeTransitionInfoSnapshot(WindowingModeTransitionInfo info) {
-            this(info, info.launchedActivity);
+        private TransitionInfoSnapshot(TransitionInfo info) {
+            this(info, info.mLastLaunchedActivity, INVALID_DELAY);
         }
 
-        private WindowingModeTransitionInfoSnapshot(WindowingModeTransitionInfo info,
-                ActivityRecord launchedActivity) {
-            this(info, launchedActivity, INVALID_DELAY);
-        }
-
-        private WindowingModeTransitionInfoSnapshot(WindowingModeTransitionInfo info,
-                ActivityRecord launchedActivity, int windowsFullyDrawnDelayMs) {
+        private TransitionInfoSnapshot(TransitionInfo info, ActivityRecord launchedActivity,
+                int windowsFullyDrawnDelayMs) {
             applicationInfo = launchedActivity.info.applicationInfo;
             packageName = launchedActivity.packageName;
             launchedActivityName = launchedActivity.info.name;
@@ -250,12 +335,12 @@
             launchedActivityAppRecordRequiredAbi = launchedActivity.app == null
                     ? null
                     : launchedActivity.app.getRequiredAbi();
-            reason = info.reason;
-            startingWindowDelayMs = info.startingWindowDelayMs;
-            bindApplicationDelayMs = info.bindApplicationDelayMs;
-            windowsDrawnDelayMs = info.windowsDrawnDelayMs;
-            type = getTransitionType(info);
-            processRecord = findProcessForActivity(launchedActivity);
+            reason = info.mReason;
+            startingWindowDelayMs = info.mStartingWindowDelayMs;
+            bindApplicationDelayMs = info.mBindApplicationDelayMs;
+            windowsDrawnDelayMs = info.mWindowsDrawnDelayMs;
+            type = info.mTransitionType;
+            processRecord = launchedActivity.app;
             processName = launchedActivity.processName;
             userId = launchedActivity.mUserId;
             launchedActivityShortComponentName = launchedActivity.shortComponentName;
@@ -277,11 +362,9 @@
         }
     }
 
-    ActivityMetricsLogger(ActivityStackSupervisor supervisor, Context context, Looper looper) {
+    ActivityMetricsLogger(ActivityStackSupervisor supervisor, Looper looper) {
         mLastLogTimeSecs = SystemClock.elapsedRealtime() / 1000;
         mSupervisor = supervisor;
-        mContext = context;
-        mHandler = new H(looper);
         mLaunchObserver = new LaunchObserverRegistryImpl(looper);
     }
 
@@ -291,7 +374,7 @@
             // We log even if the window state hasn't changed, because the user might remain in
             // home/fullscreen move forever and we would like to track this kind of behavior
             // too.
-            MetricsLogger.count(mContext, TRON_WINDOW_STATE_VARZ_STRINGS[mWindowState],
+            mMetricsLogger.count(TRON_WINDOW_STATE_VARZ_STRINGS[mWindowState],
                     (int) (now - mLastLogTimeSecs));
         }
         mLastLogTimeSecs = now;
@@ -332,145 +415,169 @@
         }
     }
 
+    /** @return Non-null {@link TransitionInfo} if the activity is found in an active transition. */
+    @Nullable
+    private TransitionInfo getActiveTransitionInfo(ActivityRecord r) {
+        for (int i = mTransitionInfoList.size() - 1; i >= 0; i--) {
+            final TransitionInfo info = mTransitionInfoList.get(i);
+            if (info.contains(r)) {
+                return info;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * This method should be only used by starting recents and starting from recents, or internal
+     * tests. Because it doesn't lookup caller and always creates a new launching state.
+     *
+     * @see #notifyActivityLaunching(Intent, ActivityRecord, int)
+     */
+    LaunchingState notifyActivityLaunching(Intent intent) {
+        return notifyActivityLaunching(intent, null /* caller */, IGNORE_CALLER);
+    }
+
+    /**
+     * If the caller is found in an active transition, it will be considered as consecutive launch
+     * and coalesced into the active transition.
+     *
+     * @see #notifyActivityLaunching(Intent, ActivityRecord, int)
+     */
+    LaunchingState notifyActivityLaunching(Intent intent, @Nullable ActivityRecord caller) {
+        return notifyActivityLaunching(intent, caller, Binder.getCallingUid());
+    }
+
     /**
      * Notifies the tracker at the earliest possible point when we are starting to launch an
-     * activity.
+     * activity. The caller must ensure that {@link #notifyActivityLaunched} will be called later
+     * with the returned {@link LaunchingState}.
      */
-    void notifyActivityLaunching(Intent intent) {
+    private LaunchingState notifyActivityLaunching(Intent intent, @Nullable ActivityRecord caller,
+            int callingUid) {
+        final long transitionStartTimeNs = SystemClock.elapsedRealtimeNanos();
+        TransitionInfo existingInfo = null;
+        if (callingUid != IGNORE_CALLER) {
+            // Associate the launching event to an active transition if the caller is found in its
+            // launched activities.
+            for (int i = mTransitionInfoList.size() - 1; i >= 0; i--) {
+                final TransitionInfo info = mTransitionInfoList.get(i);
+                if (caller != null && info.contains(caller)) {
+                    existingInfo = info;
+                    break;
+                }
+                if (existingInfo == null && callingUid == info.mLastLaunchedActivity.getUid()) {
+                    // Fallback to check the most recent matched uid for the case that the caller is
+                    // not an activity.
+                    existingInfo = info;
+                }
+            }
+        }
         if (DEBUG_METRICS) {
-            Slog.i(TAG, String.format("notifyActivityLaunching: active:%b, intent:%s",
-                                      isAnyTransitionActive(),
-                                      intent));
+            Slog.i(TAG, "notifyActivityLaunching intent=" + intent
+                    + " existingInfo=" + existingInfo);
         }
 
-        if (mCurrentTransitionStartTimeNs == INVALID_START_TIME) {
-
-            mCurrentTransitionStartTimeNs = SystemClock.elapsedRealtimeNanos();
-            mLastTransitionStartTimeNs = mCurrentTransitionStartTimeNs;
-
-            launchObserverNotifyIntentStarted(intent, mCurrentTransitionStartTimeNs);
+        if (existingInfo == null) {
+            // Only notify the observer for a new launching event.
+            launchObserverNotifyIntentStarted(intent, transitionStartTimeNs);
+            final LaunchingState launchingState = new LaunchingState();
+            launchingState.mCurrentTransitionStartTimeNs = transitionStartTimeNs;
+            return launchingState;
         }
+        existingInfo.mLaunchingState.mCurrentTransitionStartTimeNs = transitionStartTimeNs;
+        return existingInfo.mLaunchingState;
     }
 
     /**
      * Notifies the tracker that the activity is actually launching.
      *
-     * @param resultCode one of the ActivityManager.START_* flags, indicating the result of the
-     *                   launch
-     * @param launchedActivity the activity that is being launched
+     * @param launchingState The launching state to track the new or active transition.
+     * @param resultCode One of the {@link android.app.ActivityManager}.START_* flags, indicating
+     *                   the result of the launch.
+     * @param launchedActivity The activity that is being launched
      */
-    void notifyActivityLaunched(int resultCode, ActivityRecord launchedActivity) {
-        final WindowProcessController processRecord = findProcessForActivity(launchedActivity);
-        final boolean processRunning = processRecord != null;
+    void notifyActivityLaunched(@NonNull LaunchingState launchingState, int resultCode,
+            @Nullable ActivityRecord launchedActivity) {
+        if (launchedActivity == null) {
+            // The launch is aborted, e.g. intent not resolved, class not found.
+            abort(null /* info */, "nothing launched");
+            return;
+        }
 
+        final WindowProcessController processRecord = launchedActivity.app != null
+                ? launchedActivity.app
+                : mSupervisor.mService.getProcessController(
+                        launchedActivity.processName, launchedActivity.info.applicationInfo.uid);
+        // Whether the process that will contains the activity is already running.
+        final boolean processRunning = processRecord != null;
         // We consider this a "process switch" if the process of the activity that gets launched
         // didn't have an activity that was in started state. In this case, we assume that lot
         // of caches might be purged so the time until it produces the first frame is very
         // interesting.
-        final boolean processSwitch = processRecord == null
+        final boolean processSwitch = !processRunning
                 || !processRecord.hasStartedActivity(launchedActivity);
 
-        notifyActivityLaunched(resultCode, launchedActivity, processRunning, processSwitch);
-    }
-
-    /**
-     * Notifies the tracker the the activity is actually launching.
-     *
-     * @param resultCode one of the ActivityManager.START_* flags, indicating the result of the
-     *                   launch
-     * @param launchedActivity the activity being launched
-     * @param processRunning whether the process that will contains the activity is already running
-     * @param processSwitch whether the process that will contain the activity didn't have any
-     *                      activity that was stopped, i.e. the started activity is "switching"
-     *                      processes
-     */
-    private void notifyActivityLaunched(int resultCode, ActivityRecord launchedActivity,
-            boolean processRunning, boolean processSwitch) {
-
-        if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched"
-                + " resultCode=" + resultCode
-                + " launchedActivity=" + launchedActivity
-                + " processRunning=" + processRunning
-                + " processSwitch=" + processSwitch);
-
-        // If we are already in an existing transition, only update the activity name, but not the
-        // other attributes.
-        final @WindowingMode int windowingMode = launchedActivity != null
-                ? launchedActivity.getWindowingMode()
-                : WINDOWING_MODE_UNDEFINED;
-        final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
-        if (mCurrentTransitionStartTimeNs == INVALID_START_TIME) {
-            // No transition is active ignore this launch.
-            return;
+        final TransitionInfo info = launchingState.mAssociatedTransitionInfo;
+        if (DEBUG_METRICS) {
+            Slog.i(TAG, "notifyActivityLaunched" + " resultCode=" + resultCode
+                    + " launchedActivity=" + launchedActivity + " processRunning=" + processRunning
+                    + " processSwitch=" + processSwitch + " info=" + info);
         }
 
-        if (launchedActivity != null && launchedActivity.mDrawn) {
+        if (launchedActivity.mDrawn) {
             // Launched activity is already visible. We cannot measure windows drawn delay.
             abort(info, "launched activity already visible");
             return;
         }
 
-        if (launchedActivity != null && info != null) {
+        if (info != null) {
             // If we are already in an existing transition, only update the activity name, but not
             // the other attributes.
 
+            if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched update launched activity");
             // Coalesce multiple (trampoline) activities from a single sequence together.
             info.setLatestLaunchedActivity(launchedActivity);
             return;
         }
 
-        final boolean otherWindowModesLaunching =
-                mWindowingModeTransitionInfo.size() > 0 && info == null;
-        if ((!isLoggableResultCode(resultCode) || launchedActivity == null || !processSwitch
-                || windowingMode == WINDOWING_MODE_UNDEFINED) && !otherWindowModesLaunching) {
-            // Failed to launch or it was not a process switch, so we don't care about the timing.
-            abort(info, "failed to launch or not a process switch");
+        if (!processSwitch) {
+            abort(info, "not a process switch");
             return;
-        } else if (otherWindowModesLaunching) {
-            // Don't log this windowing mode but continue with the other windowing modes.
+        }
+
+        final TransitionInfo newInfo = TransitionInfo.create(launchedActivity, launchingState,
+                processRunning, resultCode);
+        if (newInfo == null) {
+            abort(info, "unrecognized launch");
             return;
         }
 
         if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched successful");
-
-        // A new launch sequence [with the windowingMode] has begun.
-        // Start tracking it.
-        final WindowingModeTransitionInfo newInfo = new WindowingModeTransitionInfo();
-        newInfo.setLatestLaunchedActivity(launchedActivity);
-        newInfo.currentTransitionProcessRunning = processRunning;
-        newInfo.startResult = resultCode;
-        mWindowingModeTransitionInfo.put(windowingMode, newInfo);
-        mLastWindowingModeTransitionInfo.put(windowingMode, newInfo);
-        mCurrentTransitionDeviceUptime = (int) (SystemClock.uptimeMillis() / 1000);
-        startTraces(newInfo);
+        // A new launch sequence has begun. Start tracking it.
+        mTransitionInfoList.add(newInfo);
+        mLastTransitionInfo.put(launchedActivity, newInfo);
+        startLaunchTrace(newInfo);
         launchObserverNotifyActivityLaunched(newInfo);
     }
 
     /**
-     * @return True if we should start logging an event for an activity start that returned
-     *         {@code resultCode} and that we'll indeed get a windows drawn event.
-     */
-    private boolean isLoggableResultCode(int resultCode) {
-        return resultCode == START_SUCCESS || resultCode == START_TASK_TO_FRONT;
-    }
-
-    /**
      * Notifies the tracker that all windows of the app have been drawn.
      */
-    WindowingModeTransitionInfoSnapshot notifyWindowsDrawn(@WindowingMode int windowingMode,
-                                                           long timestampNs) {
-        if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn windowingMode=" + windowingMode);
+    @Nullable
+    TransitionInfoSnapshot notifyWindowsDrawn(@NonNull ActivityRecord r, long timestampNs) {
+        if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn " + r);
 
-        final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
-        if (info == null || info.numUndrawnActivities == 0) {
+        final TransitionInfo info = getActiveTransitionInfo(r);
+        if (info == null || info.allDrawn()) {
+            if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn no activity to be drawn");
             return null;
         }
-        info.windowsDrawnDelayMs = calculateDelay(timestampNs);
-        info.numUndrawnActivities--;
-        final WindowingModeTransitionInfoSnapshot infoSnapshot =
-                new WindowingModeTransitionInfoSnapshot(info);
-        if (allWindowsDrawn() && mLoggedTransitionStarting) {
-            reset(false /* abort */, info, "notifyWindowsDrawn - all windows drawn", timestampNs);
+        // Always calculate the delay because the caller may need to know the individual drawn time.
+        info.mWindowsDrawnDelayMs = info.calculateDelay(timestampNs);
+        info.removePendingDrawActivity(r);
+        final TransitionInfoSnapshot infoSnapshot = new TransitionInfoSnapshot(info);
+        if (info.mLoggedTransitionStarting && info.allDrawn()) {
+            done(false /* abort */, info, "notifyWindowsDrawn - all windows drawn", timestampNs);
         }
         return infoSnapshot;
     }
@@ -478,88 +585,87 @@
     /**
      * Notifies the tracker that the starting window was drawn.
      */
-    void notifyStartingWindowDrawn(@WindowingMode int windowingMode, long timestampNs) {
-        final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
-        if (info == null || info.loggedStartingWindowDrawn) {
+    void notifyStartingWindowDrawn(@NonNull ActivityRecord r) {
+        final TransitionInfo info = getActiveTransitionInfo(r);
+        if (info == null || info.mLoggedStartingWindowDrawn) {
             return;
         }
-        info.loggedStartingWindowDrawn = true;
-        info.startingWindowDelayMs = calculateDelay(timestampNs);
+        if (DEBUG_METRICS) Slog.i(TAG, "notifyStartingWindowDrawn " + r);
+        info.mLoggedStartingWindowDrawn = true;
+        info.mStartingWindowDelayMs = info.calculateDelay(SystemClock.elapsedRealtimeNanos());
     }
 
     /**
      * Notifies the tracker that the app transition is starting.
      *
-     * @param windowingModeToReason A map from windowing mode to a reason integer, which must be on
-     *                              of ActivityTaskManagerInternal.APP_TRANSITION_* reasons.
+     * @param activityToReason A map from activity to a reason integer, which must be on of
+     *                         ActivityTaskManagerInternal.APP_TRANSITION_* reasons.
      */
-    void notifyTransitionStarting(SparseIntArray windowingModeToReason, long timestampNs) {
-        if (!isAnyTransitionActive() || mLoggedTransitionStarting) {
-            // Ignore calls to this made after a reset and prior to notifyActivityLaunching.
-
-            // Ignore any subsequent notifyTransitionStarting until the next reset.
-            return;
-        }
+    void notifyTransitionStarting(ArrayMap<ActivityRecord, Integer> activityToReason) {
         if (DEBUG_METRICS) Slog.i(TAG, "notifyTransitionStarting");
-        mCurrentTransitionDelayMs = calculateDelay(timestampNs);
-        mLoggedTransitionStarting = true;
 
-        WindowingModeTransitionInfo foundInfo = null;
-        for (int index = windowingModeToReason.size() - 1; index >= 0; index--) {
-            final @WindowingMode int windowingMode = windowingModeToReason.keyAt(index);
-            final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(
-                    windowingMode);
-            if (info == null) {
+        final long timestampNs = SystemClock.elapsedRealtimeNanos();
+        for (int index = activityToReason.size() - 1; index >= 0; index--) {
+            final ActivityRecord r = activityToReason.keyAt(index);
+            final TransitionInfo info = getActiveTransitionInfo(r);
+            if (info == null || info.mLoggedTransitionStarting) {
+                // Ignore any subsequent notifyTransitionStarting.
                 continue;
             }
-            info.reason = windowingModeToReason.valueAt(index);
-            foundInfo = info;
+            if (DEBUG_METRICS) {
+                Slog.i(TAG, "notifyTransitionStarting activity=" + r + " info=" + info);
+            }
+
+            info.mCurrentTransitionDelayMs = info.calculateDelay(timestampNs);
+            info.mReason = activityToReason.valueAt(index);
+            info.mLoggedTransitionStarting = true;
+            if (info.allDrawn()) {
+                done(false /* abort */, info, "notifyTransitionStarting - all windows drawn",
+                        timestampNs);
+            }
         }
-        if (allWindowsDrawn()) {
-            // abort metrics collection if we cannot find a matching transition.
-            final boolean abortMetrics = foundInfo == null;
-            reset(abortMetrics, foundInfo, "notifyTransitionStarting - all windows drawn",
-                timestampNs /* timestampNs */);
-        }
+    }
+
+    /** Makes sure that the reference to the removed activity is cleared. */
+    void notifyActivityRemoved(@NonNull ActivityRecord r) {
+        mLastTransitionInfo.remove(r);
     }
 
     /**
      * Notifies the tracker that the visibility of an app is changing.
      *
-     * @param activityRecord the app that is changing its visibility
+     * @param r the app that is changing its visibility
      */
-    void notifyVisibilityChanged(ActivityRecord activityRecord) {
-        final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(
-                activityRecord.getWindowingMode());
+    void notifyVisibilityChanged(@NonNull ActivityRecord r) {
+        final TransitionInfo info = getActiveTransitionInfo(r);
         if (info == null) {
             return;
         }
-        if (info.launchedActivity != activityRecord) {
+        if (DEBUG_METRICS) {
+            Slog.i(TAG, "notifyVisibilityChanged " + r + " visible=" + r.mVisibleRequested
+                    + " state=" + r.getState() + " finishing=" + r.finishing);
+        }
+        if (!r.mVisibleRequested || r.finishing) {
+            info.removePendingDrawActivity(r);
+        }
+        if (info.mLastLaunchedActivity != r) {
             return;
         }
-        final Task t = activityRecord.getTask();
-        final SomeArgs args = SomeArgs.obtain();
-        args.arg1 = t;
-        args.arg2 = activityRecord;
-        mHandler.obtainMessage(MSG_CHECK_VISIBILITY, args).sendToTarget();
+        // The activity and its task are passed separately because the activity may be removed from
+        // the task later.
+        r.mAtmService.mH.sendMessage(PooledLambda.obtainMessage(
+                ActivityMetricsLogger::checkVisibility, this, r.getTask(), r));
     }
 
     /** @return {@code true} if the given task has an activity will be drawn. */
     private static boolean hasActivityToBeDrawn(Task t) {
-        for (int i = t.getChildCount() - 1; i >= 0; --i) {
-            final ActivityRecord r = t.getChildAt(i);
-            if (r.mVisibleRequested && !r.mDrawn && !r.finishing) {
-                return true;
-            }
-        }
-        return false;
+        return t.forAllActivities((r) -> r.mVisibleRequested && !r.mDrawn && !r.finishing);
     }
 
     private void checkVisibility(Task t, ActivityRecord r) {
         synchronized (mSupervisor.mService.mGlobalLock) {
 
-            final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(
-                    r.getWindowingMode());
+            final TransitionInfo info = getActiveTransitionInfo(r);
 
             // If we have an active transition that's waiting on a certain activity that will be
             // invisible now, we'll never get onWindowsDrawn, so abort the transition if necessary.
@@ -571,7 +677,7 @@
 
             // The notified activity whose visibility changed is no longer the launched activity.
             // We can still wait to get onWindowsDrawn.
-            if (info.launchedActivity != r) {
+            if (info.mLastLaunchedActivity != r) {
                 return;
             }
 
@@ -585,11 +691,7 @@
 
             if (DEBUG_METRICS) Slog.i(TAG, "notifyVisibilityChanged to invisible activity=" + r);
             logAppTransitionCancel(info);
-            // Abort if this is the only one active transition.
-            if (mWindowingModeTransitionInfo.size() == 1
-                    && mWindowingModeTransitionInfo.get(r.getWindowingMode()) != null) {
-                abort(info, "notifyVisibilityChanged to invisible");
-            }
+            abort(info, "notifyVisibilityChanged to invisible");
         }
     }
 
@@ -599,137 +701,86 @@
      * @param appInfo The client into which we'll call bindApplication.
      */
     void notifyBindApplication(ApplicationInfo appInfo) {
-        for (int i = mWindowingModeTransitionInfo.size() - 1; i >= 0; i--) {
-            final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.valueAt(i);
+        for (int i = mTransitionInfoList.size() - 1; i >= 0; i--) {
+            final TransitionInfo info = mTransitionInfoList.get(i);
 
             // App isn't attached to record yet, so match with info.
-            if (info.launchedActivity.info.applicationInfo == appInfo) {
-                info.bindApplicationDelayMs = calculateCurrentDelay();
+            if (info.mLastLaunchedActivity.info.applicationInfo == appInfo) {
+                info.mBindApplicationDelayMs = info.calculateCurrentDelay();
             }
         }
     }
 
-    @VisibleForTesting
-    boolean allWindowsDrawn() {
-        for (int index = mWindowingModeTransitionInfo.size() - 1; index >= 0; index--) {
-            if (mWindowingModeTransitionInfo.valueAt(index).numUndrawnActivities != 0) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    private boolean isAnyTransitionActive() {
-        return mCurrentTransitionStartTimeNs != INVALID_START_TIME
-                && mWindowingModeTransitionInfo.size() > 0;
-    }
-
     /** Aborts tracking of current launch metrics. */
-    private void abort(WindowingModeTransitionInfo info, String cause) {
-        reset(true /* abort */, info, cause, 0L /* timestampNs */);
+    private void abort(TransitionInfo info, String cause) {
+        done(true /* abort */, info, cause, 0L /* timestampNs */);
     }
 
-    private void reset(boolean abort, WindowingModeTransitionInfo info, String cause,
+    /** Called when the given transition (info) is no longer active. */
+    private void done(boolean abort, @Nullable TransitionInfo info, String cause,
             long timestampNs) {
-        final boolean isAnyTransitionActive = isAnyTransitionActive();
         if (DEBUG_METRICS) {
-            Slog.i(TAG, "reset abort=" + abort + " cause=" + cause + " timestamp=" + timestampNs
-                    + " active=" + isAnyTransitionActive);
+            Slog.i(TAG, "done abort=" + abort + " cause=" + cause + " timestamp=" + timestampNs
+                    + " info=" + info);
         }
-        if (!abort && isAnyTransitionActive) {
-            logAppTransitionMultiEvents();
-        }
-        stopLaunchTrace(info);
-
-        // Ignore reset-after reset.
-        if (isAnyTransitionActive) {
-            // LaunchObserver callbacks.
-            if (abort) {
-                launchObserverNotifyActivityLaunchCancelled(info);
-            } else {
-                launchObserverNotifyActivityLaunchFinished(info, timestampNs);
-            }
-        } else {
+        if (info == null) {
             launchObserverNotifyIntentFailed();
-        }
-
-        mCurrentTransitionStartTimeNs = INVALID_START_TIME;
-        mCurrentTransitionDelayMs = INVALID_DELAY;
-        mLoggedTransitionStarting = false;
-        mWindowingModeTransitionInfo.clear();
-    }
-
-    private int calculateCurrentDelay() {
-        // Shouldn't take more than 25 days to launch an app, so int is fine here.
-        return (int) TimeUnit.NANOSECONDS
-            .toMillis(SystemClock.elapsedRealtimeNanos() - mCurrentTransitionStartTimeNs);
-    }
-
-    private int calculateDelay(long timestampNs) {
-        // Shouldn't take more than 25 days to launch an app, so int is fine here.
-        return (int) TimeUnit.NANOSECONDS.toMillis(timestampNs -
-            mCurrentTransitionStartTimeNs);
-    }
-
-    private void logAppTransitionCancel(WindowingModeTransitionInfo info) {
-        final int type = getTransitionType(info);
-        if (type == INVALID_TRANSITION_TYPE) {
             return;
         }
+
+        stopLaunchTrace(info);
+        if (abort) {
+            launchObserverNotifyActivityLaunchCancelled(info);
+        } else {
+            logAppTransitionFinished(info);
+            launchObserverNotifyActivityLaunchFinished(info, timestampNs);
+        }
+        info.mPendingDrawActivities.clear();
+        mTransitionInfoList.remove(info);
+    }
+
+    private void logAppTransitionCancel(TransitionInfo info) {
+        final int type = info.mTransitionType;
+        final ActivityRecord activity = info.mLastLaunchedActivity;
         final LogMaker builder = new LogMaker(APP_TRANSITION_CANCELLED);
-        builder.setPackageName(info.launchedActivity.packageName);
+        builder.setPackageName(activity.packageName);
         builder.setType(type);
-        builder.addTaggedData(FIELD_CLASS_NAME, info.launchedActivity.info.name);
+        builder.addTaggedData(FIELD_CLASS_NAME, activity.info.name);
         mMetricsLogger.write(builder);
         StatsLog.write(
                 StatsLog.APP_START_CANCELED,
-                info.launchedActivity.info.applicationInfo.uid,
-                info.launchedActivity.packageName,
+                activity.info.applicationInfo.uid,
+                activity.packageName,
                 convertAppStartTransitionType(type),
-                info.launchedActivity.info.name);
+                activity.info.name);
         if (DEBUG_METRICS) {
             Slog.i(TAG, String.format("APP_START_CANCELED(%s, %s, %s, %s)",
-                    info.launchedActivity.info.applicationInfo.uid,
-                    info.launchedActivity.packageName,
+                    activity.info.applicationInfo.uid,
+                    activity.packageName,
                     convertAppStartTransitionType(type),
-                    info.launchedActivity.info.name));
+                    activity.info.name));
         }
     }
 
-    private void logAppTransitionMultiEvents() {
-        if (DEBUG_METRICS) Slog.i(TAG, "logging transition events");
-        for (int index = mWindowingModeTransitionInfo.size() - 1; index >= 0; index--) {
-            final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.valueAt(index);
-            final int type = getTransitionType(info);
-            if (type == INVALID_TRANSITION_TYPE) {
-                if (DEBUG_METRICS) {
-                    Slog.i(TAG, "invalid transition type"
-                            + " processRunning=" + info.currentTransitionProcessRunning
-                            + " startResult=" + info.startResult);
-                }
-                return;
-            }
+    private void logAppTransitionFinished(@NonNull TransitionInfo info) {
+        if (DEBUG_METRICS) Slog.i(TAG, "logging finished transition " + info);
 
-            // Take a snapshot of the transition info before sending it to the handler for logging.
-            // This will avoid any races with other operations that modify the ActivityRecord.
-            final WindowingModeTransitionInfoSnapshot infoSnapshot =
-                     new WindowingModeTransitionInfoSnapshot(info);
-            final int currentTransitionDeviceUptime = mCurrentTransitionDeviceUptime;
-            final int currentTransitionDelayMs = mCurrentTransitionDelayMs;
-            BackgroundThread.getHandler().post(() -> logAppTransition(
-                    currentTransitionDeviceUptime, currentTransitionDelayMs, infoSnapshot));
-            BackgroundThread.getHandler().post(() -> logAppDisplayed(infoSnapshot));
-            if (info.pendingFullyDrawn != null) {
-                info.pendingFullyDrawn.run();
-            }
-
-            info.launchedActivity.info.launchToken = null;
+        // Take a snapshot of the transition info before sending it to the handler for logging.
+        // This will avoid any races with other operations that modify the ActivityRecord.
+        final TransitionInfoSnapshot infoSnapshot = new TransitionInfoSnapshot(info);
+        BackgroundThread.getHandler().post(() -> logAppTransition(
+                info.mCurrentTransitionDeviceUptime, info.mCurrentTransitionDelayMs, infoSnapshot));
+        BackgroundThread.getHandler().post(() -> logAppDisplayed(infoSnapshot));
+        if (info.mPendingFullyDrawn != null) {
+            info.mPendingFullyDrawn.run();
         }
+
+        info.mLastLaunchedActivity.info.launchToken = null;
     }
 
     // This gets called on a background thread without holding the activity manager lock.
     private void logAppTransition(int currentTransitionDeviceUptime, int currentTransitionDelayMs,
-            WindowingModeTransitionInfoSnapshot info) {
+            TransitionInfoSnapshot info) {
         final LogMaker builder = new LogMaker(APP_TRANSITION);
         builder.setPackageName(info.packageName);
         builder.setType(info.type);
@@ -800,12 +851,12 @@
         logAppStartMemoryStateCapture(info);
     }
 
-    private void logAppDisplayed(WindowingModeTransitionInfoSnapshot info) {
+    private void logAppDisplayed(TransitionInfoSnapshot info) {
         if (info.type != TYPE_TRANSITION_WARM_LAUNCH && info.type != TYPE_TRANSITION_COLD_LAUNCH) {
             return;
         }
 
-        EventLog.writeEvent(AM_ACTIVITY_LAUNCH_TIME,
+        EventLog.writeEvent(WM_ACTIVITY_LAUNCH_TIME,
                 info.userId, info.activityRecordIdHashCode, info.launchedActivityShortComponentName,
                 info.windowsDrawnDelayMs);
 
@@ -831,26 +882,25 @@
         return StatsLog.APP_START_OCCURRED__TYPE__UNKNOWN;
     }
 
-    /** @return the last known window drawn delay of the given windowing mode. */
-    int getLastDrawnDelayMs(@WindowingMode int windowingMode) {
-        final WindowingModeTransitionInfo info = mLastWindowingModeTransitionInfo.get(
-                windowingMode);
-        return info != null ? info.windowsDrawnDelayMs : INVALID_DELAY;
+    /** @return the last known window drawn delay of the given activity. */
+    int getLastDrawnDelayMs(ActivityRecord r) {
+        final TransitionInfo info = mLastTransitionInfo.get(r);
+        return info != null ? info.mWindowsDrawnDelayMs : INVALID_DELAY;
     }
 
-    WindowingModeTransitionInfoSnapshot logAppTransitionReportedDrawn(ActivityRecord r,
+    /** @see android.app.Activity#reportFullyDrawn */
+    TransitionInfoSnapshot logAppTransitionReportedDrawn(ActivityRecord r,
             boolean restoredFromBundle) {
-        final WindowingModeTransitionInfo info = mLastWindowingModeTransitionInfo.get(
-                r.getWindowingMode());
+        final TransitionInfo info = mLastTransitionInfo.get(r);
         if (info == null) {
             return null;
         }
-        if (info.numUndrawnActivities > 0 && info.pendingFullyDrawn == null) {
+        if (!info.allDrawn() && info.mPendingFullyDrawn == null) {
             // There are still undrawn activities, postpone reporting fully drawn until all of its
             // windows are drawn. So that is closer to an usable state.
-            info.pendingFullyDrawn = () -> {
+            info.mPendingFullyDrawn = () -> {
                 logAppTransitionReportedDrawn(r, restoredFromBundle);
-                info.pendingFullyDrawn = null;
+                info.mPendingFullyDrawn = null;
             };
             return null;
         }
@@ -859,39 +909,39 @@
         // actually used to trace this function, but instead the logical task that this function
         // fullfils (handling reportFullyDrawn() callbacks).
         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
-                "ActivityManager:ReportingFullyDrawn " + info.launchedActivity.packageName);
+                "ActivityManager:ReportingFullyDrawn " + info.mLastLaunchedActivity.packageName);
 
         final LogMaker builder = new LogMaker(APP_TRANSITION_REPORTED_DRAWN);
         builder.setPackageName(r.packageName);
         builder.addTaggedData(FIELD_CLASS_NAME, r.info.name);
         final long currentTimestampNs = SystemClock.elapsedRealtimeNanos();
-        final long startupTimeMs = info.pendingFullyDrawn != null
-                ? info.windowsDrawnDelayMs
-                : TimeUnit.NANOSECONDS.toMillis(currentTimestampNs - mLastTransitionStartTimeNs);
+        final long startupTimeMs = info.mPendingFullyDrawn != null
+                ? info.mWindowsDrawnDelayMs
+                : TimeUnit.NANOSECONDS.toMillis(currentTimestampNs - info.mTransitionStartTimeNs);
         builder.addTaggedData(APP_TRANSITION_REPORTED_DRAWN_MS, startupTimeMs);
         builder.setType(restoredFromBundle
                 ? TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE
                 : TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE);
         builder.addTaggedData(APP_TRANSITION_PROCESS_RUNNING,
-                info.currentTransitionProcessRunning ? 1 : 0);
+                info.mProcessRunning ? 1 : 0);
         mMetricsLogger.write(builder);
         StatsLog.write(
                 StatsLog.APP_START_FULLY_DRAWN,
-                info.launchedActivity.info.applicationInfo.uid,
-                info.launchedActivity.packageName,
+                info.mLastLaunchedActivity.info.applicationInfo.uid,
+                info.mLastLaunchedActivity.packageName,
                 restoredFromBundle
                         ? StatsLog.APP_START_FULLY_DRAWN__TYPE__WITH_BUNDLE
                         : StatsLog.APP_START_FULLY_DRAWN__TYPE__WITHOUT_BUNDLE,
-                info.launchedActivity.info.name,
-                info.currentTransitionProcessRunning,
+                info.mLastLaunchedActivity.info.name,
+                info.mProcessRunning,
                 startupTimeMs);
 
         // Ends the trace started at the beginning of this function. This is located here to allow
         // the trace slice to have a noticable duration.
         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
 
-        final WindowingModeTransitionInfoSnapshot infoSnapshot =
-                new WindowingModeTransitionInfoSnapshot(info, r, (int) startupTimeMs);
+        final TransitionInfoSnapshot infoSnapshot =
+                new TransitionInfoSnapshot(info, r, (int) startupTimeMs);
         BackgroundThread.getHandler().post(() -> logAppFullyDrawn(infoSnapshot));
 
         // Notify reportFullyDrawn event.
@@ -900,7 +950,7 @@
         return infoSnapshot;
     }
 
-    private void logAppFullyDrawn(WindowingModeTransitionInfoSnapshot info) {
+    private void logAppFullyDrawn(TransitionInfoSnapshot info) {
         if (info.type != TYPE_TRANSITION_WARM_LAUNCH && info.type != TYPE_TRANSITION_COLD_LAUNCH) {
             return;
         }
@@ -976,23 +1026,7 @@
         mMetricsLogger.write(builder);
     }
 
-    private int getTransitionType(WindowingModeTransitionInfo info) {
-        if (info.currentTransitionProcessRunning) {
-            if (info.startResult == START_SUCCESS) {
-                return TYPE_TRANSITION_WARM_LAUNCH;
-            } else if (info.startResult == START_TASK_TO_FRONT) {
-                return TYPE_TRANSITION_HOT_LAUNCH;
-            }
-        } else if (info.startResult == START_SUCCESS
-                || (info.startResult == START_TASK_TO_FRONT)) {
-            // Task may still exist when cold launching an activity and the start
-            // result will be set to START_TASK_TO_FRONT. Treat this as a COLD launch.
-            return TYPE_TRANSITION_COLD_LAUNCH;
-        }
-        return INVALID_TRANSITION_TYPE;
-    }
-
-    private void logAppStartMemoryStateCapture(WindowingModeTransitionInfoSnapshot info) {
+    private void logAppStartMemoryStateCapture(TransitionInfoSnapshot info) {
         if (info.processRecord == null) {
             if (DEBUG_METRICS) Slog.i(TAG, "logAppStartMemoryStateCapture processRecord null");
             return;
@@ -1018,13 +1052,6 @@
                 memoryStat.swapInBytes);
     }
 
-    private WindowProcessController findProcessForActivity(ActivityRecord launchedActivity) {
-        return launchedActivity != null
-                ? mSupervisor.mService.mProcessNames.get(
-                        launchedActivity.processName, launchedActivity.info.applicationInfo.uid)
-                : null;
-    }
-
     private ArtManagerInternal getArtManagerInternal() {
         if (mArtManagerInternal == null) {
             // Note that this may be null.
@@ -1035,30 +1062,24 @@
         return mArtManagerInternal;
     }
 
-    /**
-     * Starts traces for app launch.
-     *
-     * @param info
-     * */
-    private void startTraces(WindowingModeTransitionInfo info) {
-        if (!Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER) || info == null
-                || info.launchTraceActive) {
+    /** Starts trace for an activity is actually launching. */
+    private void startLaunchTrace(@NonNull TransitionInfo info) {
+        if (DEBUG_METRICS) Slog.i(TAG, "startLaunchTrace " + info);
+        if (!Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
             return;
         }
-        Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "launching: "
-                + info.launchedActivity.packageName, 0);
-        info.launchTraceActive = true;
+        info.mLaunchTraceName = "launching: " + info.mLastLaunchedActivity.packageName;
+        Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, info.mLaunchTraceName, 0);
     }
 
-    private void stopLaunchTrace(WindowingModeTransitionInfo info) {
-        if (info == null) {
+    /** Stops trace for the launch is completed or cancelled. */
+    private void stopLaunchTrace(@NonNull TransitionInfo info) {
+        if (DEBUG_METRICS) Slog.i(TAG, "stopLaunchTrace " + info);
+        if (info.mLaunchTraceName == null) {
             return;
         }
-        if (info.launchTraceActive) {
-            Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "launching: "
-                    + info.launchedActivity.packageName, 0);
-            info.launchTraceActive = false;
-        }
+        Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, info.mLaunchTraceName, 0);
+        info.mLaunchTraceName = null;
     }
 
     public ActivityMetricsLaunchObserverRegistry getLaunchObserverRegistry() {
@@ -1094,16 +1115,16 @@
      * Notify the {@link ActivityMetricsLaunchObserver} that the current launch sequence's activity
      * has started.
      */
-    private void launchObserverNotifyActivityLaunched(WindowingModeTransitionInfo info) {
+    private void launchObserverNotifyActivityLaunched(TransitionInfo info) {
         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                 "MetricsLogger:launchObserverNotifyActivityLaunched");
 
         @ActivityMetricsLaunchObserver.Temperature int temperature =
-                convertTransitionTypeToLaunchObserverTemperature(getTransitionType(info));
+                convertTransitionTypeToLaunchObserverTemperature(info.mTransitionType);
 
         // Beginning a launch is timing sensitive and so should be observed as soon as possible.
-        mLaunchObserver.onActivityLaunched(convertActivityRecordToProto(info.launchedActivity),
-                                           temperature);
+        mLaunchObserver.onActivityLaunched(convertActivityRecordToProto(info.mLastLaunchedActivity),
+                temperature);
 
         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
     }
@@ -1122,12 +1143,12 @@
      * Notify the {@link ActivityMetricsLaunchObserver} that the current launch sequence is
      * cancelled.
      */
-    private void launchObserverNotifyActivityLaunchCancelled(WindowingModeTransitionInfo info) {
+    private void launchObserverNotifyActivityLaunchCancelled(TransitionInfo info) {
         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                 "MetricsLogger:launchObserverNotifyActivityLaunchCancelled");
 
         final @ActivityMetricsLaunchObserver.ActivityRecordProto byte[] activityRecordProto =
-                info != null ? convertActivityRecordToProto(info.launchedActivity) : null;
+                info != null ? convertActivityRecordToProto(info.mLastLaunchedActivity) : null;
 
         mLaunchObserver.onActivityLaunchCancelled(activityRecordProto);
 
@@ -1138,14 +1159,12 @@
      * Notify the {@link ActivityMetricsLaunchObserver} that the current launch sequence's activity
      * has fully finished (successfully).
      */
-    private void launchObserverNotifyActivityLaunchFinished(WindowingModeTransitionInfo info,
-        long timestampNs) {
+    private void launchObserverNotifyActivityLaunchFinished(TransitionInfo info, long timestampNs) {
         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                 "MetricsLogger:launchObserverNotifyActivityLaunchFinished");
 
-        mLaunchObserver
-            .onActivityLaunchFinished(convertActivityRecordToProto(info.launchedActivity),
-                timestampNs);
+        mLaunchObserver.onActivityLaunchFinished(
+                convertActivityRecordToProto(info.mLastLaunchedActivity), timestampNs);
 
         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
     }
@@ -1163,7 +1182,7 @@
         final ProtoOutputStream protoOutputStream =
                 new ProtoOutputStream(LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
         // Write this data out as the top-most ActivityRecordProto (i.e. it is not a sub-object).
-        record.writeToProto(protoOutputStream);
+        record.dumpDebug(protoOutputStream);
         final byte[] bytes = protoOutputStream.getBytes();
 
         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 0acab9c..83c854b 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -122,8 +122,6 @@
 import static com.android.server.am.ActivityRecordProto.TRANSLUCENT;
 import static com.android.server.am.ActivityRecordProto.VISIBLE;
 import static com.android.server.am.ActivityRecordProto.VISIBLE_REQUESTED;
-import static com.android.server.am.EventLogTags.AM_RELAUNCH_ACTIVITY;
-import static com.android.server.am.EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED;
@@ -303,16 +301,18 @@
 import com.android.internal.content.ReferrerIntent;
 import com.android.internal.util.ToBooleanFunction;
 import com.android.internal.util.XmlUtils;
+import com.android.internal.util.function.pooled.PooledConsumer;
+import com.android.internal.util.function.pooled.PooledFunction;
+import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.AttributeCache;
 import com.android.server.LocalServices;
 import com.android.server.am.AppTimeTracker;
-import com.android.server.am.EventLogTags;
 import com.android.server.am.PendingIntentRecord;
 import com.android.server.display.color.ColorDisplayService;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.protolog.common.ProtoLog;
 import com.android.server.uri.UriPermissionOwner;
-import com.android.server.wm.ActivityMetricsLogger.WindowingModeTransitionInfoSnapshot;
+import com.android.server.wm.ActivityMetricsLogger.TransitionInfoSnapshot;
 import com.android.server.wm.ActivityStack.ActivityState;
 import com.android.server.wm.WindowManagerService.H;
 import com.android.server.wm.utils.InsetUtils;
@@ -620,10 +620,6 @@
     // TODO: Make this final
     int mTargetSdk;
 
-    // Set to true when this app creates a surface while in the middle of an animation. In that
-    // case do not clear allDrawn until the animation completes.
-    boolean deferClearAllDrawn;
-
     // Is this window's surface needed?  This is almost like visible, except
     // it will sometimes be true a little earlier: when the activity record has
     // been shown, but is still waiting for its app transition to execute
@@ -698,12 +694,6 @@
         }
     }
 
-    void dump(PrintWriter pw, String prefix) {
-    }
-
-    /**
-     * Copied from old AppWindowToken.
-     */
     @Override
     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
         final long now = SystemClock.uptimeMillis();
@@ -777,10 +767,10 @@
                         pw.print(" primaryColor=");
                         pw.println(Integer.toHexString(taskDescription.getPrimaryColor()));
                         pw.print(prefix + " backgroundColor=");
-                        pw.println(Integer.toHexString(taskDescription.getBackgroundColor()));
-                        pw.print(prefix + " statusBarColor=");
-                        pw.println(Integer.toHexString(taskDescription.getStatusBarColor()));
-                        pw.print(prefix + " navigationBarColor=");
+                        pw.print(Integer.toHexString(taskDescription.getBackgroundColor()));
+                        pw.print(" statusBarColor=");
+                        pw.print(Integer.toHexString(taskDescription.getStatusBarColor()));
+                        pw.print(" navigationBarColor=");
                         pw.println(Integer.toHexString(taskDescription.getNavigationBarColor()));
             }
         }
@@ -853,14 +843,13 @@
             pw.println(requestedVrComponent);
         }
         super.dump(pw, prefix, dumpAll);
-        pw.print(" visible="); pw.print(mVisible);
-        if (appToken != null) {
-            pw.println(prefix + "app=true mVoiceInteraction=" + mVoiceInteraction);
+        if (mVoiceInteraction) {
+            pw.println(prefix + "mVoiceInteraction=true");
         }
-        pw.print(prefix); pw.print(" mOccludesParent="); pw.print(mOccludesParent);
+        pw.print(prefix); pw.print("mOccludesParent="); pw.print(mOccludesParent);
         pw.print(" mOrientation="); pw.println(mOrientation);
         pw.println(prefix + "mVisibleRequested=" + mVisibleRequested
-                + " mClientVisible=" + mClientVisible
+                + " mVisible=" + mVisible + " mClientVisible=" + mClientVisible
                 + ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "")
                 + " reportedDrawn=" + reportedDrawn + " reportedVisible=" + reportedVisible);
         if (paused) {
@@ -907,7 +896,7 @@
             pw.println(prefix + "mRemovingFromDisplay=" + mRemovingFromDisplay);
         }
         if (lastVisibleTime != 0 || nowVisible) {
-            pw.print(prefix); pw.print(" nowVisible="); pw.print(nowVisible);
+            pw.print(prefix); pw.print("nowVisible="); pw.print(nowVisible);
                     pw.print(" lastVisibleTime=");
                     if (lastVisibleTime == 0) pw.print("0");
                     else TimeUtils.formatDuration(lastVisibleTime, now, pw);
@@ -943,6 +932,10 @@
         }
     }
 
+    void setAppTimeTracker(AppTimeTracker att) {
+        appTimeTracker = att;
+    }
+
     /** Update the saved state of an activity. */
     void setSavedState(@Nullable Bundle savedState) {
         mIcicle = savedState;
@@ -1170,6 +1163,15 @@
 
         super.onParentChanged(newParent, oldParent);
 
+        if (isPersistable()) {
+            if (oldTask != null) {
+                mAtmService.notifyTaskPersisterLocked(oldTask, false);
+            }
+            if (newTask != null) {
+                mAtmService.notifyTaskPersisterLocked(newTask, false);
+            }
+        }
+
         if (oldParent == null && newParent != null) {
             // First time we are adding the activity to the system.
             mVoiceInteraction = newTask.voiceSession != null;
@@ -1264,12 +1266,8 @@
 
         if (prevDc.mFocusedApp == this) {
             prevDc.setFocusedApp(null);
-            final ActivityStack stack = dc.getTopStack();
-            if (stack != null) {
-                final Task task = stack.getTopChild();
-                if (task != null && task.getTopChild() == this) {
-                    dc.setFocusedApp(this);
-                }
+            if (dc.getTopMostActivity() == this) {
+                dc.setFocusedApp(this);
             }
         }
 
@@ -1523,7 +1521,13 @@
         hasBeenLaunched = false;
         mStackSupervisor = supervisor;
 
-        taskAffinity = aInfo.taskAffinity;
+        // b/35954083: Limit task affinity to uid to avoid various issues associated with sharing
+        // affinity across uids.
+        final String uid = Integer.toString(info.applicationInfo.uid);
+        if (info.taskAffinity != null && !info.taskAffinity.startsWith(uid)) {
+            info.taskAffinity = uid + ":" + info.taskAffinity;
+        }
+        taskAffinity = info.taskAffinity;
         stateNotNeeded = (aInfo.flags & FLAG_STATE_NOT_NEEDED) != 0;
         nonLocalizedLabel = aInfo.nonLocalizedLabel;
         labelRes = aInfo.labelRes;
@@ -1801,7 +1805,7 @@
                 // task snapshot starting window.
                 return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
             }
-            return snapshot == null ? STARTING_WINDOW_TYPE_SPLASH_SCREEN
+            return snapshot == null ? STARTING_WINDOW_TYPE_NONE
                     : snapshotOrientationSameAsTask(snapshot) || fromRecents
                             ? STARTING_WINDOW_TYPE_SNAPSHOT : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
         } else {
@@ -2209,7 +2213,7 @@
                 OP_PICTURE_IN_PICTURE, info.applicationInfo.uid, packageName) == MODE_ALLOWED;
     }
 
-    boolean isAlwaysFocusable() {
+    private boolean isAlwaysFocusable() {
         return (info.flags & FLAG_ALWAYS_FOCUSABLE) != 0;
     }
 
@@ -2228,7 +2232,7 @@
             }
         }
         return (getWindowConfiguration().canReceiveKeys() || isAlwaysFocusable())
-                && getParent() != null;
+                && getDisplay() != null;
     }
 
     /** Move activity with its stack to front and make the stack focused. */
@@ -2247,7 +2251,8 @@
             return false;
         }
 
-        if (mRootActivityContainer.getTopResumedActivity() == this) {
+        if (mRootActivityContainer.getTopResumedActivity() == this
+                && getDisplayContent().mFocusedApp == this) {
             if (DEBUG_FOCUS) {
                 Slog.d(TAG_FOCUS, "moveActivityStackToFront: already on top, activity=" + this);
             }
@@ -2266,23 +2271,28 @@
         return true;
     }
 
+    void finishIfSubActivity(ActivityRecord parent, String otherResultWho, int otherRequestCode) {
+        if (resultTo != parent
+                || requestCode != otherRequestCode
+                || !Objects.equals(resultWho, otherResultWho)) return;
+
+        finishIfPossible("request-sub", false /* oomAdj */);
+    }
+
     /** Finish all activities in the task with the same affinity as this one. */
-    void finishActivityAffinity() {
-        final ArrayList<ActivityRecord> activities = task.mChildren;
-        for (int index = activities.indexOf(this); index >= 0; --index) {
-            final ActivityRecord cur = activities.get(index);
-            if (!Objects.equals(cur.taskAffinity, taskAffinity)) {
-                break;
-            }
-            cur.finishIfPossible("request-affinity", true /* oomAdj */);
-        }
+    boolean finishIfSameAffinity(ActivityRecord r) {
+        // End search once we get to the activity that doesn't have the same affinity.
+        if (!Objects.equals(r.taskAffinity, taskAffinity)) return true;
+
+        r.finishIfPossible("request-affinity", true /* oomAdj */);
+        return false;
     }
 
     /**
      * Sets the result for activity that started this one, clears the references to activities
      * started for result from this one, and clears new intents.
      */
-    void finishActivityResults(int resultCode, Intent resultData) {
+    private void finishActivityResults(int resultCode, Intent resultData) {
         // Send the result if needed
         if (resultTo != null) {
             if (DEBUG_RESULTS) {
@@ -2379,17 +2389,14 @@
             // Make a local reference to its task since this.task could be set to null once this
             // activity is destroyed and detached from task.
             final Task task = getTask();
-            EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
-                    mUserId, System.identityHashCode(this),
+            EventLogTags.writeWmFinishActivity(mUserId, System.identityHashCode(this),
                     task.mTaskId, shortComponentName, reason);
-            final ArrayList<ActivityRecord> activities = task.mChildren;
-            final int index = activities.indexOf(this);
-            if (index < (task.getChildCount() - 1)) {
+            ActivityRecord next = task.getActivityAbove(this);
+            if (next != null) {
                 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
                     // If the caller asked that this activity (and all above it)
                     // be cleared when the task is reset, don't lose that information,
                     // but propagate it up to the next activity.
-                    final ActivityRecord next = task.getChildAt(index + 1);
                     next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
                 }
             }
@@ -2407,9 +2414,9 @@
                 } else {
                     // Only move the next stack to top in its display.
                     final ActivityDisplay display = stack.getDisplay();
-                    final ActivityRecord next = display.topRunningActivity();
+                    next = display.topRunningActivity();
                     if (next != null) {
-                        display.positionChildAtTop(next.getActivityStack(),
+                        display.positionStackAtTop(next.getActivityStack(),
                                 false /* includingParents */, "finish-display-top");
                     }
                 }
@@ -2417,7 +2424,8 @@
 
             finishActivityResults(resultCode, resultData);
 
-            final boolean endTask = index <= 0 && !task.isClearingToReuseTask();
+            final boolean endTask = task.getActivityBelow(this) == null
+                    && !task.isClearingToReuseTask();
             final int transit = endTask ? TRANSIT_TASK_CLOSE : TRANSIT_ACTIVITY_CLOSE;
             if (isState(RESUMED)) {
                 if (endTask) {
@@ -2477,16 +2485,13 @@
                 // sync with the activity visibility being set for this finishing activity above.
                 // In this case, we can set the visibility of all the task overlay activities when
                 // we detect the last one is finishing to keep them in sync.
-                if (task.onlyHasTaskOverlayActivities(true /* excludeFinishing */)) {
-                    for (int i = task.getChildCount() - 1; i >= 0 ; --i) {
-                        final ActivityRecord taskOverlay = task.getChildAt(i);
-                        if (!taskOverlay.mTaskOverlay) {
-                            continue;
-                        }
-                        taskOverlay.prepareActivityHideTransitionAnimation(transit);
-                    }
+                if (task.onlyHasTaskOverlayActivities(false /* includeFinishing */)) {
+                    final PooledConsumer c = PooledLambda.obtainConsumer(
+                            ActivityRecord::prepareActivityHideTransitionAnimationIfOvarlay,
+                            PooledLambda.__(ActivityRecord.class), transit);
+                    task.forAllActivities(c);
+                    c.recycle();
                 }
-
                 return removedActivity ? FINISH_RESULT_REMOVED : FINISH_RESULT_REQUESTED;
             } else {
                 if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish waiting for pause of: " + this);
@@ -2498,6 +2503,12 @@
         }
     }
 
+    private void prepareActivityHideTransitionAnimationIfOvarlay(int transit) {
+        if (mTaskOverlay) {
+            prepareActivityHideTransitionAnimation(transit);
+        }
+    }
+
     private void prepareActivityHideTransitionAnimation(int transit) {
         final DisplayContent dc = getDisplay().mDisplayContent;
         dc.prepareAppTransition(transit, false);
@@ -2655,8 +2666,8 @@
             return false;
         }
 
-        EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY, mUserId,
-                System.identityHashCode(this), task.mTaskId, shortComponentName, reason);
+        EventLogTags.writeWmDestroyActivity(mUserId, System.identityHashCode(this),
+                task.mTaskId, shortComponentName, reason);
 
         final ActivityStack stack = getActivityStack();
         if (hasProcess() && !stack.inLruList(this)) {
@@ -2995,6 +3006,7 @@
         getDisplayContent().mChangingApps.remove(this);
         getDisplayContent().mUnknownAppVisibilityController.appRemovedOrHidden(this);
         mWmService.mTaskSnapshotController.onAppRemoved(this);
+        mStackSupervisor.getActivityMetricsLogger().notifyActivityRemoved(this);
         waitingToShow = false;
         if (getDisplayContent().mClosingApps.contains(this)) {
             delayed = true;
@@ -3060,7 +3072,7 @@
         }
 
         // Reset the last saved PiP snap fraction on removal.
-        mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(mActivityComponent);
+        mDisplayContent.mPinnedStackControllerLocked.resetReentryBounds(mActivityComponent);
 
         mRemovingFromDisplay = false;
     }
@@ -3218,7 +3230,6 @@
                 // to move that animation to the new one.
                 if (fromActivity.allDrawn) {
                     allDrawn = true;
-                    deferClearAllDrawn = fromActivity.deferClearAllDrawn;
                 }
                 if (fromActivity.firstWindowDrawn) {
                     firstWindowDrawn = true;
@@ -3269,15 +3280,16 @@
      * immediately finishes after, so we have to transfer T to M.
      */
     void transferStartingWindowFromHiddenAboveTokenIfNeeded() {
-        for (int i = task.mChildren.size() - 1; i >= 0; i--) {
-            final ActivityRecord fromActivity = task.mChildren.get(i);
-            if (fromActivity == this) {
-                return;
-            }
-            if (!fromActivity.mVisibleRequested && transferStartingWindow(fromActivity.token)) {
-                return;
-            }
-        }
+        final PooledFunction p = PooledLambda.obtainFunction(ActivityRecord::transferStartingWindow,
+                this, PooledLambda.__(ActivityRecord.class));
+        task.forAllActivities(p);
+        p.recycle();
+    }
+
+    private boolean transferStartingWindow(ActivityRecord fromActivity) {
+        if (fromActivity == this) return true;
+
+        return !fromActivity.mVisibleRequested && transferStartingWindow(fromActivity.token);
     }
 
     void checkKeyguardFlagsChanged() {
@@ -3349,7 +3361,7 @@
         if (!inPinnedWindowingMode() && (mShowWhenLocked || containsShowWhenLockedWindow())) {
             return true;
         } else if (mInheritShownWhenLocked) {
-            final ActivityRecord r = getActivityBelow();
+            final ActivityRecord r = task.getActivityBelow(this);
             return r != null && !r.inPinnedWindowingMode() && (r.mShowWhenLocked
                     || r.containsShowWhenLockedWindow());
         } else {
@@ -3374,19 +3386,6 @@
                 true /* topToBottom */);
     }
 
-    /**
-     * @return an {@link ActivityRecord} of the activity below this activity, or {@code null} if no
-     * such activity exists.
-     */
-    @Nullable
-    private ActivityRecord getActivityBelow() {
-        final int pos = task.mChildren.indexOf(this);
-        if (pos == -1) {
-            throw new IllegalStateException("Activity not found in its task");
-        }
-        return pos == 0 ? null : task.getChildAt(pos - 1);
-    }
-
     WindowState getImeTargetBelowWindow(WindowState w) {
         final int index = mChildren.indexOf(w);
         if (index > 0) {
@@ -3430,7 +3429,8 @@
     }
 
     @Override
-    boolean forAllActivities(Function<ActivityRecord, Boolean> callback) {
+    boolean forAllActivities(
+            Function<ActivityRecord, Boolean> callback, boolean traverseTopToBottom) {
         return callback.apply(this);
     }
 
@@ -3607,7 +3607,9 @@
                 clearOptionsLocked(false /* withAbort */);
             } else {
                 // This will clear the options for all the ActivityRecords for this Task.
-                task.clearAllPendingOptions();
+                task.forAllActivities((r) -> {
+                    r.clearOptionsLocked(false /* withAbort */);
+                });
             }
         }
     }
@@ -3711,7 +3713,6 @@
 
     void clearAllDrawn() {
         allDrawn = false;
-        deferClearAllDrawn = false;
     }
 
     /**
@@ -4323,7 +4324,7 @@
         ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppStopped: %s", this);
         mAppStopped = true;
         // Reset the last saved PiP snap fraction on app stop.
-        mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(mActivityComponent);
+        mDisplayContent.mPinnedStackControllerLocked.resetReentryBounds(mActivityComponent);
         destroySurfaces();
         // Remove any starting window that was added for this app if they are still around.
         removeStartingWindow();
@@ -4600,16 +4601,15 @@
         }
 
         // Check if position in task allows to become paused
-        final int positionInTask = task.mChildren.indexOf(this);
-        if (positionInTask == -1) {
+        if (!task.hasChild(this)) {
             throw new IllegalStateException("Activity not found in its task");
         }
-        if (positionInTask == task.getChildCount() - 1) {
+        final ActivityRecord activityAbove = task.getActivityAbove(this);
+        if (activityAbove == null) {
             // It's the topmost activity in the task - should become resumed now
             return true;
         }
         // Check if activity above is finishing now and this one becomes the topmost in task.
-        final ActivityRecord activityAbove = task.getChildAt(positionInTask + 1);
         if (activityAbove.finishing) {
             return true;
         }
@@ -4665,7 +4665,7 @@
         stopped = false;
 
         if (isActivityTypeHome()) {
-            mStackSupervisor.updateHomeProcess(task.getChildAt(0).app);
+            mStackSupervisor.updateHomeProcess(task.getBottomMostActivity().app);
         }
 
         if (nowVisible) {
@@ -4741,7 +4741,7 @@
             if (!mVisibleRequested) {
                 setVisibility(false);
             }
-            EventLogTags.writeAmStopActivity(
+            EventLogTags.writeWmStopActivity(
                     mUserId, System.identityHashCode(this), shortComponentName);
             mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
                     StopActivityItem.obtain(mVisibleRequested, configChangeFlags));
@@ -4810,8 +4810,8 @@
 
     void addToStopping(boolean scheduleIdle, boolean idleDelayed, String reason) {
         if (!mStackSupervisor.mStoppingActivities.contains(this)) {
-            EventLog.writeEvent(EventLogTags.AM_ADD_TO_STOPPING, mUserId,
-                    System.identityHashCode(this), shortComponentName, reason);
+            EventLogTags.writeWmAddToStopping(mUserId, System.identityHashCode(this),
+                    shortComponentName, reason);
             mStackSupervisor.mStoppingActivities.add(this);
         }
 
@@ -4980,7 +4980,7 @@
     }
 
     void reportFullyDrawnLocked(boolean restoredFromBundle) {
-        final WindowingModeTransitionInfoSnapshot info = mStackSupervisor
+        final TransitionInfoSnapshot info = mStackSupervisor
             .getActivityMetricsLogger().logAppTransitionReportedDrawn(this, restoredFromBundle);
         if (info != null) {
             mStackSupervisor.reportActivityLaunchedLocked(false /* timeout */, this,
@@ -5012,8 +5012,8 @@
         if (!drawn) {
             return;
         }
-        final WindowingModeTransitionInfoSnapshot info = mStackSupervisor
-            .getActivityMetricsLogger().notifyWindowsDrawn(getWindowingMode(), timestampNs);
+        final TransitionInfoSnapshot info = mStackSupervisor
+                .getActivityMetricsLogger().notifyWindowsDrawn(this, timestampNs);
         final int windowsDrawnDelayMs = info != null ? info.windowsDrawnDelayMs : INVALID_DELAY;
         final @LaunchState int launchState = info != null ? info.getLaunchState() : -1;
         mStackSupervisor.reportActivityLaunchedLocked(false /* timeout */, this,
@@ -5214,7 +5214,8 @@
                     }
                 }
             } else if (w.isDrawnLw()) {
-                onStartingWindowDrawn(SystemClock.elapsedRealtimeNanos());
+                // The starting window for this container is drawn.
+                mStackSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn(this);
                 startingDisplayed = true;
             }
         }
@@ -5222,14 +5223,6 @@
         return isInterestingAndDrawn;
     }
 
-    /** Called when the starting window for this container is drawn. */
-    private void onStartingWindowDrawn(long timestampNs) {
-        synchronized (mAtmService.mGlobalLock) {
-            mAtmService.mStackSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn(
-                    getWindowingMode(), timestampNs);
-        }
-    }
-
     /**
      * Called when the key dispatching to a window associated with the app window container
      * timed-out.
@@ -5292,6 +5285,10 @@
                 && mAtmService.mAmInternal.isUserRunning(mUserId, 0 /* flags */));
     }
 
+    boolean canBeTopRunning() {
+        return !finishing && okToShowLocked();
+    }
+
     /**
      * This method will return true if the activity is either visible, is becoming visible, is
      * currently pausing, or is resumed.
@@ -5323,13 +5320,12 @@
 
     static int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
         final ActivityRecord r = ActivityRecord.forTokenLocked(token);
-        if (r == null) {
+        if (r == null || r.getParent() == null) {
             return INVALID_TASK_ID;
         }
         final Task task = r.task;
-        final int activityNdx = task.mChildren.indexOf(r);
-        if (activityNdx < 0
-                || (onlyRoot && activityNdx > task.findRootIndex(true /* effectiveRoot */))) {
+        if (onlyRoot && r.compareTo(task.getRootActivity(
+                false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/)) > 0) {
             return INVALID_TASK_ID;
         }
         return task.mTaskId;
@@ -5686,8 +5682,6 @@
     @Override
     boolean isWaitingForTransitionStart() {
         final DisplayContent dc = getDisplayContent();
-        // TODO(display-unify): Test for null can be removed once unification is done.
-        if (dc == null) return false;
         return dc.mAppTransition.isTransitionSet()
                 && (dc.mOpeningApps.contains(this)
                 || dc.mClosingApps.contains(this)
@@ -6564,7 +6558,7 @@
             stackBounds = mTmpRect;
             pinnedStack.getBounds(stackBounds);
         }
-        mDisplayContent.mPinnedStackControllerLocked.saveReentrySnapFraction(
+        mDisplayContent.mPinnedStackControllerLocked.saveReentryBounds(
                 mActivityComponent, stackBounds);
     }
 
@@ -6942,9 +6936,13 @@
                 "Relaunching: " + this + " with results=" + pendingResults
                         + " newIntents=" + pendingNewIntents + " andResume=" + andResume
                         + " preserveWindow=" + preserveWindow);
-        EventLog.writeEvent(andResume ? AM_RELAUNCH_RESUME_ACTIVITY
-                        : AM_RELAUNCH_ACTIVITY, mUserId, System.identityHashCode(this),
-                task.mTaskId, shortComponentName);
+        if (andResume) {
+            EventLogTags.writeWmRelaunchResumeActivity(mUserId, System.identityHashCode(this),
+                    task.mTaskId, shortComponentName);
+        } else {
+            EventLogTags.writeWmRelaunchActivity(mUserId, System.identityHashCode(this),
+                    task.mTaskId, shortComponentName);
+        }
 
         startFreezingScreenLocked(0);
 
@@ -7216,6 +7214,10 @@
         return info.applicationInfo.uid;
     }
 
+    boolean isUid(int uid) {
+        return info.applicationInfo.uid == uid;
+    }
+
     int getPid() {
         return app != null ? app.getPid() : 0;
     }
@@ -7279,13 +7281,8 @@
         if (task == null) {
             return false;
         }
-        final ActivityRecord rootActivity = task.getRootActivity();
-        if (rootActivity != null) {
-            return this == rootActivity;
-        }
-        // No non-finishing activity found. In this case the bottom-most activity is considered to
-        // be the root.
-        return task.getChildAt(0) == this;
+        final ActivityRecord rootActivity = task.getRootActivity(true);
+        return this == rootActivity;
     }
 
     @Override
@@ -7309,8 +7306,8 @@
      * Write all fields to an {@code ActivityRecordProto}. This assumes the
      * {@code ActivityRecordProto} is the outer-most proto data.
      */
-    void writeToProto(ProtoOutputStream proto) {
-        writeToProto(proto, APP_WINDOW_TOKEN, WindowTraceLogLevel.ALL);
+    void dumpDebug(ProtoOutputStream proto) {
+        dumpDebug(proto, APP_WINDOW_TOKEN, WindowTraceLogLevel.ALL);
         writeIdentifierToProto(proto, IDENTIFIER);
         proto.write(STATE, mState.toString());
         proto.write(VISIBLE_REQUESTED, mVisibleRequested);
@@ -7322,9 +7319,9 @@
         proto.write(VISIBLE, mVisible);
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
-        writeToProto(proto);
+        dumpDebug(proto);
         proto.end(token);
     }
 
@@ -7332,7 +7329,7 @@
      * Copied from old AppWindowToken.
      */
     @Override
-    public void writeToProto(ProtoOutputStream proto, long fieldId,
+    public void dumpDebug(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
         // Critical log level logs only visible elements to mitigate performance overheard
         if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
@@ -7341,12 +7338,12 @@
 
         final long token = proto.start(fieldId);
         writeNameToProto(proto, NAME);
-        super.writeToProto(proto, WINDOW_TOKEN, logLevel);
+        super.dumpDebug(proto, WINDOW_TOKEN, logLevel);
         proto.write(LAST_SURFACE_SHOWING, mLastSurfaceShowing);
         proto.write(IS_WAITING_FOR_TRANSITION_START, isWaitingForTransitionStart());
         proto.write(IS_ANIMATING, isAnimating());
         if (mThumbnail != null){
-            mThumbnail.writeToProto(proto, THUMBNAIL);
+            mThumbnail.dumpDebug(proto, THUMBNAIL);
         }
         proto.write(FILLS_PARENT, mOccludesParent);
         proto.write(APP_STOPPED, mAppStopped);
@@ -7367,7 +7364,7 @@
         proto.write(VISIBLE_SET_FROM_TRANSFERRED_STARTING_WINDOW,
                 mVisibleSetFromTransferredStartingWindow);
         for (Rect bounds : mFrozenBounds) {
-            bounds.writeToProto(proto, FROZEN_BOUNDS);
+            bounds.dumpDebug(proto, FROZEN_BOUNDS);
         }
         proto.write(com.android.server.wm.AppWindowTokenProto.VISIBLE, mVisible);
         proto.end(token);
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index f1c47eb..cc45671 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -76,15 +76,12 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_APP;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RELEASE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_APP;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CLEANUP;
@@ -108,7 +105,6 @@
 import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
 import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START;
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
-import static com.android.server.wm.RootActivityContainer.FindTaskResult;
 import static com.android.server.wm.StackProto.ADJUSTED_BOUNDS;
 import static com.android.server.wm.StackProto.ADJUSTED_FOR_IME;
 import static com.android.server.wm.StackProto.ADJUST_DIVIDER_AMOUNT;
@@ -144,12 +140,10 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.Region;
-import android.net.Uri;
 import android.os.Binder;
 import android.os.Debug;
 import android.os.Handler;
@@ -163,8 +157,6 @@
 import android.service.voice.IVoiceInteractionSession;
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
-import android.util.EventLog;
-import android.util.IntArray;
 import android.util.Log;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
@@ -180,26 +172,26 @@
 import com.android.internal.os.logging.MetricsLoggerWrapper;
 import com.android.internal.policy.DividerSnapAlgorithm;
 import com.android.internal.policy.DockedDividerUtils;
+import com.android.internal.util.function.pooled.PooledConsumer;
+import com.android.internal.util.function.pooled.PooledFunction;
 import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.util.function.pooled.PooledPredicate;
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.am.ActivityManagerService.ItemMatcher;
 import com.android.server.am.AppTimeTracker;
-import com.android.server.am.EventLogTags;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
-import java.util.Set;
 import java.util.function.Consumer;
 
 /**
  * State and management of a single stack of activities.
  */
-class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarget,
-        ConfigurationContainerListener {
+class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarget {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_ATM;
     static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
     private static final String TAG_APP = TAG + POSTFIX_APP;
@@ -502,7 +494,7 @@
                 case DESTROY_ACTIVITIES_MSG: {
                     ScheduleDestroyArgs args = (ScheduleDestroyArgs)msg.obj;
                     synchronized (mService.mGlobalLock) {
-                        destroyActivitiesLocked(args.mOwner, args.mReason);
+                        destroyActivities(args.mOwner, args.mReason);
                     }
                 } break;
                 case TRANSLUCENT_TIMEOUT_MSG: {
@@ -517,13 +509,226 @@
     private static final ResetTargetTaskHelper sResetTargetTaskHelper = new ResetTargetTaskHelper();
     private final EnsureActivitiesVisibleHelper mEnsureActivitiesVisibleHelper =
             new EnsureActivitiesVisibleHelper(this);
+    private final EnsureVisibleActivitiesConfigHelper mEnsureVisibleActivitiesConfigHelper =
+            new EnsureVisibleActivitiesConfigHelper();
+    private class EnsureVisibleActivitiesConfigHelper {
+        private boolean mUpdateConfig;
+        private boolean mPreserveWindow;
+        private boolean mBehindFullscreen;
 
-    int numActivities() {
-        int count = 0;
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            count += getChildAt(taskNdx).getChildCount();
+        void reset(boolean preserveWindow) {
+            mPreserveWindow = preserveWindow;
+            mUpdateConfig = false;
+            mBehindFullscreen = false;
         }
-        return count;
+
+        void process(ActivityRecord start, boolean preserveWindow) {
+            if (start == null || !start.mVisibleRequested) {
+                return;
+            }
+            reset(preserveWindow);
+
+            final PooledFunction f = PooledLambda.obtainFunction(
+                    EnsureVisibleActivitiesConfigHelper::processActivity, this,
+                    PooledLambda.__(ActivityRecord.class));
+            forAllActivities(f, start.getTask(), true /*includeBoundary*/,
+                    true /*traverseTopToBottom*/);
+            f.recycle();
+
+            if (mUpdateConfig) {
+                // Ensure the resumed state of the focus activity if we updated the configuration of
+                // any activity.
+                mRootActivityContainer.resumeFocusedStacksTopActivities();
+            }
+        }
+
+        boolean processActivity(ActivityRecord r) {
+            mUpdateConfig |= r.ensureActivityConfiguration(0 /*globalChanges*/, mPreserveWindow);
+            mBehindFullscreen |= r.occludesParent();
+            return mBehindFullscreen;
+        }
+    }
+
+    private final CheckBehindFullscreenActivityHelper mCheckBehindFullscreenActivityHelper =
+            new CheckBehindFullscreenActivityHelper();
+    private class CheckBehindFullscreenActivityHelper {
+        private boolean mAboveTop;
+        private boolean mBehindFullscreenActivity;
+        private ActivityRecord mToCheck;
+        private Consumer<ActivityRecord> mHandleBehindFullscreenActivity;
+        private boolean mHandlingOccluded;
+
+        private void reset(ActivityRecord toCheck,
+                Consumer<ActivityRecord> handleBehindFullscreenActivity) {
+            mToCheck = toCheck;
+            mHandleBehindFullscreenActivity = handleBehindFullscreenActivity;
+            mAboveTop = true;
+            mBehindFullscreenActivity = false;
+
+            if (!shouldBeVisible(null)) {
+                // The stack is not visible, so no activity in it should be displaying a starting
+                // window. Mark all activities below top and behind fullscreen.
+                mAboveTop = false;
+                mBehindFullscreenActivity = true;
+            }
+
+            mHandlingOccluded = mToCheck == null && mHandleBehindFullscreenActivity != null;
+        }
+
+        boolean process(ActivityRecord toCheck,
+                Consumer<ActivityRecord> handleBehindFullscreenActivity) {
+            reset(toCheck, handleBehindFullscreenActivity);
+
+            if (!mHandlingOccluded && mBehindFullscreenActivity) {
+                return true;
+            }
+
+            final ActivityRecord topActivity = topRunningActivityLocked();
+            final PooledFunction f = PooledLambda.obtainFunction(
+                    CheckBehindFullscreenActivityHelper::processActivity, this,
+                    PooledLambda.__(ActivityRecord.class), topActivity);
+            forAllActivities(f);
+            f.recycle();
+
+            return mBehindFullscreenActivity;
+        }
+
+        private boolean processActivity(ActivityRecord r, ActivityRecord topActivity) {
+            if (mAboveTop) {
+                if (r == topActivity) {
+                    if (r == mToCheck) {
+                        // It is the top activity in a visible stack.
+                        mBehindFullscreenActivity = false;
+                        return true;
+                    }
+                    mAboveTop = false;
+                }
+                mBehindFullscreenActivity |= r.occludesParent();
+                return false;
+            }
+
+            if (mHandlingOccluded) {
+                mHandleBehindFullscreenActivity.accept(r);
+            } else if (r == mToCheck) {
+                return true;
+            } else if (mBehindFullscreenActivity) {
+                // It is occluded before {@param toCheck} is found.
+                return true;
+            }
+            mBehindFullscreenActivity |= r.occludesParent();
+            return false;
+        }
+    }
+
+    // TODO: Can we just loop through WindowProcessController#mActivities instead of doing this?
+    private final RemoveHistoryRecordsForApp mRemoveHistoryRecordsForApp =
+            new RemoveHistoryRecordsForApp();
+    private class RemoveHistoryRecordsForApp {
+        private boolean mHasVisibleActivities;
+        private boolean mIsProcessRemoved;
+        private WindowProcessController mApp;
+        private ArrayList<ActivityRecord> mToRemove = new ArrayList<>();
+
+        boolean process(WindowProcessController app) {
+            mToRemove.clear();
+            mHasVisibleActivities = false;
+            mApp = app;
+            mIsProcessRemoved = app.isRemoved();
+            if (mIsProcessRemoved) {
+                // The package of the died process should be force-stopped, so make its activities
+                // as finishing to prevent the process from being started again if the next top
+                // (or being visible) activity also resides in the same process.
+                app.makeFinishingForProcessRemoved();
+            }
+
+            final PooledConsumer c = PooledLambda.obtainConsumer(
+                    RemoveHistoryRecordsForApp::addActivityToRemove, this,
+                    PooledLambda.__(ActivityRecord.class));
+            forAllActivities(c);
+            c.recycle();
+
+            while (!mToRemove.isEmpty()) {
+                processActivity(mToRemove.remove(0));
+            }
+
+            mApp = null;
+            return mHasVisibleActivities;
+        }
+
+        private void addActivityToRemove(ActivityRecord r) {
+            if (r.app == mApp) {
+                mToRemove.add(r);
+            }
+        }
+
+        private void processActivity(ActivityRecord r) {
+            if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP, "Record " + r + ": app=" + r.app);
+
+            if (r.app != mApp) {
+                return;
+            }
+            if (r.isVisible() || r.mVisibleRequested) {
+                // While an activity launches a new activity, it's possible that the old
+                // activity is already requested to be hidden (mVisibleRequested=false), but
+                // this visibility is not yet committed, so isVisible()=true.
+                mHasVisibleActivities = true;
+            }
+            final boolean remove;
+            if ((r.mRelaunchReason == RELAUNCH_REASON_WINDOWING_MODE_RESIZE
+                    || r.mRelaunchReason == RELAUNCH_REASON_FREE_RESIZE)
+                    && r.launchCount < 3 && !r.finishing) {
+                // If the process crashed during a resize, always try to relaunch it, unless
+                // it has failed more than twice. Skip activities that's already finishing
+                // cleanly by itself.
+                remove = false;
+            } else if ((!r.hasSavedState() && !r.stateNotNeeded
+                    && !r.isState(ActivityState.RESTARTING_PROCESS)) || r.finishing) {
+                // Don't currently have state for the activity, or
+                // it is finishing -- always remove it.
+                remove = true;
+            } else if (!r.mVisibleRequested && r.launchCount > 2
+                    && r.lastLaunchTime > (SystemClock.uptimeMillis() - 60000)) {
+                // We have launched this activity too many times since it was
+                // able to run, so give up and remove it.
+                // (Note if the activity is visible, we don't remove the record.
+                // We leave the dead window on the screen but the process will
+                // not be restarted unless user explicitly tap on it.)
+                remove = true;
+            } else {
+                // The process may be gone, but the activity lives on!
+                remove = false;
+            }
+            if (remove) {
+                if (DEBUG_ADD_REMOVE || DEBUG_CLEANUP) Slog.i(TAG_ADD_REMOVE,
+                        "Removing activity " + r + " from stack "
+                                + ": hasSavedState=" + r.hasSavedState()
+                                + " stateNotNeeded=" + r.stateNotNeeded
+                                + " finishing=" + r.finishing
+                                + " state=" + r.getState() + " callers=" + Debug.getCallers(5));
+                if (!r.finishing || mIsProcessRemoved) {
+                    Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
+                    EventLogTags.writeWmFinishActivity(r.mUserId,
+                        System.identityHashCode(r), r.getTask().mTaskId,
+                            r.shortComponentName, "proc died without state saved");
+                }
+            } else {
+                // We have the current state for this activity, so
+                // it can be restarted later when needed.
+                if (DEBUG_ALL) Slog.v(TAG, "Keeping entry, setting app to null");
+                if (DEBUG_APP) Slog.v(TAG_APP,
+                        "Clearing app during removeHistory for activity " + r);
+                r.app = null;
+                // Set nowVisible to previous visible state. If the app was visible while
+                // it died, we leave the dead window on screen so it's basically visible.
+                // This is needed when user later tap on the dead window, we need to stop
+                // other apps when user transfers focus to the restarted activity.
+                r.nowVisible = r.mVisibleRequested;
+            }
+            r.cleanUp(true /* cleanServices */, true /* setState */);
+            if (remove) {
+                r.removeFromHistory("appDied");
+            }
+        }
     }
 
     ActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor,
@@ -533,7 +738,7 @@
         mDockedStackMinimizeThickness =
                 supervisor.mService.mWindowManager.mContext.getResources().getDimensionPixelSize(
                         com.android.internal.R.dimen.docked_stack_minimize_thickness);
-        EventLog.writeEvent(com.android.server.EventLogTags.WM_STACK_CREATED, stackId);
+        EventLogTags.writeWmStackCreated(stackId);
         mStackSupervisor = supervisor;
         mService = supervisor.mService;
         mRootActivityContainer = mService.mRootActivityContainer;
@@ -545,7 +750,7 @@
         // stacks on a wrong display.
         mDisplayId = display.mDisplayId;
         setActivityType(activityType);
-        display.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM);
+        display.addStack(this, onTop ? POSITION_TOP : POSITION_BOTTOM);
         setWindowingMode(windowingMode, false /* animate */, false /* showRecents */,
                 false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */,
                 true /* creating */);
@@ -674,7 +879,6 @@
                         newBounds /* outStackBounds */, mTmpRect2 /* outTempTaskBounds */);
                 hasNewOverrideBounds = true;
             }
-            display.onStackWindowingModeChanged(this);
         }
         if (hasNewOverrideBounds) {
             if (inSplitScreenPrimaryWindowingMode()) {
@@ -691,7 +895,7 @@
             // Since always on top is only on when the stack is freeform or pinned, the state
             // can be toggled when the windowing mode changes. We must make sure the stack is
             // placed properly when always on top state changes.
-            display.positionChildAtTop(this, false /* includingParents */);
+            display.positionStackAtTop(this, false /* includingParents */);
         }
     }
 
@@ -944,7 +1148,7 @@
         }
     }
 
-    boolean updateBoundsAllowed(Rect bounds) {
+    private boolean updateBoundsAllowed(Rect bounds) {
         if (!mUpdateBoundsDeferred) {
             return true;
         }
@@ -957,7 +1161,7 @@
         return false;
     }
 
-    boolean updateDisplayedBoundsAllowed(Rect bounds) {
+    private boolean updateDisplayedBoundsAllowed(Rect bounds) {
         if (!mUpdateBoundsDeferred) {
             return true;
         }
@@ -974,47 +1178,29 @@
         return topRunningActivityLocked(false /* focusableOnly */);
     }
 
-    void getAllRunningVisibleActivitiesLocked(ArrayList<ActivityRecord> outActivities) {
-        outActivities.clear();
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            getChildAt(taskNdx).getAllRunningVisibleActivitiesLocked(outActivities);
-        }
-    }
-
     ActivityRecord topRunningActivityLocked(boolean focusableOnly) {
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            ActivityRecord r = getChildAt(taskNdx).topRunningActivityLocked();
-            if (r != null && (!focusableOnly || r.isFocusable())) {
-                return r;
-            }
+        // Split into 2 to avoid object creation due to variable capture.
+        if (focusableOnly) {
+            return getActivity((r) -> r.canBeTopRunning() && r.isFocusable());
+        } else {
+            return getActivity(ActivityRecord::canBeTopRunning);
         }
-        return null;
     }
 
-    ActivityRecord topRunningNonOverlayTaskActivity() {
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = getChildAt(taskNdx);
-            for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = task.getChildAt(activityNdx);
-                if (!r.finishing && !r.mTaskOverlay) {
-                    return r;
-                }
-            }
-        }
-        return null;
+    private ActivityRecord topRunningNonOverlayTaskActivity() {
+        return getActivity((r) -> (r.canBeTopRunning() && !r.mTaskOverlay));
     }
 
     ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = getChildAt(taskNdx);
-            for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = task.getChildAt(activityNdx);
-                if (!r.finishing && !r.delayedResume && r != notTop && r.okToShowLocked()) {
-                    return r;
-                }
-            }
-        }
-        return null;
+        final PooledPredicate p = PooledLambda.obtainPredicate(ActivityStack::isTopRunningNonDelayed
+                , PooledLambda.__(ActivityRecord.class), notTop);
+        final ActivityRecord r = getActivity(p);
+        p.recycle();
+        return r;
+    }
+
+    private static boolean isTopRunningNonDelayed(ActivityRecord r, ActivityRecord notTop) {
+        return !r.delayedResume && r != notTop && r.canBeTopRunning();
     }
 
     /**
@@ -1027,30 +1213,19 @@
      * @return Returns the HistoryRecord of the next activity on the stack.
      */
     final ActivityRecord topRunningActivityLocked(IBinder token, int taskId) {
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            Task task = getChildAt(taskNdx);
-            if (task.mTaskId == taskId) {
-                continue;
-            }
-            for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = task.getChildAt(activityNdx);
-                // Note: the taskId check depends on real taskId fields being non-zero
-                if (!r.finishing && (token != r.appToken) && r.okToShowLocked()) {
-                    return r;
-                }
-            }
-        }
-        return null;
+        final PooledPredicate p = PooledLambda.obtainPredicate(ActivityStack::isTopRunning,
+                PooledLambda.__(ActivityRecord.class), taskId, token);
+        final ActivityRecord r = getActivity(p);
+        p.recycle();
+        return r;
+    }
+
+    private static boolean isTopRunning(ActivityRecord r, int taskId, IBinder notTop) {
+        return r.getTask().mTaskId == taskId && r.appToken != notTop && r.canBeTopRunning();
     }
 
     ActivityRecord getTopNonFinishingActivity() {
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final ActivityRecord r = getChildAt(taskNdx).getTopNonFinishingActivity();
-            if (r != null) {
-                return r;
-            }
-        }
-        return null;
+        return getTopActivity(false /*includeFinishing*/, true /*includeOverlays*/);
     }
 
     final Task topTask() {
@@ -1090,35 +1265,6 @@
         return null;
     }
 
-    boolean isInStackLocked(Task task) {
-        return mChildren.contains(task);
-    }
-
-    /** Checks if there are tasks with specific UID in the stack. */
-    boolean isUidPresent(int uid) {
-        for (int j = getChildCount() - 1; j >= 0; --j) {
-            final Task task = getChildAt(j);
-            for (int i = task.getChildCount() - 1; i >= 0 ; --i) {
-                final ActivityRecord r = task.getChildAt(i);
-                if (r.getUid() == uid) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    /** Get all UIDs that are present in the stack. */
-    void getPresentUIDs(IntArray presentUIDs) {
-        for (int j = getChildCount() - 1; j >= 0; --j) {
-            final Task task = getChildAt(j);
-            for (int i = task.getChildCount() - 1; i >= 0 ; --i) {
-                final ActivityRecord r = task.getChildAt(i);
-                presentUIDs.add(r.getUid());
-            }
-        }
-    }
-
     /** @return true if the stack can only contain one task */
     boolean isSingleTaskInstance() {
         final ActivityDisplay display = getDisplay();
@@ -1190,7 +1336,7 @@
         }
 
         final boolean movingTask = task != null;
-        display.positionChildAtTop(this, !movingTask /* includingParents */, reason);
+        display.positionStackAtTop(this, !movingTask /* includingParents */, reason);
         if (movingTask) {
             // This also moves the entire hierarchy branch to top, including parents
             positionChildAtTop(task);
@@ -1206,7 +1352,7 @@
             return;
         }
 
-        getDisplay().positionChildAtBottom(this, reason);
+        getDisplay().positionStackAtBottom(this, reason);
         if (task != null) {
             positionChildAtBottom(task);
         }
@@ -1235,138 +1381,6 @@
         return display != null && !display.isRemoved();
     }
 
-    /**
-     * Returns the top activity in any existing task matching the given Intent in the input result.
-     * Returns null if no such task is found.
-     */
-    void findTaskLocked(ActivityRecord target, FindTaskResult result) {
-        Intent intent = target.intent;
-        ActivityInfo info = target.info;
-        ComponentName cls = intent.getComponent();
-        if (info.targetActivity != null) {
-            cls = new ComponentName(info.packageName, info.targetActivity);
-        }
-        final int userId = UserHandle.getUserId(info.applicationInfo.uid);
-        boolean isDocument = intent != null & intent.isDocument();
-        // If documentData is non-null then it must match the existing task data.
-        Uri documentData = isDocument ? intent.getData() : null;
-
-        if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + target + " in " + this);
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = getChildAt(taskNdx);
-            if (task.voiceSession != null) {
-                // We never match voice sessions; those always run independently.
-                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": voice session");
-                continue;
-            }
-            if (task.mUserId != userId) {
-                // Looking for a different task.
-                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": different user");
-                continue;
-            }
-
-            // Overlays should not be considered as the task's logical top activity.
-            final ActivityRecord r = task.getTopNonFinishingActivity(false /* includeOverlays */);
-            if (r == null || r.finishing || r.mUserId != userId ||
-                    r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
-                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch root " + r);
-                continue;
-            }
-            if (!r.hasCompatibleActivityType(target)) {
-                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch activity type");
-                continue;
-            }
-
-            final Intent taskIntent = task.intent;
-            final Intent affinityIntent = task.affinityIntent;
-            final boolean taskIsDocument;
-            final Uri taskDocumentData;
-            if (taskIntent != null && taskIntent.isDocument()) {
-                taskIsDocument = true;
-                taskDocumentData = taskIntent.getData();
-            } else if (affinityIntent != null && affinityIntent.isDocument()) {
-                taskIsDocument = true;
-                taskDocumentData = affinityIntent.getData();
-            } else {
-                taskIsDocument = false;
-                taskDocumentData = null;
-            }
-
-            if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Comparing existing cls="
-                    + (task.realActivity != null ? task.realActivity.flattenToShortString() : "")
-                    + "/aff=" + r.getTask().rootAffinity + " to new cls="
-                    + intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity);
-            // TODO Refactor to remove duplications. Check if logic can be simplified.
-            if (task.realActivity != null && task.realActivity.compareTo(cls) == 0
-                    && Objects.equals(documentData, taskDocumentData)) {
-                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
-                //dump();
-                if (DEBUG_TASKS) Slog.d(TAG_TASKS,
-                        "For Intent " + intent + " bringing to top: " + r.intent);
-                result.mRecord = r;
-                result.mIdealMatch = true;
-                break;
-            } else if (affinityIntent != null && affinityIntent.getComponent() != null &&
-                    affinityIntent.getComponent().compareTo(cls) == 0 &&
-                    Objects.equals(documentData, taskDocumentData)) {
-                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
-                //dump();
-                if (DEBUG_TASKS) Slog.d(TAG_TASKS,
-                        "For Intent " + intent + " bringing to top: " + r.intent);
-                result.mRecord = r;
-                result.mIdealMatch = true;
-                break;
-            } else if (!isDocument && !taskIsDocument
-                    && result.mRecord == null && task.rootAffinity != null) {
-                if (task.rootAffinity.equals(target.taskAffinity)) {
-                    if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity candidate!");
-                    // It is possible for multiple tasks to have the same root affinity especially
-                    // if they are in separate stacks. We save off this candidate, but keep looking
-                    // to see if there is a better candidate.
-                    result.mRecord = r;
-                    result.mIdealMatch = false;
-                }
-            } else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: " + task);
-        }
-    }
-
-    /**
-     * Returns the first activity (starting from the top of the stack) that
-     * is the same as the given activity.  Returns null if no such activity
-     * is found.
-     */
-    ActivityRecord findActivityLocked(Intent intent, ActivityInfo info,
-                                      boolean compareIntentFilters) {
-        ComponentName cls = intent.getComponent();
-        if (info.targetActivity != null) {
-            cls = new ComponentName(info.packageName, info.targetActivity);
-        }
-        final int userId = UserHandle.getUserId(info.applicationInfo.uid);
-
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = getChildAt(taskNdx);
-            for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = task.getChildAt(activityNdx);
-                if (!r.okToShowLocked()) {
-                    continue;
-                }
-                if (!r.finishing && r.mUserId == userId) {
-                    if (compareIntentFilters) {
-                        if (r.intent.filterEquals(intent)) {
-                            return r;
-                        }
-                    } else {
-                        if (r.intent.getComponent().equals(cls)) {
-                            return r;
-                        }
-                    }
-                }
-            }
-        }
-
-        return null;
-    }
-
     // TODO: Should each user have there own stacks?
     @Override
     void switchUser(int userId) {
@@ -1404,35 +1418,13 @@
 
     void awakeFromSleepingLocked() {
         // Ensure activities are no longer sleeping.
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = getChildAt(taskNdx);
-            for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = task.getChildAt(activityNdx);
-                r.setSleeping(false);
-            }
-        }
+        forAllActivities((Consumer<ActivityRecord>) (r) -> r.setSleeping(false));
         if (mPausingActivity != null) {
             Slog.d(TAG, "awakeFromSleepingLocked: previously pausing activity didn't pause");
             activityPausedLocked(mPausingActivity.appToken, true);
         }
     }
 
-    void updateActivityApplicationInfoLocked(ApplicationInfo aInfo) {
-        final String packageName = aInfo.packageName;
-        final int userId = UserHandle.getUserId(aInfo.uid);
-
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = getChildAt(taskNdx);
-            for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord ar = task.getChildAt(activityNdx);
-
-                if ((userId == ar.mUserId) && packageName.equals(ar.packageName)) {
-                    ar.updateApplicationInfo(aInfo);
-                }
-            }
-        }
-    }
-
     void checkReadyForSleep() {
         if (shouldSleepActivities() && goToSleepIfPossible(false /* shuttingDown */)) {
             mStackSupervisor.checkReadyForSleepLocked(true /* allowDelay */);
@@ -1498,15 +1490,11 @@
 
         // Make sure any paused or stopped but visible activities are now sleeping.
         // This ensures that the activity's onStop() is called.
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = getChildAt(taskNdx);
-            for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = task.getChildAt(activityNdx);
-                if (r.isState(STARTED, STOPPING, STOPPED, PAUSED, PAUSING)) {
-                    r.setSleeping(true);
-                }
+        forAllActivities((r) -> {
+            if (r.isState(STARTED, STOPPING, STOPPED, PAUSED, PAUSING)) {
+                r.setSleeping(true);
             }
-        }
+        });
     }
 
     private boolean containsActivityFromStack(List<ActivityRecord> rs) {
@@ -1586,7 +1574,7 @@
         if (prev.attachedToProcess()) {
             if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
             try {
-                EventLogTags.writeAmPauseActivity(prev.mUserId, System.identityHashCode(prev),
+                EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev),
                         prev.shortComponentName, "userLeaving=" + userLeaving);
 
                 mService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
@@ -1663,10 +1651,9 @@
                 }
                 return;
             } else {
-                EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
-                        r.mUserId, System.identityHashCode(r), r.shortComponentName,
-                        mPausingActivity != null
-                            ? mPausingActivity.shortComponentName : "(none)");
+                EventLogTags.writeWmFailedToPause(r.mUserId, System.identityHashCode(r),
+                        r.shortComponentName, mPausingActivity != null
+                                ? mPausingActivity.shortComponentName : "(none)");
                 if (r.isState(PAUSING)) {
                     r.setState(PAUSED, "activityPausedLocked");
                     if (r.finishing) {
@@ -1783,31 +1770,32 @@
         if (!isAttached() || mForceHidden) {
             return true;
         }
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = getChildAt(taskNdx);
-            for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = task.getChildAt(activityNdx);
+        final PooledPredicate p = PooledLambda.obtainPredicate(ActivityStack::isOpaqueActivity,
+                PooledLambda.__(ActivityRecord.class), starting);
+        final ActivityRecord opaque = getActivity(p);
+        p.recycle();
+        return opaque == null;
+    }
 
-                if (r.finishing) {
-                    // We don't factor in finishing activities when determining translucency since
-                    // they will be gone soon.
-                    continue;
-                }
-
-                if (!r.visibleIgnoringKeyguard && r != starting) {
-                    // Also ignore invisible activities that are not the currently starting
-                    // activity (about to be visible).
-                    continue;
-                }
-
-                if (r.occludesParent() || r.hasWallpaper) {
-                    // Stack isn't translucent if it has at least one fullscreen activity
-                    // that is visible.
-                    return false;
-                }
-            }
+    private static boolean isOpaqueActivity(ActivityRecord r, ActivityRecord starting) {
+        if (r.finishing) {
+            // We don't factor in finishing activities when determining translucency since
+            // they will be gone soon.
+            return false;
         }
-        return true;
+
+        if (!r.visibleIgnoringKeyguard && r != starting) {
+            // Also ignore invisible activities that are not the currently starting
+            // activity (about to be visible).
+            return false;
+        }
+
+        if (r.occludesParent() || r.hasWallpaper) {
+            // Stack isn't translucent if it has at least one fullscreen activity
+            // that is visible.
+            return true;
+        }
+        return false;
     }
 
     boolean isTopStackOnDisplay() {
@@ -1859,8 +1847,8 @@
         boolean shouldBeVisible = true;
         final int windowingMode = getWindowingMode();
         final boolean isAssistantType = isActivityTypeAssistant();
-        for (int i = display.getChildCount() - 1; i >= 0; --i) {
-            final ActivityStack other = display.getChildAt(i);
+        for (int i = display.getStackCount() - 1; i >= 0; --i) {
+            final ActivityStack other = display.getStackAt(i);
             final boolean hasRunningActivities = other.topRunningActivityLocked() != null;
             if (other == this) {
                 // Should be visible if there is no other stack occluding it, unless it doesn't
@@ -1962,20 +1950,6 @@
                 : STACK_VISIBILITY_VISIBLE;
     }
 
-    final int rankTaskLayers(int baseLayer) {
-        int layer = 0;
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = getChildAt(taskNdx);
-            ActivityRecord r = task.topRunningActivityLocked();
-            if (r == null || r.finishing || !r.mVisibleRequested) {
-                task.mLayerRank = -1;
-            } else {
-                task.mLayerRank = baseLayer + layer++;
-            }
-        }
-        return layer;
-    }
-
     /**
      * Make sure that all activities that need to be visible in the stack (that is, they
      * currently can be seen by the user) actually are and update their configuration.
@@ -2010,12 +1984,6 @@
         }
     }
 
-    void addStartingWindowsForVisibleActivities(boolean taskSwitch) {
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            getChildAt(taskNdx).addStartingWindowsForVisibleActivities(taskSwitch);
-        }
-    }
-
     /**
      * @return true if the top visible activity wants to occlude the Keyguard, false otherwise
      */
@@ -2131,18 +2099,6 @@
         mHandler.sendEmptyMessageDelayed(TRANSLUCENT_TIMEOUT_MSG, TRANSLUCENT_CONVERSION_TIMEOUT);
     }
 
-    void clearOtherAppTimeTrackers(AppTimeTracker except) {
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = getChildAt(taskNdx);
-            for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = task.getChildAt(activityNdx);
-                if ( r.appTimeTracker != except) {
-                    r.appTimeTracker = null;
-                }
-            }
-        }
-    }
-
     /**
      * Called as activities below the top translucent activity are redrawn. When the last one is
      * redrawn notify the top activity by calling
@@ -2190,50 +2146,8 @@
      */
     boolean checkBehindFullscreenActivity(ActivityRecord toCheck,
             Consumer<ActivityRecord> handleBehindFullscreenActivity) {
-        boolean aboveTop = true;
-        boolean behindFullscreenActivity = false;
-
-        if (!shouldBeVisible(null)) {
-            // The stack is not visible, so no activity in it should be displaying a starting
-            // window. Mark all activities below top and behind fullscreen.
-            aboveTop = false;
-            behindFullscreenActivity = true;
-        }
-
-        final boolean handlingOccluded = toCheck == null && handleBehindFullscreenActivity != null;
-        if (!handlingOccluded && behindFullscreenActivity) {
-            return true;
-        }
-
-        final ActivityRecord topActivity = topRunningActivityLocked();
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = getChildAt(taskNdx);
-            for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = task.getChildAt(activityNdx);
-                if (aboveTop) {
-                    if (r == topActivity) {
-                        if (r == toCheck) {
-                            // It is the top activity in a visible stack.
-                            return false;
-                        }
-                        aboveTop = false;
-                    }
-                    behindFullscreenActivity |= r.occludesParent();
-                    continue;
-                }
-
-                if (handlingOccluded) {
-                    handleBehindFullscreenActivity.accept(r);
-                } else if (r == toCheck) {
-                    return behindFullscreenActivity;
-                } else if (behindFullscreenActivity) {
-                    // It is occluded before {@param toCheck} is found.
-                    return true;
-                }
-                behindFullscreenActivity |= r.occludesParent();
-            }
-        }
-        return behindFullscreenActivity;
+        return mCheckBehindFullscreenActivityHelper.process(
+                toCheck, handleBehindFullscreenActivity);
     }
 
     /**
@@ -2659,9 +2573,8 @@
                 // Clear app token stopped state in window manager if needed.
                 next.notifyAppResumed(next.stopped);
 
-                EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.mUserId,
-                        System.identityHashCode(next), next.getTask().mTaskId,
-                        next.shortComponentName);
+                EventLogTags.writeWmResumeActivity(next.mUserId, System.identityHashCode(next),
+                        next.getTask().mTaskId, next.shortComponentName);
 
                 next.sleeping = false;
                 mService.getAppWarningsLocked().onResumeActivity(next);
@@ -2792,7 +2705,7 @@
                     }
                     break;
                 } else if (!isOccluded) {
-                    isOccluded = task.forAllActivities(ActivityRecord::occludesParent);
+                    isOccluded = task.getActivity(ActivityRecord::occludesParent) != null;
                 }
             }
         }
@@ -2817,7 +2730,7 @@
 
         // The transition animation and starting window are not needed if {@code allowMoveToFront}
         // is false, because the activity won't be visible.
-        if ((!isHomeOrRecentsStack() || numActivities() > 0) && allowMoveToFront) {
+        if ((!isHomeOrRecentsStack() || hasActivity()) && allowMoveToFront) {
             final DisplayContent dc = getDisplay().mDisplayContent;
             if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                     "Prepare open transition: starting " + r);
@@ -2920,8 +2833,7 @@
         return true;
     }
 
-    private boolean isTaskSwitch(ActivityRecord r,
-            ActivityRecord topFocusedActivity) {
+    private boolean isTaskSwitch(ActivityRecord r, ActivityRecord topFocusedActivity) {
         return topFocusedActivity != null && r.getTask() != topFocusedActivity.getTask();
     }
 
@@ -3001,23 +2913,6 @@
         return stack;
     }
 
-    /** Finish all activities that were started for result from the specified activity. */
-    final void finishSubActivityLocked(ActivityRecord self, String resultWho, int requestCode) {
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = getChildAt(taskNdx);
-            for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = task.getChildAt(activityNdx);
-                if (r.resultTo == self && r.requestCode == requestCode) {
-                    if ((r.resultWho == null && resultWho == null) ||
-                        (r.resultWho != null && r.resultWho.equals(resultWho))) {
-                        r.finishIfPossible("request-sub", false /* oomAdj */);
-                    }
-                }
-            }
-        }
-        mService.updateOomAdj();
-    }
-
     /**
      * Finish the topmost activity that belongs to the crashed app. We may also finish the activity
      * that requested launch of the crashed one to prevent launch-crash loop.
@@ -3028,103 +2923,84 @@
      */
     final Task finishTopCrashedActivityLocked(WindowProcessController app, String reason) {
         ActivityRecord r = topRunningActivityLocked();
-        Task finishedTask = null;
         if (r == null || r.app != app) {
             return null;
         }
         Slog.w(TAG, "  Force finishing activity "
                 + r.intent.getComponent().flattenToShortString());
-        finishedTask = r.getTask();
-        int taskNdx = mChildren.indexOf(finishedTask);
-        final Task task = finishedTask;
-        int activityNdx = task.mChildren.indexOf(r);
+        Task finishedTask = r.getTask();
         getDisplay().mDisplayContent.prepareAppTransition(
                 TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
         r.finishIfPossible(reason, false /* oomAdj */);
-        finishedTask = task;
-        // Also terminate any activities below it that aren't yet
-        // stopped, to avoid a situation where one will get
-        // re-start our crashing activity once it gets resumed again.
-        --activityNdx;
-        if (activityNdx < 0) {
-            do {
-                --taskNdx;
-                if (taskNdx < 0) {
-                    break;
-                }
-                activityNdx = getChildAt(taskNdx).getChildCount() - 1;
-            } while (activityNdx < 0);
-        }
-        if (activityNdx >= 0) {
-            r = getChildAt(taskNdx).getChildAt(activityNdx);
-            if (r.isState(STARTED, RESUMED, PAUSING, PAUSED)) {
-                if (!r.isActivityTypeHome() || mService.mHomeProcess != r.app) {
+
+        // Also terminate any activities below it that aren't yet stopped, to avoid a situation
+        // where one will get re-start our crashing activity once it gets resumed again.
+        final ActivityRecord activityBelow = getActivityBelow(r);
+        if (activityBelow != null) {
+            if (activityBelow.isState(STARTED, RESUMED, PAUSING, PAUSED)) {
+                if (!activityBelow.isActivityTypeHome()
+                        || mService.mHomeProcess != activityBelow.app) {
                     Slog.w(TAG, "  Force finishing activity "
-                            + r.intent.getComponent().flattenToShortString());
-                    r.finishIfPossible(reason, false /* oomAdj */);
+                            + activityBelow.intent.getComponent().flattenToShortString());
+                    activityBelow.finishIfPossible(reason, false /* oomAdj */);
                 }
             }
         }
+
         return finishedTask;
     }
 
-    final void finishVoiceTask(IVoiceInteractionSession session) {
-        IBinder sessionBinder = session.asBinder();
-        boolean didOne = false;
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            Task tr = getChildAt(taskNdx);
-            if (tr.voiceSession != null && tr.voiceSession.asBinder() == sessionBinder) {
-                for (int activityNdx = tr.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                    ActivityRecord r = tr.getChildAt(activityNdx);
-                    if (!r.finishing) {
-                        r.finishIfPossible("finish-voice", false /* oomAdj */);
-                        didOne = true;
-                    }
-                }
-            } else {
-                // Check if any of the activities are using voice
-                for (int activityNdx = tr.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                    ActivityRecord r = tr.getChildAt(activityNdx);
-                    if (r.voiceSession != null && r.voiceSession.asBinder() == sessionBinder) {
-                        // Inform of cancellation
-                        r.clearVoiceSessionLocked();
-                        try {
-                            r.app.getThread().scheduleLocalVoiceInteractionStarted(
-                                    r.appToken, null);
-                        } catch (RemoteException re) {
-                            // Ok
-                        }
-                        mService.finishRunningVoiceLocked();
-                        break;
-                    }
-                }
-            }
-        }
+    void finishVoiceTask(IVoiceInteractionSession session) {
+        final PooledConsumer c = PooledLambda.obtainConsumer(ActivityStack::finishIfVoiceTask,
+                PooledLambda.__(Task.class), session.asBinder());
+        forAllTasks(c);
+        c.recycle();
+    }
 
-        if (didOne) {
-            mService.updateOomAdj();
+    private static void finishIfVoiceTask(Task tr, IBinder binder) {
+        if (tr.voiceSession != null && tr.voiceSession.asBinder() == binder) {
+            tr.forAllActivities((r) -> {
+                if (r.finishing) return;
+                r.finishIfPossible("finish-voice", false /* oomAdj */);
+                tr.mAtmService.updateOomAdj();
+            });
+        } else {
+            // Check if any of the activities are using voice
+            final PooledFunction f = PooledLambda.obtainFunction(
+                    ActivityStack::finishIfVoiceActivity, PooledLambda.__(ActivityRecord.class),
+                    binder);
+            tr.forAllActivities(f);
+            f.recycle();
         }
     }
 
+    private static boolean finishIfVoiceActivity(ActivityRecord r, IBinder binder) {
+        if (r.voiceSession == null || r.voiceSession.asBinder() != binder) return false;
+        // Inform of cancellation
+        r.clearVoiceSessionLocked();
+        try {
+            r.app.getThread().scheduleLocalVoiceInteractionStarted(r.appToken, null);
+        } catch (RemoteException re) {
+            // Ok Boomer...
+        }
+        r.mAtmService.finishRunningVoiceLocked();
+        return true;
+    }
+
     /** Finish all activities in the stack without waiting. */
     void finishAllActivitiesImmediately() {
-        boolean noActivitiesInStack = true;
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = getChildAt(taskNdx);
-            for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = task.getChildAt(activityNdx);
-                noActivitiesInStack = false;
-                Slog.d(TAG, "finishAllActivitiesImmediatelyLocked: finishing " + r);
-                r.destroyIfPossible("finishAllActivitiesImmediatelyLocked");
-            }
-        }
-        if (noActivitiesInStack) {
+        if (!hasChild()) {
             removeIfPossible();
+            return;
         }
+        forAllActivities((r) -> {
+            Slog.d(TAG, "finishAllActivitiesImmediatelyLocked: finishing " + r);
+            r.destroyIfPossible("finishAllActivitiesImmediately");
+        });
     }
 
     /** @return true if the stack behind this one is a standard activity type. */
-    boolean inFrontOfStandardStack() {
+    private boolean inFrontOfStandardStack() {
         final ActivityDisplay display = getDisplay();
         if (display == null) {
             return false;
@@ -3133,7 +3009,7 @@
         if (index == 0) {
             return false;
         }
-        final ActivityStack stackBehind = display.getChildAt(index - 1);
+        final ActivityStack stackBehind = display.getStackAt(index - 1);
         return stackBehind.isActivityTypeStandard();
     }
 
@@ -3171,28 +3047,25 @@
         return false;
     }
 
-    final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode,
+    boolean navigateUpTo(ActivityRecord srec, Intent destIntent, int resultCode,
             Intent resultData) {
         final Task task = srec.getTask();
-        final ArrayList<ActivityRecord> activities = task.mChildren;
-        final int start = activities.indexOf(srec);
-        if (!mChildren.contains(task) || (start < 0)) {
+
+        if (!mChildren.contains(task) || !task.hasChild(srec)) {
             return false;
         }
-        int finishTo = start - 1;
-        ActivityRecord parent = finishTo < 0 ? null : task.getChildAt(finishTo);
+
+        ActivityRecord parent = task.getActivityBelow(srec);
         boolean foundParentInTask = false;
         final ComponentName dest = destIntent.getComponent();
-        if (start > 0 && dest != null) {
-            for (int i = finishTo; i >= 0; i--) {
-                ActivityRecord r = task.getChildAt(i);
-                if (r.info.packageName.equals(dest.getPackageName()) &&
-                        r.info.name.equals(dest.getClassName())) {
-                    finishTo = i;
-                    parent = r;
-                    foundParentInTask = true;
-                    break;
-                }
+        if (task.getBottomMostActivity() != srec && dest != null) {
+            final ActivityRecord candidate = task.getActivity((ar) ->
+                    ar.info.packageName.equals(dest.getPackageName()) &&
+                    ar.info.name.equals(dest.getClassName()), srec, false /*includeBoundary*/,
+                    true /*traverseTopToBottom*/);
+            if (candidate != null) {
+                parent = candidate;
+                foundParentInTask = true;
             }
         }
 
@@ -3217,13 +3090,24 @@
             }
         }
         final long origId = Binder.clearCallingIdentity();
-        for (int i = start; i > finishTo; i--) {
-            final ActivityRecord r = activities.get(i);
-            r.finishIfPossible(resultCode, resultData, "navigate-up", true /* oomAdj */);
+
+        final int[] resultCodeHolder = new int[1];
+        resultCodeHolder[0] = resultCode;
+        final Intent[] resultDataHolder = new Intent[1];
+        resultDataHolder[0] = resultData;
+        final ActivityRecord finalParent = parent;
+        task.forAllActivities((ar) -> {
+            if (ar == finalParent) return true;
+
+            ar.finishIfPossible(
+                    resultCodeHolder[0], resultDataHolder[0], "navigate-up", true /* oomAdj */);
             // Only return the supplied result for the first activity finished
-            resultCode = Activity.RESULT_CANCELED;
-            resultData = null;
-        }
+            resultCodeHolder[0] = Activity.RESULT_CANCELED;
+            resultDataHolder[0] = null;
+            return false;
+        }, srec, true, true);
+        resultCode = resultCodeHolder[0];
+        resultData = resultDataHolder[0];
 
         if (parent != null && foundParentInTask) {
             final int parentLaunchMode = parent.info.launchMode;
@@ -3290,7 +3174,6 @@
         }
     }
 
-    /// HANDLER INTERFACE BEGIN
     void removeTimeoutsForActivity(ActivityRecord r) {
         mStackSupervisor.removeTimeoutsForActivityLocked(r);
         removePauseTimeoutForActivity(r);
@@ -3348,86 +3231,33 @@
     }
     /// HANDLER INTERFACE END
 
-    private void destroyActivitiesLocked(WindowProcessController owner, String reason) {
-        boolean lastIsOpaque = false;
-        boolean activityRemoved = false;
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = getChildAt(taskNdx);
-            for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = task.getChildAt(activityNdx);
-                if (r.finishing) {
-                    continue;
-                }
-                if (r.occludesParent()) {
-                    lastIsOpaque = true;
-                }
-                if (owner != null && r.app != owner) {
-                    continue;
-                }
-                if (!lastIsOpaque) {
-                    continue;
-                }
-                if (r.isDestroyable()) {
-                    if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Destroying " + r
-                            + " in state " + r.getState()
-                            + " resumed=" + mResumedActivity
-                            + " pausing=" + mPausingActivity + " for reason " + reason);
-                    if (r.destroyImmediately(true /* removeFromTask */, reason)) {
-                        activityRemoved = true;
-                    }
-                }
-            }
-        }
-        if (activityRemoved) {
+    private void destroyActivities(WindowProcessController owner, String reason) {
+        try {
+            mStackSupervisor.beginDeferResume();
+
+            final PooledConsumer c = PooledLambda.obtainConsumer(ActivityStack::destroyActivity,
+                    PooledLambda.__(ActivityRecord.class), owner, reason);
+            forAllActivities(c);
+            c.recycle();
+        } finally {
+            mStackSupervisor.endDeferResume();
             mRootActivityContainer.resumeFocusedStacksTopActivities();
         }
     }
 
-    final int releaseSomeActivitiesLocked(WindowProcessController app, ArraySet<Task> tasks,
-            String reason) {
-        // Iterate over tasks starting at the back (oldest) first.
-        if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Trying to release some activities in " + app);
-        int maxTasks = tasks.size() / 4;
-        if (maxTasks < 1) {
-            maxTasks = 1;
-        }
-        int numReleased = 0;
-        for (int taskNdx = 0; taskNdx < getChildCount() && maxTasks > 0; taskNdx++) {
-            final Task task = getChildAt(taskNdx);
-            if (!tasks.contains(task)) {
-                continue;
-            }
-            if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Looking for activities to release in " + task);
-            int curNum = 0;
-            for (int actNdx = 0; actNdx < task.getChildCount(); actNdx++) {
-                final ActivityRecord activity = task.getChildAt(actNdx);
-                if (activity.app == app && activity.isDestroyable()) {
-                    if (DEBUG_RELEASE) Slog.v(TAG_RELEASE, "Destroying " + activity
-                            + " in state " + activity.getState() + " resumed=" + mResumedActivity
-                            + " pausing=" + mPausingActivity + " for reason " + reason);
-                    activity.destroyImmediately(true /* removeFromApp */, reason);
-                    if (task.getChildAt(actNdx) != activity) {
-                        // Was removed from list, back up so we don't miss the next one.
-                        actNdx--;
-                    }
-                    curNum++;
-                }
-            }
-            if (curNum > 0) {
-                numReleased += curNum;
-                maxTasks--;
-                if (getChildAt(taskNdx) != task) {
-                    // The entire task got removed, back up so we don't miss the next one.
-                    taskNdx--;
-                }
-            }
-        }
-        if (DEBUG_RELEASE) Slog.d(TAG_RELEASE,
-                "Done releasing: did " + numReleased + " activities");
-        return numReleased;
+    private static void destroyActivity(
+            ActivityRecord r, WindowProcessController owner, String reason) {
+        if (r.finishing || (owner != null && r.app != owner) || !r.isDestroyable()) return;
+
+        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Destroying " + r
+                + " in state " + r.getState()
+                + " resumed=" + r.getStack().mResumedActivity
+                + " pausing=" + r.getStack().mPausingActivity + " for reason " + reason);
+
+        r.destroyImmediately(true /* removeFromTask */, reason);
     }
 
-    private void removeHistoryRecordsForAppLocked(ArrayList<ActivityRecord> list,
+    private void removeHistoryRecordsForApp(ArrayList<ActivityRecord> list,
             WindowProcessController app, String listName) {
         int i = list.size();
         if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
@@ -3444,108 +3274,15 @@
         }
     }
 
-    private boolean removeHistoryRecordsForAppLocked(WindowProcessController app) {
-        removeHistoryRecordsForAppLocked(mLruActivities, app, "mLruActivities");
-        removeHistoryRecordsForAppLocked(mStackSupervisor.mStoppingActivities, app,
+    private boolean removeHistoryRecordsForApp(WindowProcessController app) {
+        removeHistoryRecordsForApp(mLruActivities, app, "mLruActivities");
+        removeHistoryRecordsForApp(mStackSupervisor.mStoppingActivities, app,
                 "mStoppingActivities");
-        removeHistoryRecordsForAppLocked(mStackSupervisor.mGoingToSleepActivities, app,
+        removeHistoryRecordsForApp(mStackSupervisor.mGoingToSleepActivities, app,
                 "mGoingToSleepActivities");
-        removeHistoryRecordsForAppLocked(mStackSupervisor.mFinishingActivities, app,
+        removeHistoryRecordsForApp(mStackSupervisor.mFinishingActivities, app,
                 "mFinishingActivities");
-
-        final boolean isProcessRemoved = app.isRemoved();
-        if (isProcessRemoved) {
-            // The package of the died process should be force-stopped, so make its activities as
-            // finishing to prevent the process from being started again if the next top (or being
-            // visible) activity also resides in the same process.
-            app.makeFinishingForProcessRemoved();
-        }
-
-        boolean hasVisibleActivities = false;
-
-        // Clean out the history list.
-        int i = numActivities();
-        if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
-                "Removing app " + app + " from history with " + i + " entries");
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final ArrayList<ActivityRecord> activities = getChildAt(taskNdx).mChildren;
-            mTmpActivities.clear();
-            mTmpActivities.addAll(activities);
-
-            while (!mTmpActivities.isEmpty()) {
-                final int targetIndex = mTmpActivities.size() - 1;
-                final ActivityRecord r = mTmpActivities.remove(targetIndex);
-                if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
-                        "Record #" + targetIndex + " " + r + ": app=" + r.app);
-
-                if (r.app == app) {
-                    if (r.isVisible() || r.mVisibleRequested) {
-                        // While an activity launches a new activity, it's possible that the old
-                        // activity is already requested to be hidden (mVisibleRequested=false), but
-                        // this visibility is not yet committed, so isVisible()=true.
-                        hasVisibleActivities = true;
-                    }
-                    final boolean remove;
-                    if ((r.mRelaunchReason == RELAUNCH_REASON_WINDOWING_MODE_RESIZE
-                            || r.mRelaunchReason == RELAUNCH_REASON_FREE_RESIZE)
-                            && r.launchCount < 3 && !r.finishing) {
-                        // If the process crashed during a resize, always try to relaunch it, unless
-                        // it has failed more than twice. Skip activities that's already finishing
-                        // cleanly by itself.
-                        remove = false;
-                    } else if ((!r.hasSavedState() && !r.stateNotNeeded
-                            && !r.isState(ActivityState.RESTARTING_PROCESS)) || r.finishing) {
-                        // Don't currently have state for the activity, or
-                        // it is finishing -- always remove it.
-                        remove = true;
-                    } else if (!r.mVisibleRequested && r.launchCount > 2
-                            && r.lastLaunchTime > (SystemClock.uptimeMillis() - 60000)) {
-                        // We have launched this activity too many times since it was
-                        // able to run, so give up and remove it.
-                        // (Note if the activity is visible, we don't remove the record.
-                        // We leave the dead window on the screen but the process will
-                        // not be restarted unless user explicitly tap on it.)
-                        remove = true;
-                    } else {
-                        // The process may be gone, but the activity lives on!
-                        remove = false;
-                    }
-                    if (remove) {
-                        if (DEBUG_ADD_REMOVE || DEBUG_CLEANUP) Slog.i(TAG_ADD_REMOVE,
-                                "Removing activity " + r + " from stack at " + i
-                                + ": hasSavedState=" + r.hasSavedState()
-                                + " stateNotNeeded=" + r.stateNotNeeded
-                                + " finishing=" + r.finishing
-                                + " state=" + r.getState() + " callers=" + Debug.getCallers(5));
-                        if (!r.finishing || isProcessRemoved) {
-                            Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
-                            EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
-                                    r.mUserId, System.identityHashCode(r),
-                                    r.getTask().mTaskId, r.shortComponentName,
-                                    "proc died without state saved");
-                        }
-                    } else {
-                        // We have the current state for this activity, so
-                        // it can be restarted later when needed.
-                        if (DEBUG_ALL) Slog.v(TAG, "Keeping entry, setting app to null");
-                        if (DEBUG_APP) Slog.v(TAG_APP,
-                                "Clearing app during removeHistory for activity " + r);
-                        r.app = null;
-                        // Set nowVisible to previous visible state. If the app was visible while
-                        // it died, we leave the dead window on screen so it's basically visible.
-                        // This is needed when user later tap on the dead window, we need to stop
-                        // other apps when user transfers focus to the restarted activity.
-                        r.nowVisible = r.mVisibleRequested;
-                    }
-                    r.cleanUp(true /* cleanServices */, true /* setState */);
-                    if (remove) {
-                        r.removeFromHistory("appDied");
-                    }
-                }
-            }
-        }
-
-        return hasVisibleActivities;
+        return mRemoveHistoryRecordsForApp.process(app);
     }
 
     private void updateTransitLocked(int transit, ActivityOptions options) {
@@ -3565,8 +3302,7 @@
         if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);
 
         final ActivityStack topStack = getDisplay().getTopStack();
-        final ActivityRecord topActivity = topStack != null
-                ? topStack.getTopNonFinishingActivity() : null;
+        final ActivityRecord topActivity = topStack != null ? topStack.getTopNonFinishingActivity() : null;
         final int numTasks = getChildCount();
         final int index = mChildren.indexOf(tr);
         if (numTasks == 0 || index < 0)  {
@@ -3581,9 +3317,10 @@
 
         if (timeTracker != null) {
             // The caller wants a time tracker associated with this task.
-            for (int i = tr.getChildCount() - 1; i >= 0; i--) {
-                tr.getChildAt(i).appTimeTracker = timeTracker;
-            }
+            final PooledConsumer c = PooledLambda.obtainConsumer(ActivityRecord::setAppTimeTracker,
+                    PooledLambda.__(ActivityRecord.class), timeTracker);
+            tr.forAllActivities(c);
+            c.recycle();
         }
 
         try {
@@ -3634,7 +3371,7 @@
             }
 
             mRootActivityContainer.resumeFocusedStacksTopActivities();
-            EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.mUserId, tr.mTaskId);
+            EventLogTags.writeWmTaskToFront(tr.mUserId, tr.mTaskId);
             mService.getTaskChangeNotificationController().notifyTaskMovedToFront(tr.getTaskInfo());
         } finally {
             getDisplay().continueUpdateImeTarget();
@@ -3717,38 +3454,8 @@
     /**
      * Ensures all visible activities at or below the input activity have the right configuration.
      */
-    void ensureVisibleActivitiesConfigurationLocked(ActivityRecord start, boolean preserveWindow) {
-        if (start == null || !start.mVisibleRequested) {
-            return;
-        }
-
-        final Task startTask = start.getTask();
-        boolean behindFullscreen = false;
-        boolean updatedConfig = false;
-
-        for (int taskIndex = mChildren.indexOf(startTask); taskIndex >= 0; --taskIndex) {
-            final Task task = getChildAt(taskIndex);
-            final ArrayList<ActivityRecord> activities = task.mChildren;
-            int activityIndex = (start.getTask() == task)
-                    ? activities.indexOf(start) : activities.size() - 1;
-            for (; activityIndex >= 0; --activityIndex) {
-                final ActivityRecord r = activities.get(activityIndex);
-                updatedConfig |= r.ensureActivityConfiguration(0 /* globalChanges */,
-                        preserveWindow);
-                if (r.occludesParent()) {
-                    behindFullscreen = true;
-                    break;
-                }
-            }
-            if (behindFullscreen) {
-                break;
-            }
-        }
-        if (updatedConfig) {
-            // Ensure the resumed state of the focus activity if we updated the configuration of
-            // any activity.
-            mRootActivityContainer.resumeFocusedStacksTopActivities();
-        }
+    void ensureVisibleActivitiesConfiguration(ActivityRecord start, boolean preserveWindow) {
+        mEnsureVisibleActivitiesConfigHelper.process(start, preserveWindow);
     }
 
     // TODO: Can only be called from special methods in ActivityStackSupervisor.
@@ -3780,7 +3487,7 @@
             setBounds(bounds);
 
             if (!deferResume) {
-                ensureVisibleActivitiesConfigurationLocked(
+                ensureVisibleActivitiesConfiguration(
                         topRunningActivityLocked(), preserveWindows);
             }
         } finally {
@@ -3824,85 +3531,23 @@
         }
     }
 
-    boolean willActivityBeVisibleLocked(IBinder token) {
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = getChildAt(taskNdx);
-            for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = task.getChildAt(activityNdx);
-                if (r.appToken == token) {
-                    return true;
-                }
-                if (r.occludesParent() && !r.finishing) {
-                    return false;
-                }
-            }
-        }
+    boolean willActivityBeVisible(IBinder token) {
         final ActivityRecord r = ActivityRecord.forTokenLocked(token);
         if (r == null) {
             return false;
         }
-        if (r.finishing) Slog.e(TAG, "willActivityBeVisibleLocked: Returning false,"
+
+        // See if there is an occluding activity on-top of this one.
+        final ActivityRecord occludingActivity = getActivity((ar) ->
+                ar.occludesParent() && !ar.finishing,
+                r, false /*includeBoundary*/, true /*traverseTopToBottom*/);
+        if (occludingActivity != null) return false;
+
+        if (r.finishing) Slog.e(TAG, "willActivityBeVisible: Returning false,"
                 + " would have returned true for r=" + r);
         return !r.finishing;
     }
 
-    void closeSystemDialogsLocked() {
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = getChildAt(taskNdx);
-            for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = task.getChildAt(activityNdx);
-                if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
-                    r.finishIfPossible("close-sys", true /* oomAdj */);
-                }
-            }
-        }
-    }
-
-    boolean finishDisabledPackageActivitiesLocked(String packageName, Set<String> filterByClasses,
-            boolean doit, boolean evenPersistent, int userId) {
-        boolean didSomething = false;
-        Task lastTask = null;
-        ComponentName homeActivity = null;
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final ArrayList<ActivityRecord> activities = getChildAt(taskNdx).mChildren;
-            mTmpActivities.clear();
-            mTmpActivities.addAll(activities);
-
-            while (!mTmpActivities.isEmpty()) {
-                ActivityRecord r = mTmpActivities.remove(0);
-                final boolean sameComponent =
-                        (r.packageName.equals(packageName) && (filterByClasses == null
-                                || filterByClasses.contains(r.mActivityComponent.getClassName())))
-                        || (packageName == null && r.mUserId == userId);
-                if ((userId == UserHandle.USER_ALL || r.mUserId == userId)
-                        && (sameComponent || r.getTask() == lastTask)
-                        && (r.app == null || evenPersistent || !r.app.isPersistent())) {
-                    if (!doit) {
-                        if (r.finishing) {
-                            // If this activity is just finishing, then it is not
-                            // interesting as far as something to stop.
-                            continue;
-                        }
-                        return true;
-                    }
-                    if (r.isActivityTypeHome()) {
-                        if (homeActivity != null && homeActivity.equals(r.mActivityComponent)) {
-                            Slog.i(TAG, "Skip force-stop again " + r);
-                            continue;
-                        } else {
-                            homeActivity = r.mActivityComponent;
-                        }
-                    }
-                    didSomething = true;
-                    Slog.i(TAG, "  Force finishing activity " + r);
-                    lastTask = r.getTask();
-                    r.finishIfPossible("force-stop", true);
-                }
-            }
-        }
-        return didSomething;
-    }
-
     /**
      * @return The set of running tasks through {@param tasksOut} that are available to the caller.
      *         If {@param ignoreActivityType} or {@param ignoreWindowingMode} are not undefined,
@@ -3954,14 +3599,11 @@
     }
 
     void unhandledBackLocked() {
-        final int top = getChildCount() - 1;
-        if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Performing unhandledBack(): top activity at " + top);
-        if (top >= 0) {
-            final Task task = getChildAt(top);
-            int activityTop = task.getChildCount() - 1;
-            if (activityTop >= 0) {
-                task.getChildAt(activityTop).finishIfPossible("unhandled-back", true /* oomAdj */);
-            }
+        final ActivityRecord topActivity = getTopMostActivity();
+        if (DEBUG_SWITCH) Slog.d(TAG_SWITCH,
+                "Performing unhandledBack(): top activity: " + topActivity);
+        if (topActivity != null) {
+            topActivity.finishIfPossible("unhandled-back", true /* oomAdj */);
         }
     }
 
@@ -3981,25 +3623,7 @@
             mLastNoHistoryActivity = null;
         }
 
-        return removeHistoryRecordsForAppLocked(app);
-    }
-
-    void handleAppCrash(WindowProcessController app) {
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = getChildAt(taskNdx);
-            for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = task.getChildAt(activityNdx);
-                if (r.app == app) {
-                    Slog.w(TAG, "  Force finishing activity "
-                            + r.intent.getComponent().flattenToShortString());
-                    // Force the destroy to skip right to removal.
-                    r.app = null;
-                    getDisplay().mDisplayContent.prepareAppTransition(
-                            TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
-                    r.destroyIfPossible("handleAppCrashedLocked");
-                }
-            }
-        }
+        return removeHistoryRecordsForApp(app);
     }
 
     boolean dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient,
@@ -4010,8 +3634,7 @@
         pw.println("  isSleeping=" + shouldSleepActivities());
         pw.println("  mBounds=" + getRequestedOverrideBounds());
 
-        boolean printed = dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage,
-                needSep);
+        boolean printed = dumpActivities(fd, pw, dumpAll, dumpClient, dumpPackage, needSep);
 
         printed |= dumpHistoryList(fd, pw, mLruActivities, "    ", "Run", false,
                 !dumpAll, false, dumpPackage, true,
@@ -4043,15 +3666,14 @@
         return printed;
     }
 
-    boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
+    private boolean dumpActivities(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
             boolean dumpClient, String dumpPackage, boolean needSep) {
 
         if (!hasChild()) {
             return false;
         }
         final String prefix = "    ";
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = getChildAt(taskNdx);
+        forAllTasks((task) -> {
             if (needSep) {
                 pw.println("");
             }
@@ -4062,9 +3684,11 @@
             pw.println(prefix + "mLastNonFullscreenBounds=" + task.mLastNonFullscreenBounds);
             pw.println(prefix + "* " + task);
             task.dump(pw, prefix + "  ");
-            dumpHistoryList(fd, pw, getChildAt(taskNdx).mChildren,
-                    prefix, "Hist", true, !dumpAll, dumpClient, dumpPackage, false, null, task);
-        }
+            final ArrayList<ActivityRecord> activities = new ArrayList<>();
+            forAllActivities((Consumer<ActivityRecord>) activities::add);
+            dumpHistoryList(fd, pw, activities, prefix, "Hist", true, !dumpAll, dumpClient,
+                    dumpPackage, false, null, task);
+        });
         return true;
     }
 
@@ -4072,31 +3696,21 @@
         ArrayList<ActivityRecord> activities = new ArrayList<>();
 
         if ("all".equals(name)) {
-            for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-                activities.addAll(getChildAt(taskNdx).mChildren);
-            }
+            forAllActivities((Consumer<ActivityRecord>) activities::add);
         } else if ("top".equals(name)) {
-            final int top = getChildCount() - 1;
-            if (top >= 0) {
-                final Task task = getChildAt(top);
-                int listTop = task.getChildCount() - 1;
-                if (listTop >= 0) {
-                    activities.add(task.getChildAt(listTop));
-                }
+            final ActivityRecord topActivity = getTopMostActivity();
+            if (topActivity != null) {
+                activities.add(topActivity);
             }
         } else {
             ItemMatcher matcher = new ItemMatcher();
             matcher.build(name);
 
-            for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-                final Task task = getChildAt(taskNdx);
-                for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                    final ActivityRecord r1 = task.getChildAt(activityNdx);
-                    if (matcher.match(r1, r1.intent.getComponent())) {
-                        activities.add(r1);
-                    }
+            forAllActivities((r) -> {
+                if (matcher.match(r, r.intent.getComponent())) {
+                    activities.add(r);
                 }
-            }
+            });
         }
 
         return activities;
@@ -4107,22 +3721,24 @@
 
         // All activities that came from the package must be
         // restarted as if there was a config change.
-        for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = getChildAt(taskNdx);
-            for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord a = task.getChildAt(activityNdx);
-                if (a.info.packageName.equals(packageName)) {
-                    a.forceNewConfig = true;
-                    if (starting != null && a == starting && a.mVisibleRequested) {
-                        a.startFreezingScreenLocked(CONFIG_SCREEN_LAYOUT);
-                    }
-                }
-            }
-        }
+        PooledConsumer c = PooledLambda.obtainConsumer(ActivityStack::restartPackage,
+                PooledLambda.__(ActivityRecord.class), starting, packageName);
+        forAllActivities(c);
+        c.recycle();
 
         return starting;
     }
 
+    private static void restartPackage(
+            ActivityRecord r, ActivityRecord starting, String packageName) {
+        if (r.info.packageName.equals(packageName)) {
+            r.forceNewConfig = true;
+            if (starting != null && r == starting && r.mVisibleRequested) {
+                r.startFreezingScreenLocked(CONFIG_SCREEN_LAYOUT);
+            }
+        }
+    }
+
     /**
      * Removes the input task from this stack.
      *
@@ -4141,7 +3757,7 @@
 
         super.removeChild(child);
 
-        EventLog.writeEvent(EventLogTags.AM_REMOVE_TASK, child.mTaskId, mStackId);
+        EventLogTags.writeWmRemoveTask(child.mTaskId, mStackId);
 
         if (display.isSingleTaskInstance()) {
             mService.notifySingleTaskDisplayEmpty(display.mDisplayId);
@@ -4151,7 +3767,7 @@
 
         if (!hasChild()) {
             // Stack is now empty...
-          removeIfPossible();
+            removeIfPossible();
         }
 
         moveHomeStackToFrontIfNeeded(topFocused, display, reason);
@@ -4270,7 +3886,7 @@
         // always on top windows. Since the position the stack should be inserted into is calculated
         // properly in {@link ActivityDisplay#getTopInsertPosition()} in both cases, we can just
         // request that the stack is put at top here.
-        display.positionChildAtTop(this, false /* includingParents */);
+        display.positionStackAtTop(this, false /* includingParents */);
     }
 
     /** NOTE: Should only be called from {@link Task#reparent}. */
@@ -4402,7 +4018,7 @@
             final Task task = mChildren.get(0);
             setWindowingMode(WINDOWING_MODE_UNDEFINED);
 
-            getDisplay().positionChildAtTop(this, false /* includingParents */);
+            getDisplay().positionStackAtTop(this, false /* includingParents */);
 
             mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, this);
             MetricsLoggerWrapper.logPictureInPictureFullScreen(mService.mContext,
@@ -4820,9 +4436,7 @@
         }
 
         final int toTop = targetPosition == mChildren.size() - 1 ? 1 : 0;
-        EventLog.writeEvent(com.android.server.EventLogTags.WM_TASK_MOVED, child.mTaskId, toTop,
-                targetPosition);
-
+        EventLogTags.writeWmTaskMoved(child.mTaskId, toTop, targetPosition);
         return targetPosition;
     }
 
@@ -4841,20 +4455,14 @@
         }
     }
 
-    // TODO(display-unify): Remove after display unification.
-    protected void onParentChanged(ActivityDisplay newParent, ActivityDisplay oldParent) {
-        onParentChanged(
-                newParent != null ? newParent.mDisplayContent : null,
-                oldParent != null ? oldParent.mDisplayContent : null);
-    }
-
     @Override
     protected void onParentChanged(
             ConfigurationContainer newParent, ConfigurationContainer oldParent) {
+        // TODO(display-merge): Remove cast
         final ActivityDisplay display = newParent != null
-                ? ((WindowContainer) newParent).getDisplayContent().mActivityDisplay : null;
+                ? (ActivityDisplay) ((WindowContainer) newParent).getDisplayContent() : null;
         final ActivityDisplay oldDisplay = oldParent != null
-                ? ((WindowContainer) oldParent).getDisplayContent().mActivityDisplay : null;
+                ? (ActivityDisplay) ((WindowContainer) oldParent).getDisplayContent() : null;
 
         mDisplayId = (display != null) ? display.mDisplayId : INVALID_DISPLAY;
         mPrevDisplayId = (oldDisplay != null) ? oldDisplay.mDisplayId : INVALID_DISPLAY;
@@ -4872,8 +4480,7 @@
         }
         super.onParentChanged(newParent, oldParent);
         if (getParent() == null && mDisplayContent != null) {
-            EventLog.writeEvent(com.android.server.EventLogTags.WM_STACK_REMOVED, mStackId);
-
+            EventLogTags.writeWmStackRemoved(mStackId);
             mDisplayContent = null;
             mWmService.mWindowPlacerLocked.requestTraversal();
         }
@@ -6032,14 +5639,14 @@
         return shouldSleepActivities() || mService.mShuttingDown;
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId,
+    public void dumpDebug(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
         final long token = proto.start(fieldId);
-        writeToProtoInnerStackOnly(proto, STACK, logLevel);
+        dumpDebugInnerStackOnly(proto, STACK, logLevel);
         proto.write(com.android.server.am.ActivityStackProto.ID, mStackId);
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
             final Task task = getChildAt(taskNdx);
-            task.writeToProto(proto, com.android.server.am.ActivityStackProto.TASKS, logLevel);
+            task.dumpDebug(proto, com.android.server.am.ActivityStackProto.TASKS, logLevel);
         }
         if (mResumedActivity != null) {
             mResumedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY);
@@ -6047,7 +5654,7 @@
         proto.write(DISPLAY_ID, mDisplayId);
         if (!matchParentBounds()) {
             final Rect bounds = getRequestedOverrideBounds();
-            bounds.writeToProto(proto, com.android.server.am.ActivityStackProto.BOUNDS);
+            bounds.dumpDebug(proto, com.android.server.am.ActivityStackProto.BOUNDS);
         }
 
         // TODO: Remove, no longer needed with windowingMode.
@@ -6056,26 +5663,26 @@
     }
 
     // TODO(proto-merge): Remove once protos for ActivityStack and TaskStack are merged.
-    void writeToProtoInnerStackOnly(ProtoOutputStream proto, long fieldId,
+    void dumpDebugInnerStackOnly(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
         if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
             return;
         }
 
         final long token = proto.start(fieldId);
-        super.writeToProto(proto, WINDOW_CONTAINER, logLevel);
+        super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
         proto.write(StackProto.ID, mStackId);
         for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; taskNdx--) {
-            mChildren.get(taskNdx).writeToProtoInnerTaskOnly(proto, StackProto.TASKS, logLevel);
+            mChildren.get(taskNdx).dumpDebugInnerTaskOnly(proto, StackProto.TASKS, logLevel);
         }
         proto.write(FILLS_PARENT, matchParentBounds());
-        getRawBounds().writeToProto(proto, StackProto.BOUNDS);
+        getRawBounds().dumpDebug(proto, StackProto.BOUNDS);
         proto.write(DEFER_REMOVAL, mDeferRemoval);
         proto.write(MINIMIZE_AMOUNT, mMinimizeAmount);
         proto.write(ADJUSTED_FOR_IME, mAdjustedForIme);
         proto.write(ADJUST_IME_AMOUNT, mAdjustImeAmount);
         proto.write(ADJUST_DIVIDER_AMOUNT, mAdjustDividerAmount);
-        mAdjustedBounds.writeToProto(proto, ADJUSTED_BOUNDS);
+        mAdjustedBounds.dumpDebug(proto, ADJUSTED_BOUNDS);
         proto.write(ANIMATING_BOUNDS, mBoundsAnimating);
         proto.end(token);
     }
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 304f230..7356368 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -126,7 +126,6 @@
 import android.provider.MediaStore;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.EventLog;
 import android.util.MergedConfiguration;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -139,10 +138,11 @@
 import com.android.internal.os.TransferPipe;
 import com.android.internal.os.logging.MetricsLoggerWrapper;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.function.pooled.PooledConsumer;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.am.ActivityManagerService;
-import com.android.server.am.EventLogTags;
 import com.android.server.am.UserState;
+import com.android.server.wm.ActivityMetricsLogger.LaunchingState;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
@@ -444,8 +444,7 @@
         mInitialized = true;
         setRunningTasks(new RunningTasks());
 
-        mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext,
-                mHandler.getLooper());
+        mActivityMetricsLogger = new ActivityMetricsLogger(this, mHandler.getLooper());
         mKeyguardController = new KeyguardController(mService, this);
 
         mPersisterQueue = new PersisterQueue();
@@ -577,8 +576,7 @@
     }
 
     void stopWaitingForActivityVisible(ActivityRecord r) {
-        stopWaitingForActivityVisible(r,
-                getActivityMetricsLogger().getLastDrawnDelayMs(r.getWindowingMode()));
+        stopWaitingForActivityVisible(r, getActivityMetricsLogger().getLastDrawnDelayMs(r));
     }
 
     void stopWaitingForActivityVisible(ActivityRecord r, long totalTime) {
@@ -823,11 +821,11 @@
                         "Launching: " + r + " savedState=" + r.getSavedState()
                                 + " with results=" + results + " newIntents=" + newIntents
                                 + " andResume=" + andResume);
-                EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY, r.mUserId,
-                        System.identityHashCode(r), task.mTaskId, r.shortComponentName);
+                EventLogTags.writeWmRestartActivity(r.mUserId, System.identityHashCode(r),
+                        task.mTaskId, r.shortComponentName);
                 if (r.isActivityTypeHome()) {
                     // Home process is the root process of the task.
-                    updateHomeProcess(task.getChildAt(0).app);
+                    updateHomeProcess(task.getBottomMostActivity().app);
                 }
                 mService.getPackageManagerInternalLocked().notifyPackageUse(
                         r.intent.getComponent().getPackageName(), NOTIFY_PACKAGE_USE_ACTIVITY);
@@ -1502,13 +1500,11 @@
                     mRootActivityContainer.getActivityDisplay(toDisplayId);
 
             if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
-                // Tell the display we are exiting split-screen mode.
-                toDisplay.onExitingSplitScreenMode();
                 // We are moving all tasks from the docked stack to the fullscreen stack,
                 // which is dismissing the docked stack, so resize all other stacks to
                 // fullscreen here already so we don't end up with resize trashing.
-                for (int i = toDisplay.getChildCount() - 1; i >= 0; --i) {
-                    final ActivityStack otherStack = toDisplay.getChildAt(i);
+                for (int i = toDisplay.getStackCount() - 1; i >= 0; --i) {
+                    final ActivityStack otherStack = toDisplay.getStackAt(i);
                     if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
                         continue;
                     }
@@ -1656,8 +1652,8 @@
                 // screen controls and is also the same for all stacks.
                 final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
                 final Rect otherTaskRect = new Rect();
-                for (int i = display.getChildCount() - 1; i >= 0; --i) {
-                    final ActivityStack current = display.getChildAt(i);
+                for (int i = display.getStackCount() - 1; i >= 0; --i) {
+                    final ActivityStack current = display.getStackAt(i);
                     if (!current.inSplitScreenSecondaryWindowingMode()) {
                         continue;
                     }
@@ -1690,7 +1686,7 @@
                 }
             }
             if (!deferResume) {
-                stack.ensureVisibleActivitiesConfigurationLocked(r, preserveWindows);
+                stack.ensureVisibleActivitiesConfiguration(r, preserveWindows);
             }
         } finally {
             mAllowDockedStackResize = true;
@@ -1742,7 +1738,7 @@
              * to the fullscreen stack.  This is to guarantee that when we are removing a stack,
              * that the client receives onStop() before it is reparented.  We do this by detaching
              * the stack from the display so that it will be considered invisible when
-             * ensureActivitiesVisible() is called, and all of its activitys will be marked
+             * ensureActivitiesVisible() is called, and all of its activities will be marked
              * invisible as well and added to the stopping list.  After which we process the
              * stopping list by handling the idle.
              */
@@ -2487,18 +2483,23 @@
             return;
         }
 
-        for (int i = task.getChildCount() - 1; i >= 0; i--) {
-            final ActivityRecord r = task.getChildAt(i);
-            if (r.attachedToProcess()) {
-                mMultiWindowModeChangedActivities.add(r);
-            }
-        }
+        final PooledConsumer c = PooledLambda.obtainConsumer(
+                ActivityStackSupervisor::addToMultiWindowModeChangedList, this,
+                PooledLambda.__(ActivityRecord.class));
+        task.forAllActivities(c);
+        c.recycle();
 
         if (!mHandler.hasMessages(REPORT_MULTI_WINDOW_MODE_CHANGED_MSG)) {
             mHandler.sendEmptyMessage(REPORT_MULTI_WINDOW_MODE_CHANGED_MSG);
         }
     }
 
+    private void addToMultiWindowModeChangedList(ActivityRecord r) {
+        if (r.attachedToProcess()) {
+            mMultiWindowModeChangedActivities.add(r);
+        }
+    }
+
     void scheduleUpdatePictureInPictureModeIfNeeded(Task task, ActivityStack prevStack) {
         final ActivityStack stack = task.getStack();
         if (prevStack == null || prevStack == stack
@@ -2509,17 +2510,13 @@
         scheduleUpdatePictureInPictureModeIfNeeded(task, stack.getRequestedOverrideBounds());
     }
 
-    void scheduleUpdatePictureInPictureModeIfNeeded(Task task, Rect targetStackBounds) {
-        for (int i = task.getChildCount() - 1; i >= 0; i--) {
-            final ActivityRecord r = task.getChildAt(i);
-            if (r.attachedToProcess()) {
-                mPipModeChangedActivities.add(r);
-                // If we are scheduling pip change, then remove this activity from multi-window
-                // change list as the processing of pip change will make sure multi-window changed
-                // message is processed in the right order relative to pip changed.
-                mMultiWindowModeChangedActivities.remove(r);
-            }
-        }
+    private void scheduleUpdatePictureInPictureModeIfNeeded(Task task, Rect targetStackBounds) {
+        final PooledConsumer c = PooledLambda.obtainConsumer(
+                ActivityStackSupervisor::addToPipModeChangedList, this,
+                PooledLambda.__(ActivityRecord.class));
+        task.forAllActivities(c);
+        c.recycle();
+
         mPipModeChangedTargetStackBounds = targetStackBounds;
 
         if (!mHandler.hasMessages(REPORT_PIP_MODE_CHANGED_MSG)) {
@@ -2527,14 +2524,23 @@
         }
     }
 
+    private void addToPipModeChangedList(ActivityRecord r) {
+        if (!r.attachedToProcess()) return;
+
+        mPipModeChangedActivities.add(r);
+        // If we are scheduling pip change, then remove this activity from multi-window
+        // change list as the processing of pip change will make sure multi-window changed
+        // message is processed in the right order relative to pip changed.
+        mMultiWindowModeChangedActivities.remove(r);
+    }
+
     void updatePictureInPictureMode(Task task, Rect targetStackBounds, boolean forceUpdate) {
         mHandler.removeMessages(REPORT_PIP_MODE_CHANGED_MSG);
-        for (int i = task.getChildCount() - 1; i >= 0; i--) {
-            final ActivityRecord r = task.getChildAt(i);
-            if (r.attachedToProcess()) {
-                r.updatePictureInPictureMode(targetStackBounds, forceUpdate);
-            }
-        }
+        final PooledConsumer c = PooledLambda.obtainConsumer(
+                ActivityRecord::updatePictureInPictureMode,
+                PooledLambda.__(ActivityRecord.class), targetStackBounds, forceUpdate);
+        task.forAllActivities(c);
+        c.recycle();
     }
 
     void wakeUp(String reason) {
@@ -2753,7 +2759,8 @@
 
                 mRootActivityContainer.sendPowerHintForLaunchStartIfNeeded(
                         true /* forceSend */, targetActivity);
-                mActivityMetricsLogger.notifyActivityLaunching(task.intent);
+                final LaunchingState launchingState =
+                        mActivityMetricsLogger.notifyActivityLaunching(task.intent);
                 try {
                     mService.moveTaskToFrontLocked(null /* appThread */, null /* callingPackage */,
                             task.mTaskId, 0, options, true /* fromRecents */);
@@ -2761,8 +2768,8 @@
                     // the override pending app transition will be applied immediately.
                     targetActivity.applyOptionsLocked();
                 } finally {
-                    mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT,
-                            targetActivity);
+                    mActivityMetricsLogger.notifyActivityLaunched(launchingState,
+                            START_TASK_TO_FRONT, targetActivity);
                 }
 
                 mService.getActivityStartController().postStartActivityProcessingForLastStarter(
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index d3fd450..695f58c 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -546,7 +546,7 @@
         }
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         for (PendingActivityLaunch activity: mPendingActivityLaunches) {
             activity.r.writeIdentifierToProto(proto, fieldId);
         }
diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index 8420695..b2fb93d 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -156,16 +156,16 @@
         mInTask = inTask;
         mActivityOptions = activityOptions;
 
-        if (interceptSuspendedPackageIfNeeded()) {
-            // Skip the rest of interceptions as the package is suspended by device admin so
-            // no user action can undo this.
-            return true;
-        }
         if (interceptQuietProfileIfNeeded()) {
             // If work profile is turned off, skip the work challenge since the profile can only
             // be unlocked when profile's user is running.
             return true;
         }
+        if (interceptSuspendedPackageIfNeeded()) {
+            // Skip the rest of interceptions as the package is suspended by device admin so
+            // no user action can undo this.
+            return true;
+        }
         if (interceptHarmfulAppIfNeeded()) {
             // If the app has a "harmful app" warning associated with it, we should ask to uninstall
             // before issuing the work challenge.
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 8455c6d..baa2955 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -60,7 +60,6 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 
-import static com.android.server.am.EventLogTags.AM_NEW_INTENT;
 import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
 import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
@@ -114,16 +113,15 @@
 import android.service.voice.IVoiceInteractionSession;
 import android.text.TextUtils;
 import android.util.ArraySet;
-import android.util.EventLog;
 import android.util.Pools.SynchronizedPool;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.HeavyWeightSwitcherActivity;
 import com.android.internal.app.IVoiceInteractor;
-import com.android.server.am.EventLogTags;
 import com.android.server.am.PendingIntentRecord;
 import com.android.server.pm.InstantAppResolver;
+import com.android.server.wm.ActivityMetricsLogger.LaunchingState;
 import com.android.server.wm.ActivityStackSupervisor.PendingActivityLaunch;
 import com.android.server.wm.LaunchParamsController.LaunchParams;
 
@@ -152,7 +150,8 @@
     private final ActivityStartController mController;
 
     // Share state variable among methods when starting an activity.
-    private ActivityRecord mStartActivity;
+    @VisibleForTesting
+    ActivityRecord mStartActivity;
     private Intent mIntent;
     private int mCallingUid;
     private ActivityOptions mOptions;
@@ -176,7 +175,8 @@
     private int mPreferredDisplayId;
 
     private Task mInTask;
-    private boolean mAddingToTask;
+    @VisibleForTesting
+    boolean mAddingToTask;
     private Task mReuseTask;
 
     private ActivityInfo mNewTaskInfo;
@@ -573,15 +573,16 @@
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
             int startFlags, boolean doResume, ActivityOptions options, Task inTask) {
         try {
-            mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(r.intent);
+            final LaunchingState launchingState = mSupervisor.getActivityMetricsLogger()
+                    .notifyActivityLaunching(r.intent, r.resultTo);
             mLastStartReason = "startResolvedActivity";
             mLastStartActivityTimeMs = System.currentTimeMillis();
             mLastStartActivityRecord = r;
             mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
                     voiceInteractor, startFlags, doResume, options, inTask,
                     false /* restrictedBgActivity */);
-            mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(mLastStartActivityResult,
-                    mLastStartActivityRecord);
+            mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState,
+                    mLastStartActivityResult, mLastStartActivityRecord);
         } finally {
             onExecutionComplete();
         }
@@ -599,8 +600,14 @@
                 throw new IllegalArgumentException("File descriptors passed in Intent");
             }
 
-            mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(mRequest.intent);
+            final LaunchingState launchingState;
+            synchronized (mService.mGlobalLock) {
+                final ActivityRecord caller = ActivityRecord.forTokenLocked(mRequest.resultTo);
+                launchingState = mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(
+                        mRequest.intent, caller);
+            }
 
+            // Do not lock the resolving to avoid potential deadlock.
             if (mRequest.activityInfo == null) {
                 mRequest.resolveActivity(mSupervisor);
             }
@@ -644,7 +651,7 @@
                 // Notify ActivityMetricsLogger that the activity has launched.
                 // ActivityMetricsLogger will then wait for the windows to be drawn and populate
                 // WaitResult.
-                mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res,
+                mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, res,
                         mLastStartActivityRecord);
                 return getExternalResult(mRequest.waitResult == null ? res
                         : waitForResult(res, mLastStartActivityRecord));
@@ -1125,7 +1132,7 @@
             request.outActivity[0] = mLastStartActivityRecord;
         }
 
-        return getExternalResult(mLastStartActivityResult);
+        return mLastStartActivityResult;
     }
 
     /**
@@ -1447,7 +1454,7 @@
 
         // Stack should also be detached from display and be removed if it's empty.
         if (startedActivityStack != null && startedActivityStack.isAttached()
-                && startedActivityStack.numActivities() == 0
+                && !startedActivityStack.hasActivity()
                 && !startedActivityStack.isActivityTypeHome()) {
             startedActivityStack.removeIfPossible();
             startedActivityStack = null;
@@ -1550,11 +1557,12 @@
                 UserHandle.getAppId(mStartActivity.info.applicationInfo.uid)
         );
         if (newTask) {
-            EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, mStartActivity.mUserId,
+            EventLogTags.writeWmCreateTask(mStartActivity.mUserId,
                     mStartActivity.getTask().mTaskId);
         }
         mStartActivity.logStartActivity(
-                EventLogTags.AM_CREATE_ACTIVITY, mStartActivity.getTask());
+                EventLogTags.WM_CREATE_ACTIVITY, mStartActivity.getTask());
+
         mTargetStack.mLastPausedActivity = null;
 
         mRootActivityContainer.sendPowerHintForLaunchStartIfNeeded(
@@ -1640,7 +1648,7 @@
             return START_CANCELED;
         }
 
-        if (mRestrictedBgActivity && (newTask || !targetTask.containsAppUid(mCallingUid))
+        if (mRestrictedBgActivity && (newTask || !targetTask.isUidPresent(mCallingUid))
                 && handleBackgroundActivityAbort(mStartActivity)) {
             Slog.e(TAG, "Abort background activity starts from " + mCallingUid);
             return START_ABORTED;
@@ -1667,7 +1675,16 @@
      * - Comply to the specified activity launch flags
      * - Determine whether need to add a new activity on top or just brought the task to front.
      */
-    private int recycleTask(Task targetTask, ActivityRecord targetTaskTop, Task reusedTask) {
+    @VisibleForTesting
+    int recycleTask(Task targetTask, ActivityRecord targetTaskTop, Task reusedTask) {
+        // Should not recycle task which is from a different user, just adding the starting
+        // activity to the task.
+        if (targetTask.mUserId != mStartActivity.mUserId) {
+            mTargetStack = targetTask.getStack();
+            mAddingToTask = true;
+            return START_SUCCESS;
+        }
+
         // True if we are clearing top and resetting of a standard (default) launch mode
         // ({@code LAUNCH_MULTIPLE}) activity. The existing activity will be finished.
         final boolean clearTopAndResetStandardLaunchMode =
@@ -1871,8 +1888,8 @@
             // In this case, we are launching an activity in our own task that may
             // already be running somewhere in the history, and we want to shuffle it to
             // the front of the stack if so.
-            final ActivityRecord act = targetTask.findActivityInHistoryLocked(
-                    mStartActivity);
+            final ActivityRecord act =
+                    targetTask.findActivityInHistory(mStartActivity.mActivityComponent);
             if (act != null) {
                 final Task task = act.getTask();
                 task.moveActivityToFrontLocked(act);
@@ -2405,7 +2422,7 @@
             return;
         }
 
-        activity.logStartActivity(AM_NEW_INTENT, activity.getTask());
+        activity.logStartActivity(EventLogTags.WM_NEW_INTENT, activity.getTask());
         activity.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
                 mStartActivity.launchedFromPackage);
         mIntentDelivered = true;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index cce005b..25f6d6f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -32,9 +32,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.os.SystemClock;
 import android.service.voice.IVoiceInteractionSession;
-import android.util.SparseIntArray;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.app.IVoiceInteractor;
@@ -154,17 +152,6 @@
             IVoiceInteractor mInteractor);
 
     /**
-     * Callback for window manager to let activity manager know that we are finally starting the
-     * app transition;
-     *
-     * @param reasons A map from windowing mode to a reason integer why the transition was started,
-     *                which must be one of the APP_TRANSITION_* values.
-     * @param timestampNs The time at which the app transition started in
-     *                  {@link SystemClock#elapsedRealtimeNs()} ()} timebase.
-     */
-    public abstract void notifyAppTransitionStarting(SparseIntArray reasons, long timestampNs);
-
-    /**
      * Callback for window manager to let activity manager know that the app transition was
      * cancelled.
      */
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index bef4f5a..efd21ec8 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -83,6 +83,8 @@
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.SCREEN_COMPAT_PACKAGES;
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.MODE;
 import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.PACKAGE;
+import static com.android.server.am.EventLogTags.writeBootProgressEnableScreen;
+import static com.android.server.am.EventLogTags.writeConfigurationChanged;
 import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED;
 import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING;
 import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
@@ -215,11 +217,9 @@
 import android.text.format.TimeMigrationUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.util.SparseIntArray;
 import android.util.StatsLog;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
@@ -246,6 +246,8 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.pooled.PooledConsumer;
+import com.android.internal.util.function.pooled.PooledFunction;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.AttributeCache;
 import com.android.server.LocalServices;
@@ -258,7 +260,6 @@
 import com.android.server.am.ActivityManagerServiceDumpProcessesProto;
 import com.android.server.am.AppTimeTracker;
 import com.android.server.am.BaseErrorDialog;
-import com.android.server.am.EventLogTags;
 import com.android.server.am.PendingIntentController;
 import com.android.server.am.PendingIntentRecord;
 import com.android.server.am.UserState;
@@ -695,6 +696,13 @@
         int caller() default NONE;
     }
 
+    private final Runnable mUpdateOomAdjRunnable = new Runnable() {
+        @Override
+	public void run() {
+            mAmInternal.updateOomAdj();
+        }
+    };
+
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
     public ActivityTaskManagerService(Context context) {
         mContext = context;
@@ -1219,25 +1227,23 @@
             Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
             int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
         final WaitResult res = new WaitResult();
-        synchronized (mGlobalLock) {
-            enforceNotIsolatedCaller("startActivityAndWait");
-            userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
-                    userId, "startActivityAndWait");
-            // TODO: Switch to user app stacks here.
-            getActivityStartController().obtainStarter(intent, "startActivityAndWait")
-                    .setCaller(caller)
-                    .setCallingPackage(callingPackage)
-                    .setResolvedType(resolvedType)
-                    .setResultTo(resultTo)
-                    .setResultWho(resultWho)
-                    .setRequestCode(requestCode)
-                    .setStartFlags(startFlags)
-                    .setActivityOptions(bOptions)
-                    .setUserId(userId)
-                    .setProfilerInfo(profilerInfo)
-                    .setWaitResult(res)
-                    .execute();
-        }
+        enforceNotIsolatedCaller("startActivityAndWait");
+        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+                userId, "startActivityAndWait");
+        // TODO: Switch to user app stacks here.
+        getActivityStartController().obtainStarter(intent, "startActivityAndWait")
+                .setCaller(caller)
+                .setCallingPackage(callingPackage)
+                .setResolvedType(resolvedType)
+                .setResultTo(resultTo)
+                .setResultWho(resultWho)
+                .setRequestCode(requestCode)
+                .setStartFlags(startFlags)
+                .setActivityOptions(bOptions)
+                .setUserId(userId)
+                .setProfilerInfo(profilerInfo)
+                .setWaitResult(res)
+                .execute();
         return res;
     }
 
@@ -1245,24 +1251,22 @@
     public final int startActivityWithConfig(IApplicationThread caller, String callingPackage,
             Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
             int startFlags, Configuration config, Bundle bOptions, int userId) {
-        synchronized (mGlobalLock) {
-            enforceNotIsolatedCaller("startActivityWithConfig");
-            userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
-                    "startActivityWithConfig");
-            // TODO: Switch to user app stacks here.
-            return getActivityStartController().obtainStarter(intent, "startActivityWithConfig")
-                    .setCaller(caller)
-                    .setCallingPackage(callingPackage)
-                    .setResolvedType(resolvedType)
-                    .setResultTo(resultTo)
-                    .setResultWho(resultWho)
-                    .setRequestCode(requestCode)
-                    .setStartFlags(startFlags)
-                    .setGlobalConfiguration(config)
-                    .setActivityOptions(bOptions)
-                    .setUserId(userId)
-                    .execute();
-        }
+        enforceNotIsolatedCaller("startActivityWithConfig");
+        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
+                "startActivityWithConfig");
+        // TODO: Switch to user app stacks here.
+        return getActivityStartController().obtainStarter(intent, "startActivityWithConfig")
+                .setCaller(caller)
+                .setCallingPackage(callingPackage)
+                .setResolvedType(resolvedType)
+                .setResultTo(resultTo)
+                .setResultWho(resultWho)
+                .setRequestCode(requestCode)
+                .setStartFlags(startFlags)
+                .setGlobalConfiguration(config)
+                .setActivityOptions(bOptions)
+                .setUserId(userId)
+                .execute();
     }
 
 
@@ -1661,7 +1665,14 @@
                 if (getLockTaskController().activityBlockedFromFinish(r)) {
                     return false;
                 }
-                r.finishActivityAffinity();
+
+                final PooledFunction p = PooledLambda.obtainFunction(
+                        ActivityRecord::finishIfSameAffinity, r,
+                        PooledLambda.__(ActivityRecord.class));
+                r.getTask().forAllActivities(
+                        p, r, true /*includeBoundary*/, true /*traverseTopToBottom*/);
+                p.recycle();
+
                 return true;
             } finally {
                 Binder.restoreCallingIdentity(origId);
@@ -1994,10 +2005,8 @@
                 if (r == null) {
                     return false;
                 }
-                final Task task = r.getTask();
-                int index = task.mChildren.lastIndexOf(r);
-                if (index > 0) {
-                    ActivityRecord under = task.getChildAt(index - 1);
+                final ActivityRecord under = r.getTask().getActivityBelow(r);
+                if (under != null) {
                     under.returningOptions = safeOptions != null ? safeOptions.getOptions(r) : null;
                 }
                 return r.setOccludesParent(false);
@@ -2163,7 +2172,7 @@
         synchronized (mGlobalLock) {
             final ActivityRecord r = ActivityRecord.forTokenLocked(token);
             if (r != null) {
-                return r.getActivityStack().navigateUpToLocked(
+                return r.getActivityStack().navigateUpTo(
                         r, destIntent, resultCode, resultData);
             }
             return false;
@@ -2548,11 +2557,22 @@
     public final void finishSubActivity(IBinder token, String resultWho, int requestCode) {
         synchronized (mGlobalLock) {
             final long origId = Binder.clearCallingIdentity();
-            ActivityRecord r = ActivityRecord.isInStackLocked(token);
-            if (r != null) {
-                r.getActivityStack().finishSubActivityLocked(r, resultWho, requestCode);
+            try {
+                ActivityRecord r = ActivityRecord.isInStackLocked(token);
+                if (r == null) return;
+
+                final PooledConsumer c = PooledLambda.obtainConsumer(
+                        ActivityRecord::finishIfSubActivity, PooledLambda.__(ActivityRecord.class),
+                        r, resultWho, requestCode);
+                // TODO: This should probably only loop over the task since you need to be in the
+                // same task to return results.
+                r.getActivityStack().forAllActivities(c);
+                c.recycle();
+
+                updateOomAdj();
+            } finally {
+                Binder.restoreCallingIdentity(origId);
             }
-            Binder.restoreCallingIdentity(origId);
         }
     }
 
@@ -2561,7 +2581,7 @@
         synchronized (mGlobalLock) {
             ActivityStack stack = ActivityRecord.getStackLocked(token);
             if (stack != null) {
-                return stack.willActivityBeVisibleLocked(token);
+                return stack.willActivityBeVisible(token);
             }
             return false;
         }
@@ -3332,7 +3352,7 @@
             final long origId = Binder.clearCallingIdentity();
             try {
                 final WindowProcessController app = getProcessController(appInt);
-                mRootActivityContainer.releaseSomeActivitiesLocked(app, "low-mem");
+                app.releaseSomeActivities("low-mem");
             } finally {
                 Binder.restoreCallingIdentity(origId);
             }
@@ -5195,8 +5215,7 @@
 
         if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.i(TAG_CONFIGURATION,
                 "Updating global configuration to: " + values);
-
-        EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
+        writeConfigurationChanged(changes);
         StatsLog.write(StatsLog.RESOURCE_CONFIGURATION_CHANGED,
                 values.colorMode,
                 values.densityDpi,
@@ -5359,8 +5378,7 @@
     }
 
     void enableScreenAfterBoot(boolean booted) {
-        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
-                SystemClock.uptimeMillis());
+        writeBootProgressEnableScreen(SystemClock.uptimeMillis());
         mWindowManager.enableScreenAfterBoot();
 
         synchronized (mGlobalLock) {
@@ -5491,7 +5509,7 @@
         applyUpdateLockStateLocked(r);
         applyUpdateVrModeLocked(r);
 
-        EventLogTags.writeAmSetResumedActivity(
+        EventLogTags.writeWmSetResumedActivity(
                 r == null ? -1 : r.mUserId,
                 r == null ? "NULL" : r.shortComponentName,
                 reason);
@@ -5547,7 +5565,8 @@
     }
 
     void updateOomAdj() {
-        mH.post(mAmInternal::updateOomAdj);
+        mH.removeCallbacks(mUpdateOomAdjRunnable);
+        mH.post(mUpdateOomAdjRunnable);
     }
 
     void updateCpuStats() {
@@ -6075,15 +6094,6 @@
         }
 
         @Override
-        public void notifyAppTransitionStarting(SparseIntArray reasons,
-                long timestampNs) {
-            synchronized (mGlobalLock) {
-                mStackSupervisor.getActivityMetricsLogger().notifyTransitionStarting(
-                        reasons, timestampNs);
-            }
-        }
-
-        @Override
         public void notifySingleTaskDisplayDrawn(int displayId) {
             mTaskChangeNotificationController.notifySingleTaskDisplayDrawn(displayId);
         }
@@ -6419,8 +6429,7 @@
         @Override
         public void enableScreenAfterBoot(boolean booted) {
             synchronized (mGlobalLock) {
-                EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
-                        SystemClock.uptimeMillis());
+                writeBootProgressEnableScreen(SystemClock.uptimeMillis());
                 mWindowManager.enableScreenAfterBoot();
                 updateEventDispatchingLocked(booted);
             }
@@ -6908,7 +6917,7 @@
             synchronized (mGlobalLock) {
                 // The output proto of "activity --proto activities"
                 // is ActivityManagerServiceDumpActivitiesProto
-                mRootActivityContainer.writeToProto(proto,
+                mRootActivityContainer.dumpDebug(proto,
                         ActivityManagerServiceDumpActivitiesProto.ACTIVITY_STACK_SUPERVISOR,
                         WindowTraceLogLevel.ALL);
             }
@@ -7089,7 +7098,7 @@
                 int wakeFullness, boolean testPssMode) {
             synchronized (mGlobalLock) {
                 if (dumpPackage == null) {
-                    getGlobalConfiguration().writeToProto(proto, GLOBAL_CONFIGURATION);
+                    getGlobalConfiguration().dumpDebug(proto, GLOBAL_CONFIGURATION);
                     proto.write(CONFIG_WILL_CHANGE, getTopDisplayFocusedStack().mConfigWillChange);
                     writeSleepStateToProto(proto, wakeFullness, testPssMode);
                     if (mRunningVoice != null) {
@@ -7097,11 +7106,11 @@
                                 ActivityManagerServiceDumpProcessesProto.RUNNING_VOICE);
                         proto.write(ActivityManagerServiceDumpProcessesProto.Voice.SESSION,
                                 mRunningVoice.toString());
-                        mVoiceWakeLock.writeToProto(
+                        mVoiceWakeLock.dumpDebug(
                                 proto, ActivityManagerServiceDumpProcessesProto.Voice.WAKELOCK);
                         proto.end(vrToken);
                     }
-                    mVrController.writeToProto(proto,
+                    mVrController.dumpDebug(proto,
                             ActivityManagerServiceDumpProcessesProto.VR_CONTROLLER);
                     if (mController != null) {
                         final long token = proto.start(CONTROLLER);
@@ -7109,25 +7118,25 @@
                         proto.write(IS_A_MONKEY, mControllerIsAMonkey);
                         proto.end(token);
                     }
-                    mStackSupervisor.mGoingToSleepWakeLock.writeToProto(proto, GOING_TO_SLEEP);
-                    mStackSupervisor.mLaunchingActivityWakeLock.writeToProto(proto,
+                    mStackSupervisor.mGoingToSleepWakeLock.dumpDebug(proto, GOING_TO_SLEEP);
+                    mStackSupervisor.mLaunchingActivityWakeLock.dumpDebug(proto,
                             LAUNCHING_ACTIVITY);
                 }
 
                 if (mHomeProcess != null && (dumpPackage == null
                         || mHomeProcess.mPkgList.contains(dumpPackage))) {
-                    mHomeProcess.writeToProto(proto, HOME_PROC);
+                    mHomeProcess.dumpDebug(proto, HOME_PROC);
                 }
 
                 if (mPreviousProcess != null && (dumpPackage == null
                         || mPreviousProcess.mPkgList.contains(dumpPackage))) {
-                    mPreviousProcess.writeToProto(proto, PREVIOUS_PROC);
+                    mPreviousProcess.dumpDebug(proto, PREVIOUS_PROC);
                     proto.write(PREVIOUS_PROC_VISIBLE_TIME_MS, mPreviousProcessVisibleTime);
                 }
 
                 if (mHeavyWeightProcess != null && (dumpPackage == null
                         || mHeavyWeightProcess.mPkgList.contains(dumpPackage))) {
-                    mHeavyWeightProcess.writeToProto(proto, HEAVY_WEIGHT_PROC);
+                    mHeavyWeightProcess.dumpDebug(proto, HEAVY_WEIGHT_PROC);
                 }
 
                 for (Map.Entry<String, Integer> entry
@@ -7143,7 +7152,7 @@
                 }
 
                 if (mCurAppTimeTracker != null) {
-                    mCurAppTimeTracker.writeToProto(proto, CURRENT_TRACKER, true);
+                    mCurAppTimeTracker.dumpDebug(proto, CURRENT_TRACKER, true);
                 }
 
             }
diff --git a/services/core/java/com/android/server/wm/AlertWindowNotification.java b/services/core/java/com/android/server/wm/AlertWindowNotification.java
index 9177d25..0de94d9 100644
--- a/services/core/java/com/android/server/wm/AlertWindowNotification.java
+++ b/services/core/java/com/android/server/wm/AlertWindowNotification.java
@@ -21,7 +21,7 @@
 import static android.content.Context.NOTIFICATION_SERVICE;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.provider.Settings.ACTION_MANAGE_OVERLAY_PERMISSION;
+import static android.provider.Settings.ACTION_MANAGE_APP_OVERLAY_PERMISSION;
 
 import android.app.Notification;
 import android.app.NotificationChannel;
@@ -29,13 +29,11 @@
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.Context;
-
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
-
 import android.net.Uri;
 import android.os.Bundle;
 
@@ -137,7 +135,7 @@
     }
 
     private PendingIntent getContentIntent(Context context, String packageName) {
-        final Intent intent = new Intent(ACTION_MANAGE_OVERLAY_PERMISSION,
+        final Intent intent = new Intent(ACTION_MANAGE_APP_OVERLAY_PERMISSION,
                 Uri.fromParts("package", packageName, null));
         intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
         // Calls into activity manager...
diff --git a/services/core/java/com/android/server/wm/AnimationAdapter.java b/services/core/java/com/android/server/wm/AnimationAdapter.java
index 278a9ba..1be3d61 100644
--- a/services/core/java/com/android/server/wm/AnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/AnimationAdapter.java
@@ -76,11 +76,11 @@
 
     void dump(PrintWriter pw, String prefix);
 
-    default void writeToProto(ProtoOutputStream proto, long fieldId) {
+    default void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
-        writeToProto(proto);
+        dumpDebug(proto);
         proto.end(token);
     }
 
-    void writeToProto(ProtoOutputStream proto);
+    void dumpDebug(ProtoOutputStream proto);
 }
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index cd7c216..e0c5fd05 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -2142,7 +2142,7 @@
         }
     }
 
-    void writeToProto(ProtoOutputStream proto, long fieldId) {
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(APP_TRANSITION_STATE, mAppTransitionState);
         proto.write(LAST_USED_APP_TRANSITION, mLastUsedAppTransition);
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index ff1b423..d7f4b34 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -52,11 +52,10 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
-import android.os.SystemClock;
 import android.os.Trace;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
-import android.util.SparseIntArray;
 import android.view.Display;
 import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationDefinition;
@@ -81,7 +80,7 @@
     private final WallpaperController mWallpaperControllerLocked;
     private RemoteAnimationDefinition mRemoteAnimationDefinition = null;
 
-    private final SparseIntArray mTempTransitionReasons = new SparseIntArray();
+    private final ArrayMap<ActivityRecord, Integer> mTempTransitionReasons = new ArrayMap<>();
 
     AppTransitionController(WindowManagerService service, DisplayContent displayContent) {
         mService = service;
@@ -208,8 +207,8 @@
 
         mDisplayContent.computeImeTarget(true /* updateImeTarget */);
 
-        mService.mAtmInternal.notifyAppTransitionStarting(mTempTransitionReasons.clone(),
-            SystemClock.elapsedRealtimeNanos());
+        mService.mAtmService.mStackSupervisor.getActivityMetricsLogger().notifyTransitionStarting(
+                mTempTransitionReasons);
 
         if (transit == TRANSIT_SHOW_SINGLE_TASK_DISPLAY) {
             mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
@@ -390,7 +389,6 @@
             // this guy's animations regardless of whether it's
             // gotten drawn.
             wtoken.allDrawn = true;
-            wtoken.deferClearAllDrawn = false;
             // Ensure that apps that are mid-starting are also scheduled to have their
             // starting windows removed after the animation is complete
             if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit) {
@@ -442,7 +440,8 @@
         }
     }
 
-    private boolean transitionGoodToGo(ArraySet<ActivityRecord> apps, SparseIntArray outReasons) {
+    private boolean transitionGoodToGo(ArraySet<ActivityRecord> apps,
+            ArrayMap<ActivityRecord, Integer> outReasons) {
         ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
                 "Checking %d opening apps (frozen=%b timeout=%b)...", apps.size(),
                 mService.mDisplayFrozen, mDisplayContent.mAppTransition.isTimeout());
@@ -478,11 +477,10 @@
                 if (!allDrawn && !activity.startingDisplayed && !activity.startingMoved) {
                     return false;
                 }
-                final int windowingMode = activity.getWindowingMode();
                 if (allDrawn) {
-                    outReasons.put(windowingMode,  APP_TRANSITION_WINDOWS_DRAWN);
+                    outReasons.put(activity, APP_TRANSITION_WINDOWS_DRAWN);
                 } else {
-                    outReasons.put(windowingMode,
+                    outReasons.put(activity,
                             activity.mStartingData instanceof SplashScreenStartingData
                                     ? APP_TRANSITION_SPLASH_SCREEN
                                     : APP_TRANSITION_SNAPSHOT);
diff --git a/services/core/java/com/android/server/wm/BarController.java b/services/core/java/com/android/server/wm/BarController.java
index 05d5a5c..57cdb0b 100644
--- a/services/core/java/com/android/server/wm/BarController.java
+++ b/services/core/java/com/android/server/wm/BarController.java
@@ -339,7 +339,7 @@
         throw new IllegalArgumentException("Unknown state " + state);
     }
 
-    void writeToProto(ProtoOutputStream proto, long fieldId) {
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(STATE, mState);
         proto.write(TRANSIENT_STATE, mTransientBarState);
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 30f3bc5..bfa72e0 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -591,7 +591,7 @@
      * @hide
      */
     @CallSuper
-    protected void writeToProto(ProtoOutputStream proto, long fieldId,
+    protected void dumpDebug(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
         // Critical log level logs only visible elements to mitigate performance overheard
         if (logLevel != WindowTraceLogLevel.ALL && !mHasOverrideConfiguration) {
@@ -599,11 +599,11 @@
         }
 
         final long token = proto.start(fieldId);
-        mRequestedOverrideConfiguration.writeToProto(proto, OVERRIDE_CONFIGURATION,
+        mRequestedOverrideConfiguration.dumpDebug(proto, OVERRIDE_CONFIGURATION,
                 logLevel == WindowTraceLogLevel.CRITICAL);
         if (logLevel == WindowTraceLogLevel.ALL) {
-            mFullConfiguration.writeToProto(proto, FULL_CONFIGURATION, false /* critical */);
-            mMergedOverrideConfiguration.writeToProto(proto, MERGED_OVERRIDE_CONFIGURATION,
+            mFullConfiguration.dumpDebug(proto, FULL_CONFIGURATION, false /* critical */);
+            mMergedOverrideConfiguration.dumpDebug(proto, MERGED_OVERRIDE_CONFIGURATION,
                     false /* critical */);
         }
         proto.end(token);
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index e6150cb..af859d3 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -389,7 +389,7 @@
         }
 
         @Override
-        public void writeToProtoInner(ProtoOutputStream proto) {
+        public void dumpDebugInner(ProtoOutputStream proto) {
             final long token = proto.start(ALPHA);
             proto.write(FROM, mFromAlpha);
             proto.write(TO, mToAlpha);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 283b92c..8e126b5 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -138,7 +138,6 @@
 import static com.android.server.wm.utils.RegionUtils.rectListToRegion;
 
 import android.animation.AnimationHandler;
-import android.annotation.CallSuper;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -221,7 +220,7 @@
  * particular Display.
  */
 class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowContainer>
-        implements WindowManagerPolicy.DisplayContentInfo, ConfigurationContainerListener {
+        implements WindowManagerPolicy.DisplayContentInfo {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayContent" : TAG_WM;
 
     /** The default scaling mode that scales content automatically. */
@@ -236,11 +235,10 @@
     @Retention(RetentionPolicy.SOURCE)
     @interface ForceScalingMode {}
 
-    /** Unique identifier of this stack. */
-    private final int mDisplayId;
+    ActivityTaskManagerService mAtmService;
 
-    // TODO: Remove once unification is complete.
-    ActivityDisplay mActivityDisplay;
+    /** Unique identifier of this display. */
+    private final int mDisplayId;
 
     /** The containers below are the only child containers the display can have. */
     // Contains all window containers that are related to apps (Activities)
@@ -671,10 +669,12 @@
             getDisplayPolicy().layoutWindowLw(w, null, mDisplayFrames);
             w.mLayoutSeq = mLayoutSeq;
 
-            // If this is the first layout, we need to initialize the last inset values as
-            // otherwise we'd immediately cause an unnecessary resize.
+            // If this is the first layout, we need to initialize the last frames and inset values,
+            // as otherwise we'd immediately cause an unnecessary resize.
             if (firstLayout) {
+                w.updateLastFrames();
                 w.updateLastInsetValues();
+                w.updateLocationInParentDisplayIfNeeded();
             }
 
             if (w.mActivityRecord != null) {
@@ -842,16 +842,15 @@
      * @param service You know.
      * @param activityDisplay The ActivityDisplay for the display container.
      */
-    DisplayContent(Display display, WindowManagerService service,
-            ActivityDisplay activityDisplay) {
+    DisplayContent(Display display, WindowManagerService service) {
         super(service);
-        mActivityDisplay = activityDisplay;
         if (service.mRoot.getDisplayContent(display.getDisplayId()) != null) {
             throw new IllegalArgumentException("Display with ID=" + display.getDisplayId()
                     + " already exists=" + service.mRoot.getDisplayContent(display.getDisplayId())
                     + " new=" + display);
         }
 
+        mAtmService = mWmService.mAtmService;
         mDisplay = display;
         mDisplayId = display.getDisplayId();
         mWallpaperController = new WallpaperController(mWmService, this);
@@ -1125,20 +1124,6 @@
         mAppTransitionController.registerRemoteAnimations(definition);
     }
 
-    /**
-     * The display content may have configuration set from {@link #DisplayWindowSettings}. This
-     * callback let the owner of container know there is existing configuration to prevent the
-     * values from being replaced by the initializing {@link #ActivityDisplay}.
-     */
-    void initializeDisplayOverrideConfiguration() {
-        if (mActivityDisplay == null) {
-            return;
-        }
-        mActivityDisplay.onRequestedOverrideConfigurationChanged(
-                getResolvedOverrideConfiguration());
-        mActivityDisplay.registerConfigurationChangeListener(this);
-    }
-
     void reconfigureDisplayLocked() {
         if (!isReady()) {
             return;
@@ -1162,13 +1147,15 @@
     }
 
     void sendNewConfiguration() {
-        if (!isReady() || mActivityDisplay == null) {
+        if (!isReady()) {
             return;
         }
         if (mDisplayRotation.isWaitingForRemoteRotation()) {
             return;
         }
-        final boolean configUpdated = mActivityDisplay.updateDisplayOverrideConfigurationLocked();
+        // TODO(display-merge): Remove cast
+        final boolean configUpdated =
+                ((ActivityDisplay) this).updateDisplayOverrideConfigurationLocked();
         if (configUpdated) {
             return;
         }
@@ -1199,7 +1186,8 @@
 
         if (handled && requestingContainer instanceof ActivityRecord) {
             final ActivityRecord activityRecord = (ActivityRecord) requestingContainer;
-            final boolean kept = mActivityDisplay.updateDisplayOverrideConfigurationLocked(
+            // TODO(display-merge): Remove cast
+            final boolean kept = ((ActivityDisplay) this).updateDisplayOverrideConfigurationLocked(
                     config, activityRecord, false /* deferResume */, null /* result */);
             activityRecord.frozenBeforeDestroy = true;
             if (!kept) {
@@ -1208,7 +1196,8 @@
         } else {
             // We have a new configuration to push so we need to update ATMS for now.
             // TODO: Clean up display configuration push between ATMS and WMS after unification.
-            mActivityDisplay.updateDisplayOverrideConfigurationLocked(
+            // TODO(display-merge): Remove cast
+            ((ActivityDisplay) this.mDisplayContent).updateDisplayOverrideConfigurationLocked(
                     config, null /* starting */, false /* deferResume */, null);
         }
         return handled;
@@ -1797,12 +1786,15 @@
         return mTaskStackContainers.getHomeStack();
     }
 
+    ActivityStack getRecentsStack() {
+        return mTaskStackContainers.getRecentsStack();
+    }
+
     /**
-     * @return The primary split-screen stack, but only if it is visible, and {@code null} otherwise.
+     * @return The primary split-screen stack, and {@code null} otherwise.
      */
     ActivityStack getSplitScreenPrimaryStack() {
-        ActivityStack stack = mTaskStackContainers.getSplitScreenPrimaryStack();
-        return (stack != null && stack.isVisible()) ? stack : null;
+        return mTaskStackContainers.getSplitScreenPrimaryStack();
     }
 
     boolean hasSplitScreenPrimaryStack() {
@@ -1841,6 +1833,22 @@
         return mTaskStackContainers.getStack(windowingMode, activityType);
     }
 
+    protected int getStackCount() {
+        return mTaskStackContainers.mChildren.size();
+    }
+
+    protected ActivityStack getStackAt(int index) {
+        return mTaskStackContainers.mChildren.get(index);
+    }
+
+    int getIndexOf(ActivityStack stack) {
+        return mTaskStackContainers.getIndexOf(stack);
+    }
+
+    void removeStack(ActivityStack stack) {
+        mTaskStackContainers.removeChild(stack);
+    }
+
     @VisibleForTesting
     WindowList<ActivityStack> getStacks() {
         return mTaskStackContainers.mChildren;
@@ -2208,11 +2216,6 @@
         stack.reparent(mTaskStackContainers, onTop ? POSITION_TOP: POSITION_BOTTOM);
     }
 
-    // TODO(display-unify): No longer needed then.
-    void removeStackFromDisplay(ActivityStack stack) {
-        mTaskStackContainers.removeChild(stack);
-    }
-
     @Override
     protected void addChild(DisplayChildWindowContainer child,
             Comparator<DisplayChildWindowContainer> comparator) {
@@ -2364,9 +2367,6 @@
     void removeImmediately() {
         mRemovingDisplay = true;
         try {
-            if (mActivityDisplay != null) {
-                mActivityDisplay.unregisterConfigurationChangeListener(this);
-            }
             if (mParentWindow != null) {
                 mParentWindow.removeEmbeddedDisplayContent(this);
             }
@@ -2386,7 +2386,9 @@
             mWindowingLayer.release();
             mOverlayLayer.release();
             mInputMonitor.onDisplayRemoved();
-            mWmService.mDisplayNotificationController.dispatchDisplayRemoved(mActivityDisplay);
+            // TODO(display-merge): Remove cast
+            mWmService.mDisplayNotificationController
+                .dispatchDisplayRemoved((ActivityDisplay) this);
         } finally {
             mDisplayReady = false;
             mRemovingDisplay = false;
@@ -2482,7 +2484,7 @@
                 && !mDividerControllerLocked.isImeHideRequested();
         final ActivityStack dockedStack = getSplitScreenPrimaryStack();
         final boolean dockVisible = dockedStack != null;
-        final Task topDockedTask = dockVisible ? dockedStack.getTopChild() : null;
+        final Task topDockedTask = dockVisible ? dockedStack.getTask((t) -> true): null;
         final ActivityStack imeTargetStack = mWmService.getImeFocusStackLocked();
         final int imeDockSide = (dockVisible && imeTargetStack != null) ?
                 imeTargetStack.getDockSide() : DOCKED_INVALID;
@@ -2599,9 +2601,8 @@
         }
     }
 
-    @CallSuper
-    @Override
-    public void writeToProto(ProtoOutputStream proto, long fieldId,
+    // TODO(proto-merge): Remove once protos for ActivityDisplay and DisplayContent are merged.
+    public void dumpDebugInner(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
         // Critical log level logs only visible elements to mitigate performance overheard
         if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
@@ -2609,35 +2610,35 @@
         }
 
         final long token = proto.start(fieldId);
-        super.writeToProto(proto, WINDOW_CONTAINER, logLevel);
+        super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
         proto.write(ID, mDisplayId);
         for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
             final ActivityStack stack = mTaskStackContainers.getChildAt(stackNdx);
-            stack.writeToProtoInnerStackOnly(proto, STACKS, logLevel);
+            stack.dumpDebugInnerStackOnly(proto, STACKS, logLevel);
         }
-        mDividerControllerLocked.writeToProto(proto, DOCKED_STACK_DIVIDER_CONTROLLER);
-        mPinnedStackControllerLocked.writeToProto(proto, PINNED_STACK_CONTROLLER);
+        mDividerControllerLocked.dumpDebug(proto, DOCKED_STACK_DIVIDER_CONTROLLER);
+        mPinnedStackControllerLocked.dumpDebug(proto, PINNED_STACK_CONTROLLER);
         for (int i = mAboveAppWindowsContainers.getChildCount() - 1; i >= 0; --i) {
             final WindowToken windowToken = mAboveAppWindowsContainers.getChildAt(i);
-            windowToken.writeToProto(proto, ABOVE_APP_WINDOWS, logLevel);
+            windowToken.dumpDebug(proto, ABOVE_APP_WINDOWS, logLevel);
         }
         for (int i = mBelowAppWindowsContainers.getChildCount() - 1; i >= 0; --i) {
             final WindowToken windowToken = mBelowAppWindowsContainers.getChildAt(i);
-            windowToken.writeToProto(proto, BELOW_APP_WINDOWS, logLevel);
+            windowToken.dumpDebug(proto, BELOW_APP_WINDOWS, logLevel);
         }
         for (int i = mImeWindowsContainers.getChildCount() - 1; i >= 0; --i) {
             final WindowToken windowToken = mImeWindowsContainers.getChildAt(i);
-            windowToken.writeToProto(proto, IME_WINDOWS, logLevel);
+            windowToken.dumpDebug(proto, IME_WINDOWS, logLevel);
         }
         proto.write(DPI, mBaseDisplayDensity);
-        mDisplayInfo.writeToProto(proto, DISPLAY_INFO);
+        mDisplayInfo.dumpDebug(proto, DISPLAY_INFO);
         proto.write(ROTATION, getRotation());
         final ScreenRotationAnimation screenRotationAnimation = getRotationAnimation();
         if (screenRotationAnimation != null) {
-            screenRotationAnimation.writeToProto(proto, SCREEN_ROTATION_ANIMATION);
+            screenRotationAnimation.dumpDebug(proto, SCREEN_ROTATION_ANIMATION);
         }
-        mDisplayFrames.writeToProto(proto, DISPLAY_FRAMES);
-        mAppTransition.writeToProto(proto, APP_TRANSITION);
+        mDisplayFrames.dumpDebug(proto, DISPLAY_FRAMES);
+        mAppTransition.dumpDebug(proto, APP_TRANSITION);
         if (mFocusedApp != null) {
             mFocusedApp.writeNameToProto(proto, FOCUSED_APP);
         }
@@ -3929,6 +3930,7 @@
         // Cached reference to some special stacks we tend to get a lot so we don't need to loop
         // through the list to find them.
         private ActivityStack mHomeStack = null;
+        private ActivityStack mRecentsStack = null;
         private ActivityStack mPinnedStack = null;
         private ActivityStack mSplitScreenPrimaryStack = null;
 
@@ -3936,12 +3938,6 @@
             super(service);
         }
 
-        @Override
-        public void onConfigurationChanged(Configuration newParentConfig) {
-            // TODO(display-unify): Remove after unification.
-            onConfigurationChanged(newParentConfig, mActivityDisplay == null /*forwardToChildren*/);
-        }
-
         /**
          * Returns the topmost stack on the display that is compatible with the input windowing mode
          * and activity type. Null is no compatible stack on the display.
@@ -3976,6 +3972,10 @@
                     ? mTaskStackContainers.getChildAt(mTaskStackContainers.getChildCount() - 1) : null;
         }
 
+        int getIndexOf(ActivityStack stack) {
+            return mTaskStackContainers.mChildren.indexOf(stack);
+        }
+
         ActivityStack getHomeStack() {
             if (mHomeStack == null && mDisplayId == DEFAULT_DISPLAY) {
                 Slog.e(TAG_WM, "getHomeStack: Returning null from this=" + this);
@@ -3983,6 +3983,10 @@
             return mHomeStack;
         }
 
+        ActivityStack getRecentsStack() {
+            return mRecentsStack;
+        }
+
         ActivityStack getPinnedStack() {
             return mPinnedStack;
         }
@@ -4018,6 +4022,13 @@
 
                 }
                 mHomeStack = stack;
+            } else if (stack.isActivityTypeRecents()) {
+                if (mRecentsStack != null && mRecentsStack != stack) {
+                    throw new IllegalArgumentException(
+                        "addStackReferenceIfNeeded: recents stack=" + mRecentsStack
+                            + " already exist on display=" + this + " stack=" + stack);
+                }
+                mRecentsStack = stack;
             }
             final int windowingMode = stack.getWindowingMode();
             if (windowingMode == WINDOWING_MODE_PINNED) {
@@ -4034,17 +4045,23 @@
                             + " already exist on display=" + this + " stack=" + stack);
                 }
                 mSplitScreenPrimaryStack = stack;
+                // TODO(display-merge): Remove cast
+                ((ActivityDisplay) this.mDisplayContent).onSplitScreenModeActivated();
                 mDividerControllerLocked.notifyDockedStackExistsChanged(true);
             }
         }
 
-        private void removeStackReferenceIfNeeded(ActivityStack stack) {
+        void removeStackReferenceIfNeeded(ActivityStack stack) {
             if (stack == mHomeStack) {
                 mHomeStack = null;
+            } else if (stack == mRecentsStack) {
+                mRecentsStack = null;
             } else if (stack == mPinnedStack) {
                 mPinnedStack = null;
             } else if (stack == mSplitScreenPrimaryStack) {
                 mSplitScreenPrimaryStack = null;
+                // TODO(display-merge): Remove cast
+                ((ActivityDisplay) this.mDisplayContent).onSplitScreenModeDismissed();
                 // Re-set the split-screen create mode whenever the split-screen stack is removed.
                 mWmService.setDockedStackCreateStateLocked(
                         SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */);
@@ -4058,9 +4075,6 @@
             position = findPositionForStack(position, stack, true /* adding */);
 
             super.addChild(stack, position);
-            if (mActivityDisplay != null) {
-                mActivityDisplay.addChild(stack, position, true /*fromDc*/);
-            }
 
             // The reparenting case is handled in WindowContainer.
             if (!stack.mReparenting) {
@@ -4072,9 +4086,8 @@
         @Override
         protected void removeChild(ActivityStack stack) {
             super.removeChild(stack);
-            if (mActivityDisplay != null) {
-                mActivityDisplay.onChildRemoved(stack);
-            }
+            // TODO(display-merge): Remove cast
+            ((ActivityDisplay) this.mDisplayContent).onStackRemoved(stack);
             removeStackReferenceIfNeeded(stack);
         }
 
@@ -4087,7 +4100,7 @@
         @Override
         void positionChildAt(int position, ActivityStack child, boolean includingParents) {
             if (child.getWindowConfiguration().isAlwaysOnTop()
-                    && position != POSITION_TOP) {
+                    && position != POSITION_TOP && position != mChildren.size()) {
                 // This stack is always-on-top, override the default behavior.
                 Slog.w(TAG_WM, "Ignoring move of always-on-top stack=" + this + " to bottom");
 
@@ -4097,7 +4110,11 @@
                 super.positionChildAt(currentPosition, child, false /* includingParents */);
                 return;
             }
-
+            // We don't allow untrusted display to top when task stack moves to top,
+            // until user tapping this display to change display position as top intentionally.
+            if (isUntrustedVirtualDisplay() && !getParent().isOnTop()) {
+                includingParents = false;
+            }
             final int targetPosition = findPositionForStack(position, child, false /* adding */);
             super.positionChildAt(targetPosition, child, includingParents);
 
@@ -4133,7 +4150,12 @@
             final int topChildPosition = mChildren.size() - 1;
             int belowAlwaysOnTopPosition = POSITION_BOTTOM;
             for (int i = topChildPosition; i >= 0; --i) {
-                if (getStacks().get(i) != stack && !getStacks().get(i).isAlwaysOnTop()) {
+                // Since a stack could be repositioned while being one of the child, return
+                // current index if that's the same stack we are positioning and it is always on
+                // top.
+                final boolean sameStack = getStacks().get(i) == stack;
+                if ((sameStack && stack.isAlwaysOnTop())
+                        || (!sameStack && !getStacks().get(i).isAlwaysOnTop())) {
                     belowAlwaysOnTopPosition = i;
                     break;
                 }
@@ -4158,10 +4180,6 @@
                         POSITION_BOTTOM ? belowAlwaysOnTopPosition : 0;
             }
 
-            int targetPosition = requestedPosition;
-            targetPosition = Math.min(targetPosition, maxPosition);
-            targetPosition = Math.max(targetPosition, minPosition);
-
             // Cap the requested position to something reasonable for the previous position check
             // below.
             if (requestedPosition == POSITION_TOP) {
@@ -4170,6 +4188,10 @@
                 requestedPosition = 0;
             }
 
+            int targetPosition = requestedPosition;
+            targetPosition = Math.min(targetPosition, maxPosition);
+            targetPosition = Math.max(targetPosition, minPosition);
+
             int prevPosition = getStacks().indexOf(stack);
             // The positions we calculated above (maxPosition, minPosition) do not take into
             // consideration the following edge cases.
diff --git a/services/core/java/com/android/server/wm/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java
index 6b47c8a..f8495b5 100644
--- a/services/core/java/com/android/server/wm/DisplayFrames.java
+++ b/services/core/java/com/android/server/wm/DisplayFrames.java
@@ -152,9 +152,9 @@
         return mDock.bottom - mCurrent.bottom;
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
-        mStable.writeToProto(proto, STABLE_BOUNDS);
+        mStable.dumpDebug(proto, STABLE_BOUNDS);
         proto.end(token);
     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 77e557b..2283041 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2215,9 +2215,22 @@
     }
 
     private void offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames) {
+        final int rotation = displayFrames.mRotation;
+        final int navBarPosition = navigationBarPosition(displayFrames.mDisplayWidth,
+                displayFrames.mDisplayHeight, rotation);
+
         int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
         top += win.getGivenContentInsetsLw().top;
         displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom, top);
+        if (navBarPosition == NAV_BAR_BOTTOM) {
+            // Always account for the nav bar frame height on the bottom since in all navigation
+            // modes we make room to show the dismiss-ime button, even if the IME does not report
+            // insets (ie. when floating)
+            final int uimode = mService.mPolicy.getUiMode();
+            final int navFrameHeight = getNavigationBarFrameHeight(rotation, uimode);
+            displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom,
+                    displayFrames.mUnrestricted.bottom - navFrameHeight);
+        }
         displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
         top = win.getVisibleFrameLw().top;
         top += win.getGivenVisibleInsetsLw().top;
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index c76d03c..c7c3f8a 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -52,6 +52,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.IDisplayWindowRotationCallback;
+import android.view.IWindowManager;
 import android.view.Surface;
 import android.view.WindowContainerTransaction;
 
@@ -184,32 +185,11 @@
     private boolean mDefaultFixedToUserRotation;
 
     /**
-     * No overridden behavior is provided in terms of fixing rotation to user rotation. Use other
-     * flags to derive the default behavior, such as {@link WindowManagerService#mIsPc} and
-     * {@link WindowManagerService#mForceDesktopModeOnExternalDisplays}.
-     */
-    static final int FIXED_TO_USER_ROTATION_DEFAULT = 0;
-    /**
-     * Don't fix display rotation to {@link #mUserRotation} only. Always allow other factors to play
-     * a role in deciding display rotation.
-     */
-    static final int FIXED_TO_USER_ROTATION_DISABLED = 1;
-    /**
-     * Only use {@link #mUserRotation} as the display rotation.
-     */
-    static final int FIXED_TO_USER_ROTATION_ENABLED = 2;
-    @IntDef({ FIXED_TO_USER_ROTATION_DEFAULT, FIXED_TO_USER_ROTATION_DISABLED,
-            FIXED_TO_USER_ROTATION_ENABLED })
-    @Retention(RetentionPolicy.SOURCE)
-    @interface FixedToUserRotation {}
-
-    /**
      * A flag to indicate if the display rotation should be fixed to user specified rotation
      * regardless of all other states (including app requrested orientation). {@code true} the
      * display rotation should be fixed to user specified rotation, {@code false} otherwise.
      */
-    @FixedToUserRotation
-    private int mFixedToUserRotation = FIXED_TO_USER_ROTATION_DEFAULT;
+    private int mFixedToUserRotation = IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT;
 
     private int mDemoHdmiRotation;
     private int mDemoRotation;
@@ -723,8 +703,7 @@
         }
     }
 
-    void restoreSettings(int userRotationMode, int userRotation,
-            @FixedToUserRotation int fixedToUserRotation) {
+    void restoreSettings(int userRotationMode, int userRotation, int fixedToUserRotation) {
         mFixedToUserRotation = fixedToUserRotation;
 
         // We will retrieve user rotation and user rotation mode from settings for default display.
@@ -746,7 +725,7 @@
         mUserRotation = userRotation;
     }
 
-    void setFixedToUserRotation(@FixedToUserRotation int fixedToUserRotation) {
+    void setFixedToUserRotation(int fixedToUserRotation) {
         if (mFixedToUserRotation == fixedToUserRotation) {
             return;
         }
@@ -808,9 +787,9 @@
 
     boolean isFixedToUserRotation() {
         switch (mFixedToUserRotation) {
-            case FIXED_TO_USER_ROTATION_DISABLED:
+            case IWindowManager.FIXED_TO_USER_ROTATION_DISABLED:
                 return false;
-            case FIXED_TO_USER_ROTATION_ENABLED:
+            case IWindowManager.FIXED_TO_USER_ROTATION_ENABLED:
                 return true;
             default:
                 return mDefaultFixedToUserRotation;
diff --git a/services/core/java/com/android/server/wm/DisplayWindowListenerController.java b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
index 2da76ea..78fea74 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
@@ -63,7 +63,7 @@
         mDisplayListeners.finishBroadcast();
     }
 
-    void dispatchDisplayChanged(ActivityDisplay display, Configuration newConfig) {
+    void dispatchDisplayChanged(DisplayContent display, Configuration newConfig) {
         // Only report changed if this has actually been added to the hierarchy already.
         boolean isInHierarchy = false;
         for (int i = 0; i < display.getParent().getChildCount(); ++i) {
@@ -78,7 +78,7 @@
         for (int i = 0; i < count; ++i) {
             try {
                 mDisplayListeners.getBroadcastItem(i).onDisplayConfigurationChanged(
-                        display.mDisplayId, newConfig);
+                        display.getDisplayId(), newConfig);
             } catch (RemoteException e) {
             }
         }
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index dac8b14..470a02e 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -22,7 +22,6 @@
 
 import static com.android.server.wm.DisplayContent.FORCE_SCALING_MODE_AUTO;
 import static com.android.server.wm.DisplayContent.FORCE_SCALING_MODE_DISABLED;
-import static com.android.server.wm.DisplayRotation.FIXED_TO_USER_ROTATION_DEFAULT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
@@ -38,6 +37,7 @@
 import android.view.Display;
 import android.view.DisplayAddress;
 import android.view.DisplayInfo;
+import android.view.IWindowManager;
 import android.view.Surface;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -111,8 +111,7 @@
         private boolean mShouldShowWithInsecureKeyguard = false;
         private boolean mShouldShowSystemDecors = false;
         private boolean mShouldShowIme = false;
-        private @DisplayRotation.FixedToUserRotation int mFixedToUserRotation =
-                FIXED_TO_USER_ROTATION_DEFAULT;
+        private int mFixedToUserRotation = IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT;
 
         private Entry(String name) {
             mName = name;
@@ -145,7 +144,7 @@
                     && !mShouldShowWithInsecureKeyguard
                     && !mShouldShowSystemDecors
                     && !mShouldShowIme
-                    && mFixedToUserRotation == FIXED_TO_USER_ROTATION_DEFAULT;
+                    && mFixedToUserRotation == IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT;
         }
     }
 
@@ -242,8 +241,7 @@
         writeSettingsIfNeeded(entry, displayInfo);
     }
 
-    void setFixedToUserRotation(DisplayContent displayContent,
-            @DisplayRotation.FixedToUserRotation int fixedToUserRotation) {
+    void setFixedToUserRotation(DisplayContent displayContent, int fixedToUserRotation) {
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
         final Entry entry = getOrCreateEntry(displayInfo);
         entry.mFixedToUserRotation = fixedToUserRotation;
@@ -610,7 +608,7 @@
                 if (entry.mShouldShowIme) {
                     out.attribute(null, "shouldShowIme", Boolean.toString(entry.mShouldShowIme));
                 }
-                if (entry.mFixedToUserRotation != FIXED_TO_USER_ROTATION_DEFAULT) {
+                if (entry.mFixedToUserRotation != IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT) {
                     out.attribute(null, "fixedToUserRotation",
                             Integer.toString(entry.mFixedToUserRotation));
                 }
@@ -644,7 +642,8 @@
         if (mIdentifier == IDENTIFIER_PORT && displayInfo.address != null) {
             // Config suggests using port as identifier for physical displays.
             if (displayInfo.address instanceof DisplayAddress.Physical) {
-                return "port:" + ((DisplayAddress.Physical) displayInfo.address).getPort();
+                byte port = ((DisplayAddress.Physical) displayInfo.address).getPort();
+                return "port:" + Byte.toUnsignedInt(port);
             }
         }
         return displayInfo.uniqueId;
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 07d5094..1a1a7d4 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -1018,7 +1018,7 @@
         pw.println(prefix + "  mAdjustedForDivider=" + mAdjustedForDivider);
     }
 
-    void writeToProto(ProtoOutputStream proto, long fieldId) {
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(MINIMIZED_DOCK, mMinimizedDock);
         proto.end(token);
diff --git a/services/core/java/com/android/server/wm/EventLogTags.logtags b/services/core/java/com/android/server/wm/EventLogTags.logtags
new file mode 100644
index 0000000..aab901e
--- /dev/null
+++ b/services/core/java/com/android/server/wm/EventLogTags.logtags
@@ -0,0 +1,77 @@
+# See system/core/logcat/event.logtags for a description of the format of this file.
+
+option java_package com.android.server.wm
+
+# Do not change these names without updating the checkin_events setting in
+# google3/googledata/wireless/android/provisioning/gservices.config !!
+#
+# An activity is being finished:
+30001 wm_finish_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3),(Reason|3)
+# A task is being brought to the front of the screen:
+30002 wm_task_to_front (User|1|5),(Task|1|5)
+# An existing activity is being given a new intent:
+30003 wm_new_intent (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3),(Action|3),(MIME Type|3),(URI|3),(Flags|1|5)
+# A new task is being created:
+30004 wm_create_task (User|1|5),(Task ID|1|5)
+# A new activity is being created in an existing task:
+30005 wm_create_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3),(Action|3),(MIME Type|3),(URI|3),(Flags|1|5)
+# An activity has been resumed into the foreground but was not already running:
+30006 wm_restart_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3)
+# An activity has been resumed and is now in the foreground:
+30007 wm_resume_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3)
+
+# Activity launch time
+30009 wm_activity_launch_time (User|1|5),(Token|1|5),(Component Name|3),(time|2|3)
+
+# The Activity Manager failed to pause the given activity.
+30012 wm_failed_to_pause (User|1|5),(Token|1|5),(Wanting to pause|3),(Currently pausing|3)
+# Attempting to pause the current activity
+30013 wm_pause_activity (User|1|5),(Token|1|5),(Component Name|3),(User Leaving|3)
+# Application process has been started
+
+# An activity is being destroyed:
+30018 wm_destroy_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3),(Reason|3)
+# An activity has been relaunched, resumed, and is now in the foreground:
+30019 wm_relaunch_resume_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3)
+# An activity has been relaunched:
+30020 wm_relaunch_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3)
+# The activity's onPause has been called.
+30021 wm_on_paused_called (Token|1|5),(Component Name|3),(Reason|3)
+# The activity's onResume has been called.
+30022 wm_on_resume_called (Token|1|5),(Component Name|3),(Reason|3)
+
+# Activity set to resumed
+30043 wm_set_resumed_activity (User|1|5),(Component Name|3),(Reason|3)
+
+# Stack focus
+30044 wm_focused_stack (User|1|5),(Display Id|1|5),(Focused Stack Id|1|5),(Last Focused Stack Id|1|5),(Reason|3)
+
+# Attempting to stop an activity
+30048 wm_stop_activity (User|1|5),(Token|1|5),(Component Name|3)
+
+# The task is being removed from its parent stack
+30061 wm_remove_task (Task ID|1|5), (Stack ID|1|5)
+
+# An activity been add into stopping list
+30066 wm_add_to_stopping (User|1|5),(Token|1|5),(Component Name|3),(Reason|3)
+
+# Keyguard status changed
+30067 wm_set_keyguard_shown (keyguardShowing|1),(aodShowing|1),(keyguardGoingAway|1),(Reason|3)
+
+# Out of memory for surfaces.
+31000 wm_no_surface_memory (Window|3),(PID|1|5),(Operation|3)
+# Task created.
+31001 wm_task_created (TaskId|1|5),(StackId|1|5)
+# Task moved to top (1) or bottom (0).
+31002 wm_task_moved (TaskId|1|5),(ToTop|1),(Index|1)
+# Task removed with source explanation.
+31003 wm_task_removed (TaskId|1|5),(Reason|3)
+# Stack created.
+31004 wm_stack_created (StackId|1|5)
+# Home stack moved to top (1) or bottom (0).
+31005 wm_home_stack_moved (ToTop|1)
+# Stack removed.
+31006 wm_stack_removed (StackId|1|5)
+# bootanim finished:
+31007 wm_boot_animation_done (time|2|3)
+
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index b4055545..69e8fdc 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -293,7 +293,7 @@
         }
 
         @Override
-        public void writeToProto(ProtoOutputStream proto) {
+        public void dumpDebug(ProtoOutputStream proto) {
         }
     }
 }
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 52cc422..ac5c96b 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -43,13 +43,11 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.Trace;
-import android.util.EventLog;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.policy.IKeyguardDismissCallback;
-import com.android.server.am.EventLogTags;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
 
@@ -143,7 +141,7 @@
         if (!keyguardChanged && !aodChanged) {
             return;
         }
-        EventLog.writeEvent(EventLogTags.AM_SET_KEYGUARD_SHOWN,
+        EventLogTags.writeWmSetKeyguardShown(
                 keyguardShowing ? 1 : 0,
                 aodShowing ? 1 : 0,
                 mKeyguardGoingAway ? 1 : 0,
@@ -184,7 +182,7 @@
         mService.deferWindowLayout();
         try {
             setKeyguardGoingAway(true);
-            EventLog.writeEvent(EventLogTags.AM_SET_KEYGUARD_SHOWN,
+            EventLogTags.writeWmSetKeyguardShown(
                     1 /* keyguardShowing */,
                     mAodShowing ? 1 : 0,
                     1 /* keyguardGoingAway */,
@@ -198,8 +196,7 @@
             // Some stack visibility might change (e.g. docked stack)
             mRootActivityContainer.resumeFocusedStacksTopActivities();
             mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
-            mRootActivityContainer.addStartingWindowsForVisibleActivities(
-                    true /* taskSwitch */);
+            mRootActivityContainer.addStartingWindowsForVisibleActivities();
             mWindowManager.executeAppTransition();
         } finally {
             mService.continueWindowLayout();
@@ -534,8 +531,8 @@
          * occlusion state.
          */
         private ActivityStack getStackForControllingOccluding(ActivityDisplay display) {
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
+            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getStackAt(stackNdx);
                 if (stack != null && stack.isFocusableAndVisible()
                         && !stack.inPinnedWindowingMode()) {
                     return stack;
@@ -555,7 +552,7 @@
             pw.println(sb.toString());
         }
 
-        void writeToProto(ProtoOutputStream proto, long fieldId) {
+        void dumpDebug(ProtoOutputStream proto, long fieldId) {
             final long token = proto.start(fieldId);
             proto.write(DISPLAY_ID, mDisplayId);
             proto.write(KEYGUARD_OCCLUDED, mOccluded);
@@ -573,7 +570,7 @@
         pw.println(prefix + "  mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);
     }
 
-    void writeToProto(ProtoOutputStream proto, long fieldId) {
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(AOD_SHOWING, mAodShowing);
         proto.write(KEYGUARD_SHOWING, mKeyguardShowing);
@@ -589,7 +586,7 @@
 
     private void writeDisplayStatesToProto(ProtoOutputStream proto, long fieldId) {
         for (int i = 0; i < mDisplayStates.size(); i++) {
-            mDisplayStates.valueAt(i).writeToProto(proto, fieldId);
+            mDisplayStates.valueAt(i).dumpDebug(proto, fieldId);
         }
     }
 }
diff --git a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
index e67cb6fc..5892239 100644
--- a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
@@ -76,9 +76,9 @@
     }
 
     @Override
-    public void writeToProto(ProtoOutputStream proto) {
+    public void dumpDebug(ProtoOutputStream proto) {
         final long token = proto.start(LOCAL);
-        mSpec.writeToProto(proto, ANIMATION_SPEC);
+        mSpec.dumpDebug(proto, ANIMATION_SPEC);
         proto.end(token);
     }
 
@@ -131,12 +131,12 @@
 
         void dump(PrintWriter pw, String prefix);
 
-        default void writeToProto(ProtoOutputStream proto, long fieldId) {
+        default void dumpDebug(ProtoOutputStream proto, long fieldId) {
             final long token = proto.start(fieldId);
-            writeToProtoInner(proto);
+            dumpDebugInner(proto);
             proto.end(token);
         }
 
-        void writeToProtoInner(ProtoOutputStream proto);
+        void dumpDebugInner(ProtoOutputStream proto);
     }
 }
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index a5b1fda..a8e7aea 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -236,10 +236,10 @@
     /**
      * Saves the current snap fraction for re-entry of the current activity into PiP.
      */
-    void saveReentrySnapFraction(final ComponentName componentName, final Rect stackBounds) {
+    void saveReentryBounds(final ComponentName componentName, final Rect stackBounds) {
         if (mPinnedStackListener == null) return;
         try {
-            mPinnedStackListener.onSaveReentrySnapFraction(componentName, stackBounds);
+            mPinnedStackListener.onSaveReentryBounds(componentName, stackBounds);
         } catch (RemoteException e) {
             Slog.e(TAG_WM, "Error delivering save reentry fraction event.", e);
         }
@@ -248,10 +248,10 @@
     /**
      * Resets the last saved snap fraction so that the default bounds will be returned.
      */
-    void resetReentrySnapFraction(ComponentName componentName) {
+    void resetReentryBounds(ComponentName componentName) {
         if (mPinnedStackListener == null) return;
         try {
-            mPinnedStackListener.onResetReentrySnapFraction(componentName);
+            mPinnedStackListener.onResetReentryBounds(componentName);
         } catch (RemoteException e) {
             Slog.e(TAG_WM, "Error delivering reset reentry fraction event.", e);
         }
@@ -604,11 +604,11 @@
         pw.println(prefix + "  mDisplayInfo=" + mDisplayInfo);
     }
 
-    void writeToProto(ProtoOutputStream proto, long fieldId) {
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
-        getDefaultBounds(INVALID_SNAP_FRACTION).writeToProto(proto, DEFAULT_BOUNDS);
+        getDefaultBounds(INVALID_SNAP_FRACTION).dumpDebug(proto, DEFAULT_BOUNDS);
         mService.getStackBounds(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mTmpRect);
-        getMovementBounds(mTmpRect).writeToProto(proto, MOVEMENT_BOUNDS);
+        getMovementBounds(mTmpRect).dumpDebug(proto, MOVEMENT_BOUNDS);
         proto.end(token);
     }
 }
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 824a3c8..d5bbe6b 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -42,7 +42,10 @@
 import android.util.Slog;
 import android.view.IRecentsAnimationRunner;
 
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.util.function.pooled.PooledPredicate;
 import com.android.server.protolog.common.ProtoLog;
+import com.android.server.wm.ActivityMetricsLogger.LaunchingState;
 import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks;
 
 /**
@@ -194,7 +197,8 @@
                     true /* forceSend */, targetActivity);
         }
 
-        mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching(mTargetIntent);
+        final LaunchingState launchingState =
+                mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching(mTargetIntent);
 
         if (mCaller != null) {
             mCaller.setRunningRecentsAnimation(true);
@@ -253,8 +257,8 @@
             // we fetch the visible tasks to be controlled by the animation
             mService.mRootActivityContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
 
-            mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunched(START_TASK_TO_FRONT,
-                    targetActivity);
+            mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState,
+                    START_TASK_TO_FRONT, targetActivity);
 
             // Register for stack order changes
             mDefaultDisplay.registerStackOrderChangedListener(this);
@@ -471,8 +475,8 @@
      * @return The top stack that is not always-on-top.
      */
     private ActivityStack getTopNonAlwaysOnTopStack() {
-        for (int i = mDefaultDisplay.getChildCount() - 1; i >= 0; i--) {
-            final ActivityStack s = mDefaultDisplay.getChildAt(i);
+        for (int i = mDefaultDisplay.getStackCount() - 1; i >= 0; i--) {
+            final ActivityStack s = mDefaultDisplay.getStackAt(i);
             if (s.getWindowConfiguration().isAlwaysOnTop()) {
                 continue;
             }
@@ -490,13 +494,15 @@
             return null;
         }
 
-        for (int i = targetStack.getChildCount() - 1; i >= 0; i--) {
-            final Task task = targetStack.getChildAt(i);
-            if (task.mUserId == mUserId
-                    && task.getBaseIntent().getComponent().equals(mTargetIntent.getComponent())) {
-                return task.getTopNonFinishingActivity();
-            }
-        }
-        return null;
+        final PooledPredicate p = PooledLambda.obtainPredicate(RecentsAnimation::matchesTarget,
+                this, PooledLambda.__(Task.class));
+        final Task task = targetStack.getTask(p);
+        p.recycle();
+        return task != null ? task.getTopNonFinishingActivity() : null;
+    }
+
+    private boolean matchesTarget(Task task) {
+        return task.mUserId == mUserId
+                && task.getBaseIntent().getComponent().equals(mTargetIntent.getComponent());
     }
 }
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 282144e..39091a6 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
@@ -42,10 +41,10 @@
 import android.os.IBinder.DeathRecipient;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
 import android.util.proto.ProtoOutputStream;
 import android.view.IRecentsAnimationController;
 import android.view.IRecentsAnimationRunner;
@@ -55,6 +54,9 @@
 import android.view.SurfaceControl.Transaction;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.function.pooled.PooledConsumer;
+import com.android.internal.util.function.pooled.PooledFunction;
+import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.LocalServices;
 import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.protolog.common.ProtoLog;
@@ -369,13 +371,13 @@
         final ActivityStack targetStack = mDisplayContent.getStack(WINDOWING_MODE_UNDEFINED,
                 targetActivityType);
         if (targetStack != null) {
-            for (int i = targetStack.getChildCount() - 1; i >= 0; i--) {
-                final Task t = targetStack.getChildAt(i);
-                if (!visibleTasks.contains(t)) {
-                    visibleTasks.add(t);
-                }
-            }
+            final PooledConsumer c = PooledLambda.obtainConsumer((t, outList) ->
+	            { if (!outList.contains(t)) outList.add(t); }, PooledLambda.__(Task.class),
+                    visibleTasks);
+            targetStack.forAllTasks(c);
+            c.recycle();
         }
+
         final int taskCount = visibleTasks.size();
         for (int i = 0; i < taskCount; i++) {
             final Task task = visibleTasks.get(i);
@@ -499,10 +501,13 @@
         } catch (RemoteException e) {
             Slog.e(TAG, "Failed to start recents animation", e);
         }
-        final SparseIntArray reasons = new SparseIntArray();
-        reasons.put(WINDOWING_MODE_FULLSCREEN, APP_TRANSITION_RECENTS_ANIM);
-        mService.mAtmInternal
-            .notifyAppTransitionStarting(reasons, SystemClock.elapsedRealtimeNanos());
+
+        if (mTargetActivityRecord != null) {
+            final ArrayMap<ActivityRecord, Integer> reasons = new ArrayMap<>(1);
+            reasons.put(mTargetActivityRecord, APP_TRANSITION_RECENTS_ANIM);
+            mService.mAtmService.mStackSupervisor.getActivityMetricsLogger()
+                    .notifyTransitionStarting(reasons);
+        }
     }
 
     private RemoteAnimationTarget[] createAppAnimations() {
@@ -800,12 +805,12 @@
     private boolean isAnimatingApp(ActivityRecord activity) {
         for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
             final Task task = mPendingAnimations.get(i).mTask;
-            for (int j = task.getChildCount() - 1; j >= 0; j--) {
-                final ActivityRecord app = task.getChildAt(j);
-                if (app == activity) {
-                    return true;
-                }
-            }
+            final PooledFunction f = PooledLambda.obtainFunction(
+                    (a, b) -> a == b, activity,
+                    PooledLambda.__(ActivityRecord.class));
+            boolean isAnimatingApp = task.forAllActivities(f);
+            f.recycle();
+            return isAnimatingApp;
         }
         return false;
     }
@@ -905,10 +910,10 @@
         }
 
         @Override
-        public void writeToProto(ProtoOutputStream proto) {
+        public void dumpDebug(ProtoOutputStream proto) {
             final long token = proto.start(REMOTE);
             if (mTarget != null) {
-                mTarget.writeToProto(proto, TARGET);
+                mTarget.dumpDebug(proto, TARGET);
             }
             proto.end(token);
         }
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index efd1241..0b9be1a 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -464,10 +464,10 @@
         }
 
         @Override
-        public void writeToProto(ProtoOutputStream proto) {
+        public void dumpDebug(ProtoOutputStream proto) {
             final long token = proto.start(REMOTE);
             if (mRecord.mTarget != null) {
-                mRecord.mTarget.writeToProto(proto, TARGET);
+                mRecord.mTarget.dumpDebug(proto, TARGET);
             }
             proto.end(token);
         }
diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
index 413dfd5..3aa91d5 100644
--- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
+++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
@@ -125,8 +125,7 @@
                     // TODO: We should probably look for other stacks also, since corresponding
                     //  task with the same affinity is unlikely to be in the same stack.
                     final Task targetTask;
-                    final ActivityRecord bottom = mParent.getActivity(
-                            (ar) -> true, false /*traverseTopToBottom*/);
+                    final ActivityRecord bottom = mParent.getBottomMostActivity();
 
                     if (bottom != null && r.taskAffinity.equals(bottom.getTask().affinity)) {
                         // If the activity currently at the bottom has the same task affinity as
@@ -210,10 +209,8 @@
                 // we have put it on top of another instance of the same activity? Then we drop
                 // the instance below so it remains singleTop.
                 if (r.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
-                    final ArrayList<ActivityRecord> taskActivities = mTargetTask.mChildren;
-                    final int targetNdx = taskActivities.indexOf(r);
-                    if (targetNdx > 0) {
-                        final ActivityRecord p = taskActivities.get(targetNdx - 1);
+                    final ActivityRecord p = mTargetTask.getActivityBelow(r);
+                    if (p != null) {
                         if (p.intent.getComponent().equals(r.intent.getComponent())) {
                             p.finishIfPossible("replace", false /* oomAdj */);
                         }
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 8f1d6ee..5653ec0 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -33,6 +33,7 @@
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
+import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
 import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
 
 import static com.android.server.am.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER;
@@ -51,7 +52,6 @@
 import static com.android.server.wm.ActivityStackSupervisor.dumpHistoryList;
 import static com.android.server.wm.ActivityStackSupervisor.printThisActivity;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RELEASE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
@@ -86,6 +86,7 @@
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.power.V1_0.PowerHint;
+import android.net.Uri;
 import android.os.FactoryTest;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -108,6 +109,11 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.ResolverActivity;
+import com.android.internal.util.ToBooleanFunction;
+import com.android.internal.util.function.pooled.PooledConsumer;
+import com.android.internal.util.function.pooled.PooledFunction;
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.util.function.pooled.PooledPredicate;
 import com.android.server.LocalServices;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.am.AppTimeTracker;
@@ -121,6 +127,7 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -201,14 +208,46 @@
 
     // Whether tasks have moved and we need to rank the tasks before next OOM scoring
     private boolean mTaskLayersChanged = true;
+    private int mTmpTaskLayerRank;
 
-    private final ArrayList<ActivityRecord> mTmpActivityList = new ArrayList<>();
+    private boolean mTmpBoolean;
+    private RemoteException mTmpRemoteException;
 
     private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
-    static class FindTaskResult {
+    static class FindTaskResult implements ToBooleanFunction<Task> {
         ActivityRecord mRecord;
         boolean mIdealMatch;
 
+        private ActivityRecord mTarget;
+        private Intent intent;
+        private ActivityInfo info;
+        private ComponentName cls;
+        private int userId;
+        private boolean isDocument;
+        private Uri documentData;
+
+        /**
+         * Returns the top activity in any existing task matching the given Intent in the input
+         * result. Returns null if no such task is found.
+         */
+        void process(ActivityRecord target, ActivityStack parent) {
+            mTarget = target;
+
+            intent = target.intent;
+            info = target.info;
+            cls = intent.getComponent();
+            if (info.targetActivity != null) {
+                cls = new ComponentName(info.packageName, info.targetActivity);
+            }
+            userId = UserHandle.getUserId(info.applicationInfo.uid);
+            isDocument = intent != null & intent.isDocument();
+            // If documentData is non-null then it must match the existing task data.
+            documentData = isDocument ? intent.getData() : null;
+
+            if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + target + " in " + parent);
+            parent.forAllTasks(this);
+        }
+
         void clear() {
             mRecord = null;
             mIdealMatch = false;
@@ -218,6 +257,84 @@
             mRecord = result.mRecord;
             mIdealMatch = result.mIdealMatch;
         }
+
+        @Override
+        public boolean apply(Task task) {
+            if (task.voiceSession != null) {
+                // We never match voice sessions; those always run independently.
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": voice session");
+                return false;
+            }
+            if (task.mUserId != userId) {
+                // Looking for a different task.
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": different user");
+                return false;
+            }
+
+            // Overlays should not be considered as the task's logical top activity.
+            final ActivityRecord r = task.getTopNonFinishingActivity(false /* includeOverlays */);
+            if (r == null || r.finishing || r.mUserId != userId ||
+                    r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch root " + r);
+                return false;
+            }
+            if (!r.hasCompatibleActivityType(mTarget)) {
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch activity type");
+                return false;
+            }
+
+            final Intent taskIntent = task.intent;
+            final Intent affinityIntent = task.affinityIntent;
+            final boolean taskIsDocument;
+            final Uri taskDocumentData;
+            if (taskIntent != null && taskIntent.isDocument()) {
+                taskIsDocument = true;
+                taskDocumentData = taskIntent.getData();
+            } else if (affinityIntent != null && affinityIntent.isDocument()) {
+                taskIsDocument = true;
+                taskDocumentData = affinityIntent.getData();
+            } else {
+                taskIsDocument = false;
+                taskDocumentData = null;
+            }
+
+            if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Comparing existing cls="
+                    + (task.realActivity != null ? task.realActivity.flattenToShortString() : "")
+                    + "/aff=" + r.getTask().rootAffinity + " to new cls="
+                    + intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity);
+            // TODO Refactor to remove duplications. Check if logic can be simplified.
+            if (task.realActivity != null && task.realActivity.compareTo(cls) == 0
+                    && Objects.equals(documentData, taskDocumentData)) {
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
+                //dump();
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS,
+                        "For Intent " + intent + " bringing to top: " + r.intent);
+                mRecord = r;
+                mIdealMatch = true;
+                return true;
+            } else if (affinityIntent != null && affinityIntent.getComponent() != null &&
+                    affinityIntent.getComponent().compareTo(cls) == 0 &&
+                    Objects.equals(documentData, taskDocumentData)) {
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS,
+                        "For Intent " + intent + " bringing to top: " + r.intent);
+                mRecord = r;
+                mIdealMatch = true;
+                return true;
+            } else if (!isDocument && !taskIsDocument
+                    && mRecord == null && task.rootAffinity != null) {
+                if (task.rootAffinity.equals(mTarget.taskAffinity)) {
+                    if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity candidate!");
+                    // It is possible for multiple tasks to have the same root affinity especially
+                    // if they are in separate stacks. We save off this candidate, but keep looking
+                    // to see if there is a better candidate.
+                    mRecord = r;
+                    mIdealMatch = false;
+                }
+            } else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: " + task);
+
+            return false;
+        }
     }
 
     RootActivityContainer(ActivityTaskManagerService service) {
@@ -652,10 +769,12 @@
             starting.frozenBeforeDestroy = true;
         }
 
-        if (displayContent != null && displayContent.mActivityDisplay != null) {
+        if (displayContent != null) {
             // Update the configuration of the activities on the display.
-            return displayContent.mActivityDisplay.updateDisplayOverrideConfigurationLocked(config,
-                    starting, deferResume, null /* result */);
+            // TODO(display-merge): Remove cast
+            return ((ActivityDisplay) displayContent)
+                .updateDisplayOverrideConfigurationLocked(config, starting, deferResume,
+                    null /* result */);
         } else {
             return true;
         }
@@ -672,8 +791,8 @@
         for (int i = mActivityDisplays.size() - 1; i >= 0; i--) {
             final ActivityDisplay display = mActivityDisplays.get(i);
             // Traverse all stacks on a display.
-            for (int j = display.getChildCount() - 1; j >= 0; --j) {
-                final ActivityStack stack = display.getChildAt(j);
+            for (int j = display.getStackCount() - 1; j >= 0; --j) {
+                final ActivityStack stack = display.getStackAt(j);
                 // Get top activity from a visible stack and add it to the list.
                 if (stack.shouldBeVisible(null /* starting */)) {
                     final ActivityRecord top = stack.getTopNonFinishingActivity();
@@ -743,8 +862,8 @@
         WindowProcessController fgApp = null;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
+            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getStackAt(stackNdx);
                 if (isTopDisplayFocusedStack(stack)) {
                     final ActivityRecord resumedActivity = stack.getResumedActivity();
                     if (resumedActivity != null) {
@@ -772,27 +891,21 @@
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ActivityDisplay display = mActivityDisplays.get(displayNdx);
             final ActivityStack stack = display.getFocusedStack();
-            if (stack != null) {
-                stack.getAllRunningVisibleActivitiesLocked(mTmpActivityList);
-                final ActivityRecord top = stack.topRunningActivityLocked();
-                final int size = mTmpActivityList.size();
-                for (int i = 0; i < size; i++) {
-                    final ActivityRecord activity = mTmpActivityList.get(i);
-                    if (activity.app == null && app.mUid == activity.info.applicationInfo.uid
-                            && processName.equals(activity.processName)) {
-                        try {
-                            if (mStackSupervisor.realStartActivityLocked(activity, app,
-                                    top == activity /* andResume */, true /* checkConfig */)) {
-                                didSomething = true;
-                            }
-                        } catch (RemoteException e) {
-                            Slog.w(TAG, "Exception in new application when starting activity "
-                                    + top.intent.getComponent().flattenToShortString(), e);
-                            throw e;
-                        }
-                    }
-                }
+            if (stack == null) {
+                continue;
             }
+
+            mTmpRemoteException = null;
+            mTmpBoolean = false; // Set to true if an activity was started.
+            final PooledFunction c = PooledLambda.obtainFunction(
+                    RootActivityContainer::startActivityForAttachedApplicationIfNeeded, this,
+                    PooledLambda.__(ActivityRecord.class), app, stack.topRunningActivityLocked());
+            stack.forAllActivities(c);
+            c.recycle();
+            if (mTmpRemoteException != null) {
+                throw mTmpRemoteException;
+            }
+            didSomething |= mTmpBoolean;
         }
         if (!didSomething) {
             ensureActivitiesVisible(null, 0, false /* preserve_windows */);
@@ -800,6 +913,27 @@
         return didSomething;
     }
 
+    private boolean startActivityForAttachedApplicationIfNeeded(ActivityRecord r,
+            WindowProcessController app, ActivityRecord top) {
+        if (r.finishing || !r.okToShowLocked() || !r.visibleIgnoringKeyguard || r.app != null
+                || app.mUid != r.info.applicationInfo.uid || !app.mName.equals(r.processName)) {
+            return false;
+        }
+
+        try {
+            if (mStackSupervisor.realStartActivityLocked(r, app, top == r /*andResume*/,
+                    true /*checkConfig*/)) {
+                mTmpBoolean = true;
+            }
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Exception in new application when starting activity "
+                    + top.intent.getComponent().flattenToShortString(), e);
+            mTmpRemoteException = e;
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Make sure that all activities that need to be visible in the system actually are and update
      * their configuration.
@@ -855,8 +989,8 @@
         mStackSupervisor.mStartingUsers.add(uss);
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
+            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getStackAt(stackNdx);
                 stack.switchUser(userId);
                 Task task = stack.topTask();
                 if (task != null) {
@@ -923,7 +1057,7 @@
                     + " to its current displayId=" + displayId);
         }
 
-        if (activityDisplay.isSingleTaskInstance() && activityDisplay.getChildCount() > 0) {
+        if (activityDisplay.isSingleTaskInstance() && activityDisplay.getStackCount() > 0) {
             // We don't allow moving stacks to single instance display that already has a child.
             Slog.e(TAG, "Can not move stack=" + stack
                     + " to single task instance display=" + activityDisplay);
@@ -1096,8 +1230,8 @@
             final ActivityDisplay display = mActivityDisplays.get(displayNdx);
             // It is possible that request to finish activity might also remove its task and stack,
             // so we need to be careful with indexes in the loop and check child count every time.
-            for (int stackNdx = 0; stackNdx < display.getChildCount(); ++stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
+            for (int stackNdx = 0; stackNdx < display.getStackCount(); ++stackNdx) {
+                final ActivityStack stack = display.getStackAt(stackNdx);
                 final Task t = stack.finishTopCrashedActivityLocked(app, reason);
                 if (stack == focusedStack || finishedTask == null) {
                     finishedTask = t;
@@ -1127,8 +1261,8 @@
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             boolean resumedOnDisplay = false;
             final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
+            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getStackAt(stackNdx);
                 final ActivityRecord topRunningActivity = stack.topRunningActivityLocked();
                 if (!stack.isFocusableAndVisible() || topRunningActivity == null) {
                     continue;
@@ -1181,8 +1315,8 @@
             }
 
             // Set the sleeping state of the stacks on the display.
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
+            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getStackAt(stackNdx);
                 if (displayShouldSleep) {
                     stack.goToSleepIfPossible(false /* shuttingDown */);
                 } else {
@@ -1222,9 +1356,9 @@
         }
     }
 
-    protected <T extends ActivityStack> T getStack(int stackId) {
+    protected ActivityStack getStack(int stackId) {
         for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
-            final T stack = mActivityDisplays.get(i).getStack(stackId);
+            final ActivityStack stack = mActivityDisplays.get(i).getStack(stackId);
             if (stack != null) {
                 return stack;
             }
@@ -1233,9 +1367,10 @@
     }
 
     /** @see ActivityDisplay#getStack(int, int) */
-    private <T extends ActivityStack> T getStack(int windowingMode, int activityType) {
+    ActivityStack getStack(int windowingMode, int activityType) {
         for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
-            final T stack = mActivityDisplays.get(i).getStack(windowingMode, activityType);
+            final ActivityStack stack =
+                    mActivityDisplays.get(i).getStack(windowingMode, activityType);
             if (stack != null) {
                 return stack;
             }
@@ -1243,7 +1378,7 @@
         return null;
     }
 
-    private <T extends ActivityStack> T getStack(int windowingMode, int activityType,
+    private ActivityStack getStack(int windowingMode, int activityType,
             int displayId) {
         ActivityDisplay display = getActivityDisplay(displayId);
         if (display == null) {
@@ -1316,8 +1451,8 @@
         if (displayId == INVALID_DISPLAY) {
             for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) {
                 final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-                for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                    final ActivityStack stack = display.getChildAt(stackNdx);
+                for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+                    final ActivityStack stack = display.getStackAt(stackNdx);
                     list.add(getStackInfo(stack));
                 }
             }
@@ -1327,8 +1462,8 @@
         if (display == null) {
             return list;
         }
-        for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = display.getChildAt(stackNdx);
+        for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = display.getStackAt(stackNdx);
             list.add(getStackInfo(stack));
         }
         return list;
@@ -1416,9 +1551,9 @@
     ActivityStack findStackBehind(ActivityStack stack) {
         final ActivityDisplay display = getActivityDisplay(stack.mDisplayId);
         if (display != null) {
-            for (int i = display.getChildCount() - 1; i >= 0; i--) {
-                if (display.getChildAt(i) == stack && i > 0) {
-                    return display.getChildAt(i - 1);
+            for (int i = display.getStackCount() - 1; i >= 0; i--) {
+                if (display.getStackAt(i) == stack && i > 0) {
+                    return display.getStackAt(i - 1);
                 }
             }
         }
@@ -1442,7 +1577,7 @@
     }
 
     // TODO: remove after object merge with RootWindowContainer
-    void onChildPositionChanged(ActivityDisplay display, int position) {
+    void onChildPositionChanged(DisplayContent display, int position) {
         // Assume AM lock is held from positionChildAt of controller in each hierarchy.
         if (display != null) {
             positionChildAt(display, position);
@@ -1450,18 +1585,20 @@
     }
 
     /** Change the z-order of the given display. */
-    private void positionChildAt(ActivityDisplay display, int position) {
+    private void positionChildAt(DisplayContent display, int position) {
         if (position >= mActivityDisplays.size()) {
             position = mActivityDisplays.size() - 1;
         } else if (position < 0) {
             position = 0;
         }
 
+        // TODO(display-merge): Remove cast
+        final ActivityDisplay activityDisplay = (ActivityDisplay) display;
         if (mActivityDisplays.isEmpty()) {
-            mActivityDisplays.add(display);
+            mActivityDisplays.add(activityDisplay);
         } else if (mActivityDisplays.get(position) != display) {
             mActivityDisplays.remove(display);
-            mActivityDisplays.add(position, display);
+            mActivityDisplays.add(position, activityDisplay);
         }
         mStackSupervisor.updateTopResumedActivityIfNeeded();
     }
@@ -1526,14 +1663,12 @@
         }
     }
 
-    void addStartingWindowsForVisibleActivities(boolean taskSwitch) {
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
-                stack.addStartingWindowsForVisibleActivities(taskSwitch);
+    void addStartingWindowsForVisibleActivities() {
+        mRootWindowContainer.forAllActivities((r) -> {
+            if (r.mVisibleRequested) {
+                r.showStartingWindow(null /* prev */, false /* newTask */, true /*taskSwitch*/);
             }
-        }
+        });
     }
 
     void invalidateTaskLayers() {
@@ -1541,79 +1676,65 @@
     }
 
     void rankTaskLayersIfNeeded() {
-        if (!mTaskLayersChanged) {
+        if (!mTaskLayersChanged || mRootWindowContainer == null) {
             return;
         }
         mTaskLayersChanged = false;
-        for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); displayNdx++) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-            int baseLayer = 0;
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
-                baseLayer += stack.rankTaskLayers(baseLayer);
-            }
+        mTmpTaskLayerRank = 0;
+        final PooledConsumer c = PooledLambda.obtainConsumer(
+                RootActivityContainer::rankTaskLayerForActivity, this,
+                PooledLambda.__(ActivityRecord.class));
+        mRootWindowContainer.forAllActivities(c);
+        c.recycle();
+    }
+
+    private void rankTaskLayerForActivity(ActivityRecord r) {
+        if (r.canBeTopRunning() && r.mVisibleRequested) {
+            r.getTask().mLayerRank = ++mTmpTaskLayerRank;
+        } else {
+            r.getTask().mLayerRank = -1;
         }
     }
 
     void clearOtherAppTimeTrackers(AppTimeTracker except) {
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
-                stack.clearOtherAppTimeTrackers(except);
-            }
+        final PooledConsumer c = PooledLambda.obtainConsumer(
+                RootActivityContainer::clearOtherAppTimeTrackers,
+                PooledLambda.__(ActivityRecord.class), except);
+        mRootWindowContainer.forAllActivities(c);
+        c.recycle();
+    }
+
+    private static void clearOtherAppTimeTrackers(ActivityRecord r, AppTimeTracker except) {
+        if ( r.appTimeTracker != except) {
+            r.appTimeTracker = null;
         }
     }
 
     void scheduleDestroyAllActivities(WindowProcessController app, String reason) {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
+            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getStackAt(stackNdx);
                 stack.scheduleDestroyActivities(app, reason);
             }
         }
     }
 
-    void releaseSomeActivitiesLocked(WindowProcessController app, String reason) {
-        // Tasks is non-null only if two or more tasks are found.
-        ArraySet<Task> tasks = app.getReleaseSomeActivitiesTasks();
-        if (tasks == null) {
-            if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Didn't find two or more tasks to release");
-            return;
-        }
-        // If we have activities in multiple tasks that are in a position to be destroyed,
-        // let's iterate through the tasks and release the oldest one.
-        final int numDisplays = mActivityDisplays.size();
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-            final int stackCount = display.getChildCount();
-            // Step through all stacks starting from behind, to hit the oldest things first.
-            for (int stackNdx = 0; stackNdx < stackCount; stackNdx++) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
-                // Try to release activities in this stack; if we manage to, we are done.
-                if (stack.releaseSomeActivitiesLocked(app, tasks, reason) > 0) {
-                    return;
-                }
-            }
-        }
-    }
-
     // Tries to put all activity stacks to sleep. Returns true if all stacks were
     // successfully put to sleep.
     boolean putStacksToSleep(boolean allowDelay, boolean shuttingDown) {
         boolean allSleep = true;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
                 // Stacks and activities could be removed while putting activities to sleep if
                 // the app process was gone. This prevents us getting exception by accessing an
                 // invalid stack index.
-                if (stackNdx >= display.getChildCount()) {
+                if (stackNdx >= display.getStackCount()) {
                     continue;
                 }
 
-                final ActivityStack stack = display.getChildAt(stackNdx);
+                final ActivityStack stack = display.getStackAt(stackNdx);
                 if (allowDelay) {
                     allSleep &= stack.goToSleepIfPossible(shuttingDown);
                 } else {
@@ -1625,28 +1746,52 @@
     }
 
     void handleAppCrash(WindowProcessController app) {
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
-                stack.handleAppCrash(app);
-            }
-        }
+        final PooledConsumer c = PooledLambda.obtainConsumer(
+                RootActivityContainer::handleAppCrash, PooledLambda.__(ActivityRecord.class), app);
+        mRootWindowContainer.forAllActivities(c);
+        c.recycle();
+    }
+
+    private static void handleAppCrash(ActivityRecord r, WindowProcessController app) {
+        if (r.app != app) return;
+        Slog.w(TAG, "  Force finishing activity "
+                + r.intent.getComponent().flattenToShortString());
+        // Force the destroy to skip right to removal.
+        r.app = null;
+        r.getDisplay().mDisplayContent.prepareAppTransition(
+                TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
+        r.destroyIfPossible("handleAppCrashed");
     }
 
     ActivityRecord findActivity(Intent intent, ActivityInfo info, boolean compareIntentFilters) {
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
-                final ActivityRecord ar = stack.findActivityLocked(
-                        intent, info, compareIntentFilters);
-                if (ar != null) {
-                    return ar;
-                }
+        ComponentName cls = intent.getComponent();
+        if (info.targetActivity != null) {
+            cls = new ComponentName(info.packageName, info.targetActivity);
+        }
+        final int userId = UserHandle.getUserId(info.applicationInfo.uid);
+
+        final PooledPredicate p = PooledLambda.obtainPredicate(
+                RootActivityContainer::matchesActivity, PooledLambda.__(ActivityRecord.class),
+                userId, compareIntentFilters, intent, cls);
+        final ActivityRecord r = mRootWindowContainer.getActivity(p);
+        p.recycle();
+        return r;
+    }
+
+    private static boolean matchesActivity(ActivityRecord r, int userId,
+            boolean compareIntentFilters, Intent intent, ComponentName cls) {
+        if (!r.canBeTopRunning() || r.mUserId != userId)  return false;
+
+        if (compareIntentFilters) {
+            if (r.intent.filterEquals(intent)) {
+                return true;
+            }
+        } else {
+            if (r.intent.getComponent().equals(cls)) {
+                return true;
             }
         }
-        return null;
+        return false;
     }
 
     boolean hasAwakeDisplay() {
@@ -1831,8 +1976,8 @@
                 r.getActivityType());
 
         // Return the topmost valid stack on the display.
-        for (int i = activityDisplay.getChildCount() - 1; i >= 0; --i) {
-            final ActivityStack stack = activityDisplay.getChildAt(i);
+        for (int i = activityDisplay.getStackCount() - 1; i >= 0; --i) {
+            final ActivityStack stack = activityDisplay.getStackAt(i);
             if (isValidLaunchStack(stack, r, windowingMode)) {
                 return stack;
             }
@@ -1969,8 +2114,8 @@
         boolean hasVisibleActivities = false;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
+            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getStackAt(stackNdx);
                 hasVisibleActivities |= stack.handleAppDiedLocked(app);
             }
         }
@@ -1978,48 +2123,113 @@
     }
 
     void closeSystemDialogs() {
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
-                stack.closeSystemDialogsLocked();
+        mRootWindowContainer.forAllActivities((r) -> {
+            if ((r.info.flags & ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
+                r.finishIfPossible("close-sys", true /* oomAdj */);
             }
+        });
+    }
+
+    FinishDisabledPackageActivitiesHelper mFinishDisabledPackageActivitiesHelper =
+            new FinishDisabledPackageActivitiesHelper();
+    class FinishDisabledPackageActivitiesHelper {
+        private boolean mDidSomething;
+        private String mPackageName;
+        private Set<String> mFilterByClasses;
+        private boolean mDoit;
+        private boolean mEvenPersistent;
+        private int mUserId;
+        private Task mLastTask;
+        private ComponentName mHomeActivity;
+
+        private void reset(String packageName, Set<String> filterByClasses,
+                boolean doit, boolean evenPersistent, int userId) {
+            mDidSomething = false;
+            mPackageName = packageName;
+            mFilterByClasses = filterByClasses;
+            mDoit = doit;
+            mEvenPersistent = evenPersistent;
+            mUserId = userId;
+            mLastTask = null;
+            mHomeActivity = null;
+        }
+
+        boolean process(String packageName, Set<String> filterByClasses,
+                boolean doit, boolean evenPersistent, int userId) {
+            reset(packageName, filterByClasses, doit, evenPersistent, userId);
+
+            final PooledFunction f = PooledLambda.obtainFunction(
+                    FinishDisabledPackageActivitiesHelper::processActivity, this,
+                    PooledLambda.__(ActivityRecord.class));
+            mRootWindowContainer.forAllActivities(f);
+            f.recycle();
+            return mDidSomething;
+        }
+
+        private boolean processActivity(ActivityRecord r) {
+            final boolean sameComponent =
+                    (r.packageName.equals(mPackageName) && (mFilterByClasses == null
+                            || mFilterByClasses.contains(r.mActivityComponent.getClassName())))
+                            || (mPackageName == null && r.mUserId == mUserId);
+            if ((mUserId == UserHandle.USER_ALL || r.mUserId == mUserId)
+                    && (sameComponent || r.getTask() == mLastTask)
+                    && (r.app == null || mEvenPersistent || !r.app.isPersistent())) {
+                if (!mDoit) {
+                    if (r.finishing) {
+                        // If this activity is just finishing, then it is not
+                        // interesting as far as something to stop.
+                        return false;
+                    }
+                    return true;
+                }
+                if (r.isActivityTypeHome()) {
+                    if (mHomeActivity != null && mHomeActivity.equals(r.mActivityComponent)) {
+                        Slog.i(TAG, "Skip force-stop again " + r);
+                        return false;
+                    } else {
+                        mHomeActivity = r.mActivityComponent;
+                    }
+                }
+                mDidSomething = true;
+                Slog.i(TAG, "  Force finishing activity " + r);
+                mLastTask = r.getTask();
+                r.finishIfPossible("force-stop", true);
+            }
+
+            return false;
         }
     }
 
     /** @return true if some activity was finished (or would have finished if doit were true). */
     boolean finishDisabledPackageActivities(String packageName, Set<String> filterByClasses,
             boolean doit, boolean evenPersistent, int userId) {
-        boolean didSomething = false;
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
-                if (stack.finishDisabledPackageActivitiesLocked(
-                        packageName, filterByClasses, doit, evenPersistent, userId)) {
-                    didSomething = true;
-                }
-            }
-        }
-        return didSomething;
+        return mFinishDisabledPackageActivitiesHelper.process(packageName, filterByClasses, doit,
+                evenPersistent, userId);
     }
 
     void updateActivityApplicationInfo(ApplicationInfo aInfo) {
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
-                stack.updateActivityApplicationInfoLocked(aInfo);
-            }
+        final String packageName = aInfo.packageName;
+        final int userId = UserHandle.getUserId(aInfo.uid);
+        final PooledConsumer c = PooledLambda.obtainConsumer(
+                RootActivityContainer::updateActivityApplicationInfo,
+                PooledLambda.__(ActivityRecord.class), aInfo, userId, packageName);
+        mRootWindowContainer.forAllActivities(c);
+        c.recycle();
+    }
+
+    private static void updateActivityApplicationInfo(
+            ActivityRecord r, ApplicationInfo aInfo, int userId, String packageName) {
+        if (r.mUserId == userId && packageName.equals(r.packageName)) {
+            r.updateApplicationInfo(aInfo);
         }
     }
 
     void finishVoiceTask(IVoiceInteractionSession session) {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-            final int numStacks = display.getChildCount();
+            final int numStacks = display.getStackCount();
             for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
+                final ActivityStack stack = display.getStackAt(stackNdx);
                 stack.finishVoiceTask(session);
             }
         }
@@ -2063,7 +2273,7 @@
             // If the focused stack is not null or not empty, there should have some activities
             // resuming or resumed. Make sure these activities are idle.
             final ActivityStack stack = display.getFocusedStack();
-            if (stack == null || stack.numActivities() == 0) {
+            if (stack == null || !stack.hasActivity()) {
                 continue;
             }
             final ActivityRecord resumedActivity = stack.getResumedActivity();
@@ -2084,8 +2294,8 @@
         boolean foundResumed = false;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
+            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getStackAt(stackNdx);
                 final ActivityRecord r = stack.getResumedActivity();
                 if (r != null) {
                     if (!r.nowVisible) {
@@ -2102,8 +2312,8 @@
         boolean pausing = true;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
+            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getStackAt(stackNdx);
                 final ActivityRecord r = stack.mPausingActivity;
                 if (r != null && !r.isState(PAUSED, STOPPED, STOPPING)) {
                     if (DEBUG_STATES) {
@@ -2130,8 +2340,8 @@
         try {
             for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
                 final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-                for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                    final ActivityStack stack = display.getChildAt(stackNdx);
+                for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+                    final ActivityStack stack = display.getStackAt(stackNdx);
                     final List<Task> tasks = stack.getAllTasks();
                     for (int taskNdx = tasks.size() - 1; taskNdx >= 0; taskNdx--) {
                         final Task task = tasks.get(taskNdx);
@@ -2174,8 +2384,8 @@
     void cancelInitializingActivities() {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
+            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getStackAt(stackNdx);
                 stack.cancelInitializingActivities();
             }
         }
@@ -2207,8 +2417,8 @@
         int numDisplays = mActivityDisplays.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
             final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
+            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getStackAt(stackNdx);
                 final Task task = stack.taskForIdLocked(id);
                 if (task == null) {
                     continue;
@@ -2265,8 +2475,8 @@
         int numDisplays = mActivityDisplays.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
             final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
+            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getStackAt(stackNdx);
                 final ActivityRecord r = stack.isInStackLocked(token);
                 if (r != null) {
                     return r;
@@ -2348,8 +2558,8 @@
             int numDisplays = mActivityDisplays.size();
             for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
                 final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-                for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                    final ActivityStack stack = display.getChildAt(stackNdx);
+                for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+                    final ActivityStack stack = display.getStackAt(stackNdx);
                     if (!dumpVisibleStacksOnly || stack.shouldBeVisible(null)) {
                         activities.addAll(stack.getDumpActivitiesLocked(name));
                     }
@@ -2400,8 +2610,8 @@
             pw.print("Display #"); pw.print(activityDisplay.mDisplayId);
             pw.println(" (activities from top to bottom):");
             final ActivityDisplay display = mActivityDisplays.get(displayNdx);
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
+            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getStackAt(stackNdx);
                 pw.println();
                 printed = stack.dump(fd, pw, dumpAll, dumpClient, dumpPackage, needSep);
                 needSep = printed;
@@ -2423,15 +2633,15 @@
         return printed;
     }
 
-    protected void writeToProto(ProtoOutputStream proto, long fieldId,
+    protected void dumpDebug(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
         final long token = proto.start(fieldId);
-        super.writeToProto(proto, CONFIGURATION_CONTAINER, logLevel);
+        super.dumpDebug(proto, CONFIGURATION_CONTAINER, logLevel);
         for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) {
             final ActivityDisplay activityDisplay = mActivityDisplays.get(displayNdx);
-            activityDisplay.writeToProto(proto, DISPLAYS, logLevel);
+            activityDisplay.dumpDebug(proto, DISPLAYS, logLevel);
         }
-        mStackSupervisor.getKeyguardController().writeToProto(proto, KEYGUARD_CONTROLLER);
+        mStackSupervisor.getKeyguardController().dumpDebug(proto, KEYGUARD_CONTROLLER);
         // TODO(b/111541062): Update tests to look for resumed activities on all displays
         final ActivityStack focusedStack = getTopDisplayFocusedStack();
         if (focusedStack != null) {
@@ -2445,7 +2655,7 @@
         }
         proto.write(IS_HOME_RECENTS_COMPONENT,
                 mStackSupervisor.mRecentTasks.isRecentsComponentHomeActivity(mCurrentUser));
-        mService.getActivityStartController().writeToProto(proto, PENDING_ACTIVITIES);
+        mService.getActivityStartController().dumpDebug(proto, PENDING_ACTIVITIES);
         proto.end(token);
     }
 
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 565f95e..361bbe4 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -37,7 +37,6 @@
 import static com.android.server.wm.RootWindowContainerProto.DISPLAYS;
 import static com.android.server.wm.RootWindowContainerProto.WINDOWS;
 import static com.android.server.wm.RootWindowContainerProto.WINDOW_CONTAINER;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
@@ -68,16 +67,13 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.util.ArraySet;
-import android.util.EventLog;
 import android.util.Slog;
 import android.util.SparseIntArray;
 import android.util.proto.ProtoOutputStream;
-import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 
-import com.android.server.EventLogTags;
 import com.android.server.protolog.common.ProtoLog;
 
 import java.io.PrintWriter;
@@ -206,6 +202,12 @@
     }
 
     @Override
+    boolean isOnTop() {
+        // Considered always on top
+        return true;
+    }
+
+    @Override
     void onChildPositionChanged(WindowContainer child) {
         mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
                 !mWmService.mPerDisplayFocusEnabled /* updateInputWindows */);
@@ -221,36 +223,6 @@
         return null;
     }
 
-    DisplayContent createDisplayContent(final Display display, ActivityDisplay activityDisplay) {
-        final int displayId = display.getDisplayId();
-
-        // In select scenarios, it is possible that a DisplayContent will be created on demand
-        // rather than waiting for the controller. In this case, associate the controller and return
-        // the existing display.
-        final DisplayContent existing = getDisplayContent(displayId);
-
-        if (existing != null) {
-            existing.mActivityDisplay = activityDisplay;
-            existing.initializeDisplayOverrideConfiguration();
-            return existing;
-        }
-
-        final DisplayContent dc = new DisplayContent(display, mWmService, activityDisplay);
-
-        if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Adding display=" + display);
-
-        mWmService.mDisplayWindowSettings.applySettingsToDisplayLocked(dc);
-        dc.initializeDisplayOverrideConfiguration();
-
-        if (mWmService.mDisplayManagerInternal != null) {
-            mWmService.mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(
-                    displayId, dc.getDisplayInfo());
-            dc.configureDisplayPolicy();
-        }
-
-        return dc;
-    }
-
     /**
      * Called when DisplayWindowSettings values may change.
      */
@@ -264,7 +236,6 @@
                 continue;
             }
 
-            displayContent.initializeDisplayOverrideConfiguration();
             displayContent.reconfigureDisplayLocked();
 
             // We need to update global configuration as well if config of default display has
@@ -488,10 +459,8 @@
         final WindowSurfaceController surfaceController = winAnimator.mSurfaceController;
         boolean leakedSurface = false;
         boolean killedApps = false;
-
-        EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(),
+        EventLogTags.writeWmNoSurfaceMemory(winAnimator.mWin.toString(),
                 winAnimator.mSession.mPid, operation);
-
         final long callingIdentity = Binder.clearCallingIdentity();
         try {
             // There was some problem...first, do a sanity check of the window list to make sure
@@ -1031,19 +1000,19 @@
 
     @CallSuper
     @Override
-    public void writeToProto(ProtoOutputStream proto, long fieldId,
+    public void dumpDebug(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
         if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
             return;
         }
 
         final long token = proto.start(fieldId);
-        super.writeToProto(proto, WINDOW_CONTAINER, logLevel);
+        super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
         if (mWmService.mDisplayReady) {
             final int count = mChildren.size();
             for (int i = 0; i < count; ++i) {
                 final DisplayContent displayContent = mChildren.get(i);
-                displayContent.writeToProto(proto, DISPLAYS, logLevel);
+                displayContent.dumpDebugInner(proto, DISPLAYS, logLevel);
             }
         }
         if (logLevel == WindowTraceLogLevel.ALL) {
@@ -1063,7 +1032,7 @@
     void positionChildAt(int position, DisplayContent child, boolean includingParents) {
         super.positionChildAt(position, child, includingParents);
         if (mRootActivityContainer != null) {
-            mRootActivityContainer.onChildPositionChanged(child.mActivityDisplay, position);
+            mRootActivityContainer.onChildPositionChanged(child, position);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index f2678bb..ca9d91e 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -52,8 +52,8 @@
         final int numDisplays = activityDisplays.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
             final ActivityDisplay display = activityDisplays.get(displayNdx);
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getChildAt(stackNdx);
+            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getStackAt(stackNdx);
                 mTmpStackTasks.clear();
                 stack.getRunningTasks(mTmpStackTasks, ignoreActivityType, ignoreWindowingMode,
                         callingUid, allowed, crossUser, profileIds);
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index c19c96f..1a7d214 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -244,7 +244,7 @@
         }
     }
 
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(STARTED, mStarted);
         proto.write(ANIMATION_RUNNING, mAnimRunning);
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index ba728ba..976730e 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -340,13 +340,13 @@
      * @param fieldId Field Id of the SurfaceAnimator as defined in the parent message.
      * @hide
      */
-    void writeToProto(ProtoOutputStream proto, long fieldId) {
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         if (mAnimation != null) {
-            mAnimation.writeToProto(proto, ANIMATION_ADAPTER);
+            mAnimation.dumpDebug(proto, ANIMATION_ADAPTER);
         }
         if (mLeash != null) {
-            mLeash.writeToProto(proto, LEASH);
+            mLeash.dumpDebug(proto, LEASH);
         }
         proto.write(ANIMATION_START_DELAYED, mAnimationStartDelayed);
         proto.end(token);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 28c5575..b1d0692 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -56,8 +56,6 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.SurfaceControl.METADATA_TASK_ID;
 
-import static com.android.server.EventLogTags.WM_TASK_CREATED;
-import static com.android.server.EventLogTags.WM_TASK_REMOVED;
 import static com.android.server.am.TaskRecordProto.ACTIVITIES;
 import static com.android.server.am.TaskRecordProto.ACTIVITY_TYPE;
 import static com.android.server.am.TaskRecordProto.FULLSCREEN;
@@ -69,7 +67,6 @@
 import static com.android.server.am.TaskRecordProto.RESIZE_MODE;
 import static com.android.server.am.TaskRecordProto.STACK_ID;
 import static com.android.server.am.TaskRecordProto.TASK;
-import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
 import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN;
 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
@@ -128,7 +125,6 @@
 import android.provider.Settings;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.DisplayMetrics;
-import android.util.EventLog;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
@@ -141,6 +137,10 @@
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.util.ToBooleanFunction;
 import com.android.internal.util.XmlUtils;
+import com.android.internal.util.function.pooled.PooledConsumer;
+import com.android.internal.util.function.pooled.PooledFunction;
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.util.function.pooled.PooledPredicate;
 import com.android.server.protolog.common.ProtoLog;
 import com.android.server.wm.ActivityStack.ActivityState;
 
@@ -155,8 +155,9 @@
 import java.util.ArrayList;
 import java.util.Objects;
 import java.util.function.Consumer;
+import java.util.function.Predicate;
 
-class Task extends WindowContainer<ActivityRecord> implements ConfigurationContainerListener {
+class Task extends WindowContainer<WindowContainer> {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_ATM;
     private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
     private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
@@ -385,6 +386,44 @@
     /** @see #setCanAffectSystemUiFlags */
     private boolean mCanAffectSystemUiFlags = true;
 
+    private static Exception sTmpException;
+
+    private final FindRootHelper mFindRootHelper = new FindRootHelper();
+    private class FindRootHelper {
+        private ActivityRecord mRoot;
+
+        private void clear() {
+            mRoot = null;
+        }
+
+        ActivityRecord findRoot(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone) {
+            final PooledFunction f = PooledLambda.obtainFunction(FindRootHelper::processActivity,
+                    this, PooledLambda.__(ActivityRecord.class), ignoreRelinquishIdentity,
+                    setToBottomIfNone);
+            clear();
+            forAllActivities(f, false /*traverseTopToBottom*/);
+            f.recycle();
+            return mRoot;
+        }
+
+        private boolean processActivity(ActivityRecord r,
+                boolean ignoreRelinquishIdentity, boolean setToBottomIfNone) {
+            if (mRoot == null && setToBottomIfNone) {
+                // This is the first activity we are process. Set it as the candidate root in case
+                // we don't find a better one.
+                mRoot = r;
+            }
+
+            if (r.finishing) return false;
+
+            // Set this as the candidate root since it isn't finishing.
+            mRoot = r;
+
+            // Only end search if we are ignore relinquishing identity or we are not relinquishing.
+            return ignoreRelinquishIdentity || (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
+        }
+    }
+
     /**
      * Don't use constructor directly. Use {@link #create(ActivityTaskManagerService, int,
      * ActivityInfo, Intent, TaskDescription)} instead.
@@ -421,8 +460,7 @@
             ActivityStack stack) {
         super(atmService.mWindowManager);
 
-        EventLog.writeEvent(WM_TASK_CREATED, _taskId,
-                stack != null ? stack.mStackId : INVALID_STACK_ID);
+        EventLogTags.writeWmTaskCreated(_taskId, stack != null ? stack.mStackId : INVALID_STACK_ID);
         mAtmService = atmService;
         mTaskId = _taskId;
         mUserId = _userId;
@@ -468,7 +506,7 @@
         mAtmService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity);
     }
 
-    void cleanUpResourcesForDestroy() {
+    private void cleanUpResourcesForDestroy() {
         if (hasChild()) {
             return;
         }
@@ -930,15 +968,21 @@
         final ActivityStack oldStack = ((ActivityStack) oldParent);
         final ActivityStack newStack = ((ActivityStack) newParent);
 
+        // Task is going to be removed, clean it up before detaching from hierarchy.
+        if (oldParent != null && newParent == null) {
+            cleanUpResourcesForDestroy();
+        }
+
         mStack = newStack;
 
         super.onParentChanged(newParent, oldParent);
 
         if (oldStack != null) {
-            for (int i = getChildCount() - 1; i >= 0; --i) {
-                final ActivityRecord activity = getChildAt(i);
-                oldStack.onActivityRemovedFromStack(activity);
-            }
+            final PooledConsumer c = PooledLambda.obtainConsumer(
+                    ActivityStack::onActivityRemovedFromStack, oldStack,
+                    PooledLambda.__(ActivityRecord.class));
+            forAllActivities(c);
+            c.recycle();
 
             if (oldStack.inPinnedWindowingMode()
                     && (newStack == null || !newStack.inPinnedWindowingMode())) {
@@ -949,10 +993,11 @@
         }
 
         if (newStack != null) {
-            for (int i = getChildCount() - 1; i >= 0; --i) {
-                final ActivityRecord activity = getChildAt(i);
-                newStack.onActivityAddedToStack(activity);
-            }
+            final PooledConsumer c = PooledLambda.obtainConsumer(
+                    ActivityStack::onActivityAddedToStack, newStack,
+                    PooledLambda.__(ActivityRecord.class));
+            forAllActivities(c);
+            c.recycle();
 
             // TODO: Ensure that this is actually necessary here
             // Notify the voice session if required
@@ -972,12 +1017,6 @@
             updateOverrideConfigurationFromLaunchBounds();
         }
 
-        // Task is being removed.
-        if (oldParent != null && newParent == null) {
-            cleanUpResourcesForDestroy();
-        }
-
-
         // Update task bounds if needed.
         adjustBoundsForDisplayChangeIfNeeded(getDisplayContent());
 
@@ -1072,25 +1111,11 @@
     }
 
     ActivityRecord getRootActivity(boolean setToBottomIfNone) {
-        return getRootActivity(false /*ignoreRelinquishIdentity*/, false /*setToBottomIfNone*/);
+        return getRootActivity(false /*ignoreRelinquishIdentity*/, setToBottomIfNone);
     }
 
     ActivityRecord getRootActivity(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone) {
-        ActivityRecord root;
-        if (ignoreRelinquishIdentity) {
-            root = getActivity((r) -> !r.finishing, false /*traverseTopToBottom*/);
-        } else {
-            root = getActivity((r) ->
-                            !r.finishing && (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0,
-                    false /*traverseTopToBottom*/);
-        }
-
-        if (root == null && setToBottomIfNone) {
-            // All activities in the task are either finishing or relinquish task identity.
-            // But we still want to update the intent, so let's use the bottom activity.
-            root = getActivity((r) -> true, false /*traverseTopToBottom*/);
-        }
-        return root;
+        return mFindRootHelper.findRoot(ignoreRelinquishIdentity, setToBottomIfNone);
     }
 
     ActivityRecord getTopNonFinishingActivity() {
@@ -1098,101 +1123,42 @@
     }
 
     ActivityRecord getTopNonFinishingActivity(boolean includeOverlays) {
-        for (int i = getChildCount() - 1; i >= 0; --i) {
-            final ActivityRecord r = getChildAt(i);
-            if (r.finishing || (!includeOverlays && r.mTaskOverlay)) {
-                continue;
-            }
-            return r;
-        }
-        return null;
+        return getTopActivity(false /*includeFinishing*/, includeOverlays);
     }
 
     ActivityRecord topRunningActivityLocked() {
-        if (mStack != null) {
-            for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                ActivityRecord r = getChildAt(activityNdx);
-                if (!r.finishing && r.okToShowLocked()) {
-                    return r;
-                }
-            }
+        if (getParent() == null) {
+            return null;
         }
-        return null;
+        return getActivity(ActivityRecord::canBeTopRunning);
     }
 
     /**
      * Return true if any activities in this task belongs to input uid.
      */
-    boolean containsAppUid(int uid) {
-        for (int i = getChildCount() - 1; i >= 0; --i) {
-            final ActivityRecord r = getChildAt(i);
-            if (r.getUid() == uid) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    void getAllRunningVisibleActivitiesLocked(ArrayList<ActivityRecord> outActivities) {
-        if (mStack != null) {
-            for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                ActivityRecord r = getChildAt(activityNdx);
-                if (!r.finishing && r.okToShowLocked() && r.visibleIgnoringKeyguard) {
-                    outActivities.add(r);
-                }
-            }
-        }
+    boolean isUidPresent(int uid) {
+        final PooledPredicate p = PooledLambda.obtainPredicate(
+                ActivityRecord::isUid, PooledLambda.__(ActivityRecord.class), uid);
+        final boolean isUidPresent = getActivity(p) != null;
+        p.recycle();
+        return isUidPresent;
     }
 
     ActivityRecord topRunningActivityWithStartingWindowLocked() {
-        if (mStack != null) {
-            for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                ActivityRecord r = getChildAt(activityNdx);
-                if (r.mStartingWindowState != STARTING_WINDOW_SHOWN
-                        || r.finishing || !r.okToShowLocked()) {
-                    continue;
-                }
-                return r;
-            }
+        if (getParent() == null) {
+            return null;
         }
-        return null;
+        return getActivity((r) -> r.mStartingWindowState == STARTING_WINDOW_SHOWN
+                && r.canBeTopRunning());
     }
 
     /**
      * Return the number of running activities, and the number of non-finishing/initializing
      * activities in the provided {@param reportOut} respectively.
      */
-    void getNumRunningActivities(TaskActivitiesReport reportOut) {
+    private void getNumRunningActivities(TaskActivitiesReport reportOut) {
         reportOut.reset();
-        for (int i = getChildCount() - 1; i >= 0; --i) {
-            final ActivityRecord r = getChildAt(i);
-            if (r.finishing) {
-                continue;
-            }
-
-            reportOut.base = r;
-
-            // Increment the total number of non-finishing activities
-            reportOut.numActivities++;
-
-            if (reportOut.top == null || (reportOut.top.isState(ActivityState.INITIALIZING))) {
-                reportOut.top = r;
-                // Reset the number of running activities until we hit the first non-initializing
-                // activity
-                reportOut.numRunning = 0;
-            }
-            if (r.attachedToProcess()) {
-                // Increment the number of actually running activities
-                reportOut.numRunning++;
-            }
-        }
-    }
-
-    boolean okToShowLocked() {
-        // NOTE: If {@link Task#topRunningActivity} return is not null then it is
-        // okay to show the activity when locked.
-        return mAtmService.mStackSupervisor.isCurrentProfileLocked(mUserId)
-                || topRunningActivityLocked() != null;
+        forAllActivities(reportOut);
     }
 
     /**
@@ -1216,10 +1182,11 @@
     }
 
     @Override
-    void addChild(ActivityRecord r, int index) {
+    void addChild(WindowContainer child, int index) {
         // If this task had any child before we added this one.
         boolean hadChild = hasChild();
 
+        final ActivityRecord r = (ActivityRecord) child;
         index = getAdjustedAddPosition(r, index);
         super.addChild(r, index);
 
@@ -1248,9 +1215,6 @@
         }
 
         updateEffectiveIntent();
-        if (r.isPersistable()) {
-            mAtmService.notifyTaskPersisterLocked(this, false);
-        }
 
         // Make sure the list of display UID whitelists is updated
         // now that this record is in a new task.
@@ -1262,16 +1226,13 @@
     }
 
     @Override
-    void removeChild(ActivityRecord r) {
+    void removeChild(WindowContainer r) {
         if (!mChildren.contains(r)) {
             Slog.e(TAG, "removeChild: r=" + r + " not found in t=" + this);
             return;
         }
 
         super.removeChild(r);
-        if (r.isPersistable()) {
-            mAtmService.notifyTaskPersisterLocked(this, false);
-        }
 
         if (inPinnedWindowingMode()) {
             // We normally notify listeners of task stack changes on pause, however pinned stack
@@ -1287,7 +1248,7 @@
             // The following block can be executed multiple times if there is more than one overlay.
             // {@link ActivityStackSupervisor#removeTaskByIdLocked} handles this by reverse lookup
             // of the task by id and exiting early if not found.
-            if (onlyHasTaskOverlayActivities(false /* excludingFinishing */)) {
+            if (onlyHasTaskOverlayActivities(true /*includeFinishing*/)) {
                 // When destroying a task, tell the supervisor to remove it so that any activity it
                 // has can be cleaned up correctly. This is currently the only place where we remove
                 // a task with the DESTROYING mode, so instead of passing the onlyHasTaskOverlays
@@ -1301,7 +1262,7 @@
         } else if (!mReuseTask) {
             // Remove entire task if it doesn't have any activity left and it isn't marked for reuse
             mStack.removeChild(this, reason);
-            EventLog.writeEvent(WM_TASK_REMOVED, mTaskId,
+            EventLogTags.writeWmTaskRemoved(mTaskId,
                     "removeChild: last r=" + r + " in t=" + this);
             removeIfPossible();
         }
@@ -1309,25 +1270,20 @@
 
     /**
      * @return whether or not there are ONLY task overlay activities in the stack.
-     *         If {@param excludeFinishing} is set, then ignore finishing activities in the check.
-     *         If there are no task overlay activities, this call returns false.
+     *         If {@param includeFinishing} is set, then don't ignore finishing activities in the
+     *         check. If there are no task overlay activities, this call returns false.
      */
-    boolean onlyHasTaskOverlayActivities(boolean excludeFinishing) {
-        int count = 0;
-        for (int i = getChildCount() - 1; i >= 0; i--) {
-            final ActivityRecord r = getChildAt(i);
-            if (excludeFinishing && r.finishing) {
-                continue;
-            }
-            if (!r.mTaskOverlay) {
-                return false;
-            }
-            count++;
+    boolean onlyHasTaskOverlayActivities(boolean includeFinishing) {
+        if (getChildCount() == 0) {
+            return false;
         }
-        return count > 0;
+        if (includeFinishing) {
+            return getActivity((r) -> r.mTaskOverlay) != null;
+        }
+        return getActivity((r) -> !r.finishing && r.mTaskOverlay) != null;
     }
 
-    boolean autoRemoveFromRecents() {
+    private boolean autoRemoveFromRecents() {
         // We will automatically remove the task either if it has explicitly asked for
         // this, or it is empty and has never contained an activity that got shown to
         // the user.
@@ -1339,24 +1295,21 @@
      * task starting at a specified index.
      */
     private void performClearTaskAtIndexLocked(String reason) {
-        int numActivities = getChildCount();
-        for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
-            final ActivityRecord r = getChildAt(activityNdx);
-            if (r.finishing) {
-                continue;
-            }
-            if (mStack == null) {
+        // Broken down into to cases to avoid object create due to capturing mStack.
+        if (mStack == null) {
+            forAllActivities((r) -> {
+                if (r.finishing) return;
                 // Task was restored from persistent storage.
                 r.takeFromHistory();
                 removeChild(r);
-                --activityNdx;
-                --numActivities;
-            } else if (r.finishIfPossible(Activity.RESULT_CANCELED, null /* resultData */, reason,
-                    false /* oomAdj */)
-                    == FINISH_RESULT_REMOVED) {
-                --activityNdx;
-                --numActivities;
-            }
+            });
+        } else {
+            forAllActivities((r) -> {
+                if (r.finishing) return;
+                // TODO: figure-out how to avoid object creation due to capture of reason variable.
+                r.finishIfPossible(Activity.RESULT_CANCELED, null /* resultData */, reason,
+                        false /* oomAdj */);
+            });
         }
     }
 
@@ -1387,50 +1340,43 @@
      * @return Returns the old activity that should be continued to be used,
      * or {@code null} if none was found.
      */
-    final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
-        int numActivities = getChildCount();
-        for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
-            ActivityRecord r = getChildAt(activityNdx);
-            if (r.finishing) {
-                continue;
-            }
-            if (r.mActivityComponent.equals(newR.mActivityComponent)) {
-                // Here it is!  Now finish everything in front...
-                final ActivityRecord ret = r;
+    private ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
+        final ActivityRecord r = findActivityInHistory(newR.mActivityComponent);
+        if (r == null) return null;
 
-                for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
-                    r = getChildAt(activityNdx);
-                    if (r.finishing) {
-                        continue;
-                    }
-                    ActivityOptions opts = r.takeOptionsLocked(false /* fromClient */);
-                    if (opts != null) {
-                        ret.updateOptionsLocked(opts);
-                    }
-                    if (r.finishIfPossible("clear-task-stack", false /* oomAdj */)
-                            == FINISH_RESULT_REMOVED) {
-                        --activityNdx;
-                        --numActivities;
-                    }
-                }
+        final PooledFunction f = PooledLambda.obtainFunction(Task::finishActivityAbove,
+                PooledLambda.__(ActivityRecord.class), r);
+        forAllActivities(f);
+        f.recycle();
 
-                // Finally, if this is a normal launch mode (that is, not
-                // expecting onNewIntent()), then we will finish the current
-                // instance of the activity so a new fresh one can be started.
-                if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
-                        && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0
-                        && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) {
-                    if (!ret.finishing) {
-                        ret.finishIfPossible("clear-task-top", false /* oomAdj */);
-                        return null;
-                    }
-                }
-
-                return ret;
+        // Finally, if this is a normal launch mode (that is, not expecting onNewIntent()), then we
+        // will finish the current instance of the activity so a new fresh one can be started.
+        if (r.launchMode == ActivityInfo.LAUNCH_MULTIPLE
+                && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0
+                && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) {
+            if (!r.finishing) {
+                r.finishIfPossible("clear-task-top", false /* oomAdj */);
+                return null;
             }
         }
 
-        return null;
+        return r;
+    }
+
+    private static boolean finishActivityAbove(ActivityRecord r, ActivityRecord boundaryActivity) {
+        // Stop operation once we reach the boundary activity.
+        if (r == boundaryActivity) return true;
+
+        if (!r.finishing) {
+            final ActivityOptions opts = r.takeOptionsLocked(false /* fromClient */);
+            if (opts != null) {
+                // TODO: Why is this updating the boundary activity vs. the current activity???
+                boundaryActivity.updateOptionsLocked(opts);
+            }
+            r.finishIfPossible("clear-task-stack", false /* oomAdj */);
+        }
+
+        return false;
     }
 
     void removeTaskActivitiesLocked(String reason) {
@@ -1541,140 +1487,83 @@
      * Find the activity in the history stack within the given task.  Returns
      * the index within the history at which it's found, or < 0 if not found.
      */
-    final ActivityRecord findActivityInHistoryLocked(ActivityRecord r) {
-        final ComponentName realActivity = r.mActivityComponent;
-        for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-            ActivityRecord candidate = getChildAt(activityNdx);
-            if (candidate.finishing) {
-                continue;
-            }
-            if (candidate.mActivityComponent.equals(realActivity)) {
-                return candidate;
-            }
-        }
-        return null;
+    ActivityRecord findActivityInHistory(ComponentName component) {
+        final PooledPredicate p = PooledLambda.obtainPredicate(Task::matchesActivityInHistory,
+                PooledLambda.__(ActivityRecord.class), component);
+        final ActivityRecord r = getActivity(p);
+        p.recycle();
+        return r;
+    }
+
+    private static boolean matchesActivityInHistory(
+            ActivityRecord r, ComponentName activityComponent) {
+        return !r.finishing && r.mActivityComponent.equals(activityComponent);
     }
 
     /** Updates the last task description values. */
     void updateTaskDescription() {
-        // TODO(AM refactor): Cleanup to use findRootIndex()
-        // Traverse upwards looking for any break between main task activities and
-        // utility activities.
-        int activityNdx;
-        final int numActivities = getChildCount();
-        final boolean relinquish = numActivities != 0
-                && (getChildAt(0).info.flags & FLAG_RELINQUISH_TASK_IDENTITY) != 0;
-        for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities; ++activityNdx) {
-            final ActivityRecord r = getChildAt(activityNdx);
-            if (relinquish && (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
-                // This will be the top activity for determining taskDescription. Pre-inc to
-                // overcome initial decrement below.
-                ++activityNdx;
-                break;
-            }
-            if (r.intent != null
-                    && (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
-                break;
-            }
+        final ActivityRecord root = getRootActivity(true);
+        if (root == null) return;
+
+        final TaskDescription taskDescription = new TaskDescription();
+        final PooledFunction f = PooledLambda.obtainFunction(
+                Task::setTaskDescriptionFromActivityAboveRoot,
+                PooledLambda.__(ActivityRecord.class), root, taskDescription);
+        forAllActivities(f);
+        f.recycle();
+        taskDescription.setResizeMode(mResizeMode);
+        taskDescription.setMinWidth(mMinWidth);
+        taskDescription.setMinHeight(mMinHeight);
+        setTaskDescription(taskDescription);
+        // Update the task affiliation color if we are the parent of the group
+        if (mTaskId == mAffiliatedTaskId) {
+            mAffiliatedTaskColor = taskDescription.getPrimaryColor();
         }
-        if (activityNdx > 0) {
-            // Traverse downwards starting below break looking for set label, icon.
-            // Note that if there are activities in the task but none of them set the
-            // recent activity values, then we do not fall back to the last set
-            // values in the Task.
-            String label = null;
-            String iconFilename = null;
-            int iconResource = -1;
-            int colorPrimary = 0;
-            int colorBackground = 0;
-            int statusBarColor = 0;
-            int navigationBarColor = 0;
-            boolean statusBarContrastWhenTransparent = false;
-            boolean navigationBarContrastWhenTransparent = false;
-            boolean topActivity = true;
-            for (--activityNdx; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = getChildAt(activityNdx);
-                if (r.mTaskOverlay) {
-                    continue;
-                }
-                if (r.taskDescription != null) {
-                    if (label == null) {
-                        label = r.taskDescription.getLabel();
-                    }
-                    if (iconResource == -1) {
-                        iconResource = r.taskDescription.getIconResource();
-                    }
-                    if (iconFilename == null) {
-                        iconFilename = r.taskDescription.getIconFilename();
-                    }
-                    if (colorPrimary == 0) {
-                        colorPrimary = r.taskDescription.getPrimaryColor();
-                    }
-                    if (topActivity) {
-                        colorBackground = r.taskDescription.getBackgroundColor();
-                        statusBarColor = r.taskDescription.getStatusBarColor();
-                        navigationBarColor = r.taskDescription.getNavigationBarColor();
-                        statusBarContrastWhenTransparent =
-                                r.taskDescription.getEnsureStatusBarContrastWhenTransparent();
-                        navigationBarContrastWhenTransparent =
-                                r.taskDescription.getEnsureNavigationBarContrastWhenTransparent();
-                    }
-                }
-                topActivity = false;
-            }
-            final TaskDescription taskDescription = new TaskDescription(label, null, iconResource,
-                    iconFilename, colorPrimary, colorBackground, statusBarColor, navigationBarColor,
-                    statusBarContrastWhenTransparent, navigationBarContrastWhenTransparent,
-                    mResizeMode, mMinWidth, mMinHeight);
-            setTaskDescription(taskDescription);
-            // Update the task affiliation color if we are the parent of the group
-            if (mTaskId == mAffiliatedTaskId) {
-                mAffiliatedTaskColor = taskDescription.getPrimaryColor();
-            }
-            mAtmService.getTaskChangeNotificationController().notifyTaskDescriptionChanged(
-                    getTaskInfo());
-        }
+        mAtmService.getTaskChangeNotificationController().notifyTaskDescriptionChanged(
+                getTaskInfo());
     }
 
-    /**
-     * Find the index of the root activity in the task. It will be the first activity from the
-     * bottom that is not finishing.
-     *
-     * @param effectiveRoot Flag indicating whether 'effective root' should be returned - an
-     *                      activity that defines the task identity (its base intent). It's the
-     *                      first one that does not have
-     *                      {@link ActivityInfo#FLAG_RELINQUISH_TASK_IDENTITY}.
-     * @return index of the 'root' or 'effective' root in the list of activities, -1 if no eligible
-     *         activity was found.
-     */
-    int findRootIndex(boolean effectiveRoot) {
-        int effectiveNdx = -1;
-        final int topActivityNdx = getChildCount() - 1;
-        for (int activityNdx = 0; activityNdx <= topActivityNdx; ++activityNdx) {
-            final ActivityRecord r = getChildAt(activityNdx);
-            if (r.finishing) {
-                continue;
+    private static boolean setTaskDescriptionFromActivityAboveRoot(
+            ActivityRecord r, ActivityRecord root, TaskDescription td) {
+        if (!r.mTaskOverlay && r.taskDescription != null) {
+            final TaskDescription atd = r.taskDescription;
+            if (td.getLabel() == null) {
+                td.setLabel(atd.getLabel());
             }
-            effectiveNdx = activityNdx;
-            if (!effectiveRoot || (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
-                break;
+            if (td.getIconResource() == 0) {
+                td.setIcon(atd.getIconResource());
             }
+            if (td.getIconFilename() == null) {
+                td.setIconFilename(atd.getIconFilename());
+            }
+            if (td.getPrimaryColor() == 0) {
+                td.setPrimaryColor(atd.getPrimaryColor());
+            }
+            if (td.getBackgroundColor() == 0) {
+                td.setBackgroundColor(atd.getBackgroundColor());
+            }
+            if (td.getStatusBarColor() == 0) {
+                td.setStatusBarColor(atd.getStatusBarColor());
+                td.setEnsureStatusBarContrastWhenTransparent(
+                        atd.getEnsureStatusBarContrastWhenTransparent());
+            }
+            if (td.getNavigationBarColor() == 0) {
+                td.setNavigationBarColor(atd.getNavigationBarColor());
+                td.setEnsureNavigationBarContrastWhenTransparent(
+                        atd.getEnsureNavigationBarContrastWhenTransparent());
+            }
+
         }
-        return effectiveNdx;
+
+        // End search once we get to root.
+        return r == root;
     }
 
     // TODO (AM refactor): Invoke automatically when there is a change in children
     @VisibleForTesting
     void updateEffectiveIntent() {
-        int effectiveRootIndex = findRootIndex(true /* effectiveRoot */);
-        if (effectiveRootIndex == -1) {
-            // All activities in the task are either finishing or relinquish task identity.
-            // But we still want to update the intent, so let's use the bottom activity.
-            effectiveRootIndex = 0;
-        }
-        final ActivityRecord r = getChildAt(effectiveRootIndex);
-        setIntent(r);
-
+        final ActivityRecord root = getRootActivity(true /*setToBottomIfNone*/);
+        setIntent(root);
         // Update the task description when the activities change
         updateTaskDescription();
     }
@@ -2224,15 +2113,6 @@
         return mLastNonFullscreenBounds;
     }
 
-    void addStartingWindowsForVisibleActivities(boolean taskSwitch) {
-        for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-            final ActivityRecord r = getChildAt(activityNdx);
-            if (r.mVisibleRequested) {
-                r.showStartingWindow(null /* prev */, false /* newTask */, taskSwitch);
-            }
-        }
-    }
-
     void setRootProcess(WindowProcessController proc) {
         clearRootProcess();
         if (intent != null
@@ -2249,12 +2129,6 @@
         }
     }
 
-    void clearAllPendingOptions() {
-        for (int i = getChildCount() - 1; i >= 0; i--) {
-            getChildAt(i).clearOptionsLocked(false /* withAbort */);
-        }
-    }
-
     @Override
     DisplayContent getDisplayContent() {
         return getTaskStack() != null ? getTaskStack().getDisplayContent() : null;
@@ -2264,20 +2138,14 @@
         return (ActivityStack) getParent();
     }
 
+    // TODO(task-hierarchy): Needs to take a generic WindowManager when task contains other tasks.
     int getAdjustedAddPosition(ActivityRecord r, int suggestedPosition) {
         int maxPosition = mChildren.size();
         if (!r.mTaskOverlay) {
             // We want to place all non-overlay activities below overlays.
-            while (maxPosition > 0) {
-                final ActivityRecord current = mChildren.get(maxPosition - 1);
-                if (current.mTaskOverlay) {
-                    --maxPosition;
-                    continue;
-                }
-                break;
-            }
-            if (maxPosition < 0) {
-                maxPosition = 0;
+            final ActivityRecord bottomMostOverlay = getActivity((ar) -> ar.mTaskOverlay, false);
+            if (bottomMostOverlay != null) {
+                maxPosition = Math.max(mChildren.indexOf(bottomMostOverlay) - 1, 0);
             }
         }
 
@@ -2285,18 +2153,13 @@
     }
 
     @Override
-    void positionChildAt(int position, ActivityRecord child, boolean includingParents) {
-        position = getAdjustedAddPosition(child, position);
+    void positionChildAt(int position, WindowContainer child, boolean includingParents) {
+        position = getAdjustedAddPosition((ActivityRecord) child, position);
         super.positionChildAt(position, child, includingParents);
     }
 
     private boolean hasWindowsAlive() {
-        for (int i = mChildren.size() - 1; i >= 0; i--) {
-            if (mChildren.get(i).hasWindowsAlive()) {
-                return true;
-            }
-        }
-        return false;
+        return getActivity(ActivityRecord::hasWindowsAlive) != null;
     }
 
     @VisibleForTesting
@@ -2311,7 +2174,7 @@
     @Override
     void removeImmediately() {
         if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
-        EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeTask");
+        EventLogTags.writeWmTaskRemoved(mTaskId, "removeTask");
         super.removeImmediately();
     }
 
@@ -2319,7 +2182,7 @@
     void reparent(ActivityStack stack, int position, boolean moveParents, String reason) {
         if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
                 + " from stack=" + getTaskStack());
-        EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "reParentTask");
+        EventLogTags.writeWmTaskRemoved(mTaskId, "reParentTask");
 
         final ActivityStack prevStack = getTaskStack();
         final boolean wasTopFocusedStack =
@@ -2526,26 +2389,21 @@
      * @param out Rect containing the max visible bounds.
      * @return true if the task has some visible app windows; false otherwise.
      */
-    private boolean getMaxVisibleBounds(Rect out) {
-        boolean foundTop = false;
-        for (int i = mChildren.size() - 1; i >= 0; i--) {
-            final ActivityRecord token = mChildren.get(i);
-            // skip hidden (or about to hide) apps
-            if (token.mIsExiting || !token.isClientVisible() || !token.mVisibleRequested) {
-                continue;
-            }
-            final WindowState win = token.findMainWindow();
-            if (win == null) {
-                continue;
-            }
-            if (!foundTop) {
-                foundTop = true;
-                out.setEmpty();
-            }
-
-            win.getMaxVisibleBounds(out);
+    private static void getMaxVisibleBounds(ActivityRecord token, Rect out, boolean[] foundTop) {
+        // skip hidden (or about to hide) apps
+        if (token.mIsExiting || !token.isClientVisible() || !token.mVisibleRequested) {
+            return;
         }
-        return foundTop;
+        final WindowState win = token.findMainWindow();
+        if (win == null) {
+            return;
+        }
+        if (!foundTop[0]) {
+            foundTop[0] = true;
+            out.setEmpty();
+        }
+
+        win.getMaxVisibleBounds(out);
     }
 
     /** Bounds of the task to be used for dimming, as well as touch related tests. */
@@ -2555,8 +2413,14 @@
         // a DimLayer anyway if we weren't visible.
         final boolean dockedResizing = displayContent != null
                 && displayContent.mDividerControllerLocked.isResizing();
-        if (inFreeformWindowingMode() && getMaxVisibleBounds(out)) {
-            return;
+        if (inFreeformWindowingMode()) {
+            boolean[] foundTop = { false };
+            final PooledConsumer c = PooledLambda.obtainConsumer(Task::getMaxVisibleBounds,
+                    PooledLambda.__(ActivityRecord.class), out, foundTop);
+            c.recycle();
+            if (foundTop[0]) {
+                return;
+            }
         }
 
         if (!matchParentBounds()) {
@@ -2662,8 +2526,9 @@
     }
 
     boolean showForAllUsers() {
-        final int tokensCount = mChildren.size();
-        return (tokensCount != 0) && mChildren.get(tokensCount - 1).mShowForAllUsers;
+        if (mChildren.isEmpty()) return false;
+        final ActivityRecord r = getTopNonFinishingActivity();
+        return r != null && r.mShowForAllUsers;
     }
 
     /**
@@ -2737,24 +2602,17 @@
     }
 
     ActivityRecord getTopFullscreenActivity() {
-        for (int i = mChildren.size() - 1; i >= 0; i--) {
-            final ActivityRecord activity = mChildren.get(i);
-            final WindowState win = activity.findMainWindow();
-            if (win != null && win.mAttrs.isFullscreen()) {
-                return activity;
-            }
-        }
-        return null;
+        return getActivity((r) -> {
+            final WindowState win = r.findMainWindow();
+            return (win != null && win.mAttrs.isFullscreen());
+        });
     }
 
     ActivityRecord getTopVisibleActivity() {
-        for (int i = mChildren.size() - 1; i >= 0; i--) {
-            final ActivityRecord activity = mChildren.get(i);
-            if (!activity.mIsExiting && activity.isClientVisible() && activity.mVisibleRequested) {
-                return activity;
-            }
-        }
-        return null;
+        return getActivity((r) -> {
+            // skip hidden (or about to hide) apps
+            return !r.mIsExiting && r.isClientVisible() && r.mVisibleRequested;
+        });
     }
 
     void positionChildAtTop(ActivityRecord child) {
@@ -2810,6 +2668,13 @@
         return callback.apply(this);
     }
 
+    @Override
+    Task getTask(Predicate<Task> callback, boolean traverseTopToBottom) {
+        // I'm a task!
+        // TODO(task-hierarchy): Change to traverse children when tasks can contain other tasks.
+        return callback.test(this) ? this : null;
+    }
+
     /**
      * @param canAffectSystemUiFlags If false, all windows in this task can not affect SystemUI
      *                               flags. See {@link WindowState#canAffectSystemUiFlags()}.
@@ -2856,22 +2721,21 @@
     }
 
     // TODO(proto-merge): Remove once protos for TaskRecord and Task are merged.
-    void writeToProtoInnerTaskOnly(ProtoOutputStream proto, long fieldId,
+    void dumpDebugInnerTaskOnly(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
         if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
             return;
         }
 
         final long token = proto.start(fieldId);
-        super.writeToProto(proto, WINDOW_CONTAINER, logLevel);
+        super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
         proto.write(TaskProto.ID, mTaskId);
-        for (int i = mChildren.size() - 1; i >= 0; i--) {
-            final ActivityRecord activity = mChildren.get(i);
-            activity.writeToProto(proto, APP_WINDOW_TOKENS, logLevel);
-        }
+        forAllActivities((r) -> {
+            r.dumpDebug(proto, APP_WINDOW_TOKENS, logLevel);
+        });
         proto.write(FILLS_PARENT, matchParentBounds());
-        getBounds().writeToProto(proto, TaskProto.BOUNDS);
-        mOverrideDisplayedBounds.writeToProto(proto, DISPLAYED_BOUNDS);
+        getBounds().dumpDebug(proto, TaskProto.BOUNDS);
+        mOverrideDisplayedBounds.dumpDebug(proto, DISPLAYED_BOUNDS);
         if (mSurfaceControl != null) {
             proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth());
             proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight());
@@ -2892,11 +2756,11 @@
         final String triplePrefix = doublePrefix + "  ";
         final String quadruplePrefix = triplePrefix + "  ";
 
-        for (int i = mChildren.size() - 1; i >= 0; i--) {
-            final ActivityRecord activity = mChildren.get(i);
-            pw.println(triplePrefix + "Activity #" + i + " " + activity);
-            activity.dump(pw, quadruplePrefix, dumpAll);
-        }
+        int[] index = { 0 };
+        forAllActivities((r) -> {
+            pw.println(triplePrefix + "Activity #" + index[0]++ + " " + r);
+            r.dump(pw, quadruplePrefix, dumpAll);
+        });
     }
 
     /**
@@ -3066,22 +2930,22 @@
     }
 
     @Override
-    public void writeToProto(ProtoOutputStream proto, long fieldId,
+    public void dumpDebug(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
         if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
             return;
         }
 
         final long token = proto.start(fieldId);
-        writeToProtoInnerTaskOnly(proto, TASK, logLevel);
+        dumpDebugInnerTaskOnly(proto, TASK, logLevel);
         proto.write(com.android.server.am.TaskRecordProto.ID, mTaskId);
-        for (int i = getChildCount() - 1; i >= 0; i--) {
-            final ActivityRecord activity = getChildAt(i);
-            activity.writeToProto(proto, ACTIVITIES);
-        }
+
+        forAllActivities((r) -> {
+            r.dumpDebug(proto, ACTIVITIES);
+        });
         proto.write(STACK_ID, getStackId());
         if (mLastNonFullscreenBounds != null) {
-            mLastNonFullscreenBounds.writeToProto(proto, LAST_NON_FULLSCREEN_BOUNDS);
+            mLastNonFullscreenBounds.dumpDebug(proto, LAST_NON_FULLSCREEN_BOUNDS);
         }
         if (realActivity != null) {
             proto.write(REAL_ACTIVITY, realActivity.flattenToShortString());
@@ -3096,7 +2960,7 @@
 
         if (!matchParentBounds()) {
             final Rect bounds = getRequestedOverrideBounds();
-            bounds.writeToProto(proto, com.android.server.am.TaskRecordProto.BOUNDS);
+            bounds.dumpDebug(proto, com.android.server.am.TaskRecordProto.BOUNDS);
         }
         proto.write(MIN_WIDTH, mMinWidth);
         proto.write(MIN_HEIGHT, mMinHeight);
@@ -3104,7 +2968,7 @@
     }
 
     /** @see #getNumRunningActivities(TaskActivitiesReport) */
-    static class TaskActivitiesReport {
+    static class TaskActivitiesReport implements Consumer<ActivityRecord> {
         int numRunning;
         int numActivities;
         ActivityRecord top;
@@ -3114,12 +2978,35 @@
             numRunning = numActivities = 0;
             top = base = null;
         }
+
+        @Override
+        public void accept(ActivityRecord r) {
+            if (r.finishing) {
+                return;
+            }
+
+            base = r;
+
+            // Increment the total number of non-finishing activities
+            numActivities++;
+
+            if (top == null || (top.isState(ActivityState.INITIALIZING))) {
+                top = r;
+                // Reset the number of running activities until we hit the first non-initializing
+                // activity
+                numRunning = 0;
+            }
+            if (r.attachedToProcess()) {
+                // Increment the number of actually running activities
+                numRunning++;
+            }
+        }
     }
 
     /**
      * Saves this {@link Task} to XML using given serializer.
      */
-    void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
+    void saveToXml(XmlSerializer out) throws Exception {
         if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
 
         out.attribute(null, ATTR_TASKID, String.valueOf(mTaskId));
@@ -3185,19 +3072,33 @@
             out.endTag(null, TAG_INTENT);
         }
 
-        final int numActivities = getChildCount();
-        for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
-            final ActivityRecord r = getChildAt(activityNdx);
-            if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable()
-                    || ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT
-                            | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT)
-                    && activityNdx > 0) {
-                // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
-                break;
-            }
+        sTmpException = null;
+        final PooledFunction f = PooledLambda.obtainFunction(Task::saveActivityToXml,
+                PooledLambda.__(ActivityRecord.class), getBottomMostActivity(), out);
+        forAllActivities(f);
+        f.recycle();
+        if (sTmpException != null) {
+            throw sTmpException;
+        }
+    }
+
+    private static boolean saveActivityToXml(
+            ActivityRecord r, ActivityRecord first, XmlSerializer out) {
+        if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable()
+                || ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT
+                | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT)
+                && r != first) {
+            // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
+            return true;
+        }
+        try {
             out.startTag(null, TAG_ACTIVITY);
             r.saveToXml(out);
             out.endTag(null, TAG_ACTIVITY);
+            return false;
+        } catch (Exception e) {
+            sTmpException = e;
+            return true;
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 8ad8972..9d19cfe 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -705,8 +705,8 @@
     private void adjustBoundsToAvoidConflictInDisplay(@NonNull ActivityDisplay display,
             @NonNull Rect inOutBounds) {
         final List<Rect> taskBoundsToCheck = new ArrayList<>();
-        for (int i = 0; i < display.getChildCount(); ++i) {
-            final ActivityStack stack = display.getChildAt(i);
+        for (int i = 0; i < display.getStackCount(); ++i) {
+            final ActivityStack stack = display.getStackAt(i);
             if (!stack.inFreeformWindowingMode()) {
                 continue;
             }
diff --git a/services/core/java/com/android/server/wm/TaskPersister.java b/services/core/java/com/android/server/wm/TaskPersister.java
index 1e2f0d0..eb130a1 100644
--- a/services/core/java/com/android/server/wm/TaskPersister.java
+++ b/services/core/java/com/android/server/wm/TaskPersister.java
@@ -514,7 +514,7 @@
             mService = service;
         }
 
-        private StringWriter saveToXml(Task task) throws IOException, XmlPullParserException {
+        private StringWriter saveToXml(Task task) throws Exception {
             if (DEBUG) Slog.d(TAG, "saveToXml: task=" + task);
             final XmlSerializer xmlSerializer = new FastXmlSerializer();
             StringWriter stringWriter = new StringWriter();
@@ -550,8 +550,7 @@
                     try {
                         if (DEBUG) Slog.d(TAG, "Saving task=" + task);
                         stringWriter = saveToXml(task);
-                    } catch (IOException e) {
-                    } catch (XmlPullParserException e) {
+                    } catch (Exception e) {
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotCache.java b/services/core/java/com/android/server/wm/TaskSnapshotCache.java
index d07516a..5cbab5d 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotCache.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotCache.java
@@ -48,9 +48,9 @@
         if (entry != null) {
             mAppTaskMap.remove(entry.topApp);
         }
-        final ActivityRecord top = task.getTopChild();
+        final ActivityRecord top = task.getTopMostActivity();
         mAppTaskMap.put(top, task.mTaskId);
-        mRunningCache.put(task.mTaskId, new CacheEntry(snapshot, task.getTopChild()));
+        mRunningCache.put(task.mTaskId, new CacheEntry(snapshot, top));
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index f83ceb0..c1a36c4 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -235,23 +235,18 @@
      * children, which should be ignored.
      */
     @Nullable private ActivityRecord findAppTokenForSnapshot(Task task) {
-        for (int i = task.getChildCount() - 1; i >= 0; --i) {
-            final ActivityRecord activity = task.getChildAt(i);
-            if (activity == null || !activity.isSurfaceShowing()
-                    || activity.findMainWindow() == null) {
-                continue;
+        return task.getActivity((r) -> {
+            if (r == null || !r.isSurfaceShowing() || r.findMainWindow() == null) {
+                return false;
             }
-            final boolean hasVisibleChild = activity.forAllWindows(
+            return r.forAllWindows(
                     // Ensure at least one window for the top app is visible before attempting to
                     // take a screenshot. Visible here means that the WSA surface is shown and has
                     // an alpha greater than 0.
                     ws -> ws.mWinAnimator != null && ws.mWinAnimator.getShown()
                             && ws.mWinAnimator.mLastAlpha > 0f, true  /* traverseTopToBottom */);
-            if (hasVisibleChild) {
-                return activity;
-            }
-        }
-        return null;
+
+        });
     }
 
     @Nullable
@@ -380,7 +375,7 @@
 
     @VisibleForTesting
     int getSnapshotMode(Task task) {
-        final ActivityRecord topChild = task.getTopChild();
+        final ActivityRecord topChild = task.getTopMostActivity();
         if (!task.isActivityTypeStandardOrUndefined() && !task.isActivityTypeAssistant()) {
             return SNAPSHOT_MODE_NONE;
         } else if (topChild != null && topChild.shouldUseAppThemeSnapshot()) {
@@ -395,7 +390,7 @@
      * as possible by using the theme's window background.
      */
     private TaskSnapshot drawAppThemeSnapshot(Task task) {
-        final ActivityRecord topChild = task.getTopChild();
+        final ActivityRecord topChild = task.getTopMostActivity();
         if (topChild == null) {
             return null;
         }
diff --git a/services/core/java/com/android/server/wm/VrController.java b/services/core/java/com/android/server/wm/VrController.java
index 3e136d35..54cac38 100644
--- a/services/core/java/com/android/server/wm/VrController.java
+++ b/services/core/java/com/android/server/wm/VrController.java
@@ -441,7 +441,7 @@
       return String.format("[VrState=0x%x,VrRenderThreadTid=%d]", mVrState, mVrRenderThreadTid);
     }
 
-    void writeToProto(ProtoOutputStream proto, long fieldId) {
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         ProtoUtils.writeBitWiseFlagsToProtoEnum(proto, VrControllerProto.VR_MODE,
                 mVrState, ORIG_ENUMS, PROTO_ENUMS);
diff --git a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
index 513008d..801e521 100644
--- a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
@@ -165,10 +165,10 @@
     }
 
     @Override
-    public void writeToProto(ProtoOutputStream proto) {
+    public void dumpDebug(ProtoOutputStream proto) {
         final long token = proto.start(REMOTE);
         if (mTarget != null) {
-            mTarget.writeToProto(proto, TARGET);
+            mTarget.dumpDebug(proto, TARGET);
         }
         proto.end(token);
     }
diff --git a/services/core/java/com/android/server/wm/WindowAnimationSpec.java b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
index 7c183a8..06bffd4 100644
--- a/services/core/java/com/android/server/wm/WindowAnimationSpec.java
+++ b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
@@ -149,7 +149,7 @@
     }
 
     @Override
-    public void writeToProtoInner(ProtoOutputStream proto) {
+    public void dumpDebugInner(ProtoOutputStream proto) {
         final long token = proto.start(WINDOW);
         proto.write(ANIMATION, mAnimation.toString());
         proto.end(token);
diff --git a/services/core/java/com/android/server/wm/WindowChangeAnimationSpec.java b/services/core/java/com/android/server/wm/WindowChangeAnimationSpec.java
index d5d4e08..d3530c5 100644
--- a/services/core/java/com/android/server/wm/WindowChangeAnimationSpec.java
+++ b/services/core/java/com/android/server/wm/WindowChangeAnimationSpec.java
@@ -186,7 +186,7 @@
     }
 
     @Override
-    public void writeToProtoInner(ProtoOutputStream proto) {
+    public void dumpDebugInner(ProtoOutputStream proto) {
         final long token = proto.start(WINDOW);
         proto.write(ANIMATION, mAnimation.toString());
         proto.end(token);
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 453514b2..e80f3b8 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -288,10 +288,8 @@
         final DisplayContent dc = newParent.getDisplayContent();
 
         mReparenting = true;
-        // Oddly enough we add to the new parent before removing from the old parent to avoid
-        // issues...
-        newParent.addChild(this, position);
         oldParent.removeChild(this);
+        newParent.addChild(this, position);
         mReparenting = false;
 
         // Relayout display(s)
@@ -310,6 +308,10 @@
     final protected void setParent(WindowContainer<WindowContainer> parent) {
         final WindowContainer oldParent = mParent;
         mParent = parent;
+
+        if (mParent != null) {
+            mParent.onChildAdded(this);
+        }
         if (!mReparenting) {
             onParentChanged(mParent, oldParent);
         }
@@ -389,7 +391,6 @@
         } else {
             mChildren.add(positionToAdd, child);
         }
-        onChildAdded(child);
 
         // Set the parent after we've actually added a child in case a subclass depends on this.
         child.setParent(this);
@@ -418,7 +419,6 @@
         }
 
         mChildren.add(index, child);
-        onChildAdded(child);
 
         // Set the parent after we've actually added a child in case a subclass depends on this.
         child.setParent(this);
@@ -1096,11 +1096,22 @@
     }
 
     boolean forAllActivities(Function<ActivityRecord, Boolean> callback) {
-        for (int i = mChildren.size() - 1; i >= 0; --i) {
-            if (mChildren.get(i).forAllActivities(callback)) {
-                return true;
+        return forAllActivities(callback, true /*traverseTopToBottom*/);
+    }
+
+    boolean forAllActivities(
+            Function<ActivityRecord, Boolean> callback, boolean traverseTopToBottom) {
+        if (traverseTopToBottom) {
+            for (int i = mChildren.size() - 1; i >= 0; --i) {
+                if (mChildren.get(i).forAllActivities(callback, traverseTopToBottom)) return true;
+            }
+        } else {
+            final int count = mChildren.size();
+            for (int i = 0; i < count; i++) {
+                if (mChildren.get(i).forAllActivities(callback, traverseTopToBottom)) return true;
             }
         }
+
         return false;
     }
 
@@ -1121,6 +1132,61 @@
         }
     }
 
+    /**
+     * Process all activities in this branch of the tree.
+     *
+     * @param callback Called for each activity found.
+     * @param boundary We don't return activities via {@param callback} until we get to this node in
+     *                 the tree.
+     * @param includeBoundary If the boundary from be processed to return activities.
+     * @param traverseTopToBottom direction to traverse the tree.
+     * @return {@code true} if we ended the search before reaching the end of the tree.
+     */
+    final boolean forAllActivities(Function<ActivityRecord, Boolean> callback,
+            WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom) {
+        return forAllActivities(
+                callback, boundary, includeBoundary, traverseTopToBottom, new boolean[1]);
+    }
+
+    private boolean forAllActivities(Function<ActivityRecord, Boolean> callback,
+            WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom,
+            boolean[] boundaryFound) {
+        if (traverseTopToBottom) {
+            for (int i = mChildren.size() - 1; i >= 0; --i) {
+                if (processForAllActivitiesWithBoundary(callback, boundary, includeBoundary,
+                        traverseTopToBottom, boundaryFound, mChildren.get(i))) {
+                    return true;
+                }
+            }
+        } else {
+            final int count = mChildren.size();
+            for (int i = 0; i < count; i++) {
+                if (processForAllActivitiesWithBoundary(callback, boundary, includeBoundary,
+                        traverseTopToBottom, boundaryFound, mChildren.get(i))) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    private boolean processForAllActivitiesWithBoundary(Function<ActivityRecord, Boolean> callback,
+            WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom,
+            boolean[] boundaryFound, WindowContainer wc) {
+        if (wc == boundary) {
+            boundaryFound[0] = true;
+            if (!includeBoundary) return false;
+        }
+
+        if (boundaryFound[0]) {
+            return wc.forAllActivities(callback, traverseTopToBottom);
+        }
+
+        return wc.forAllActivities(
+                callback, boundary, includeBoundary, traverseTopToBottom, boundaryFound);
+    }
+
     /** @return {@code true} if this node or any of its children contains an activity. */
     boolean hasActivity() {
         for (int i = mChildren.size() - 1; i >= 0; --i) {
@@ -1156,6 +1222,81 @@
         return null;
     }
 
+    /**
+     * Gets an activity in a branch of the tree.
+     *
+     * @param callback called to test if this is the activity that should be returned.
+     * @param boundary We don't return activities via {@param callback} until we get to this node in
+     *                 the tree.
+     * @param includeBoundary If the boundary from be processed to return activities.
+     * @param traverseTopToBottom direction to traverse the tree.
+     * @return The activity if found or null.
+     */
+    final ActivityRecord getActivity(Predicate<ActivityRecord> callback,
+            WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom) {
+        return getActivity(
+                callback, boundary, includeBoundary, traverseTopToBottom, new boolean[1]);
+    }
+
+    private ActivityRecord getActivity(Predicate<ActivityRecord> callback,
+            WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom,
+            boolean[] boundaryFound) {
+        if (traverseTopToBottom) {
+            for (int i = mChildren.size() - 1; i >= 0; --i) {
+                final ActivityRecord r = processGetActivityWithBoundary(callback, boundary,
+                        includeBoundary, traverseTopToBottom, boundaryFound, mChildren.get(i));
+                if (r != null) {
+                    return r;
+                }
+            }
+        } else {
+            final int count = mChildren.size();
+            for (int i = 0; i < count; i++) {
+                final ActivityRecord r = processGetActivityWithBoundary(callback, boundary,
+                        includeBoundary, traverseTopToBottom, boundaryFound, mChildren.get(i));
+                if (r != null) {
+                    return r;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    private ActivityRecord processGetActivityWithBoundary(Predicate<ActivityRecord> callback,
+            WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom,
+            boolean[] boundaryFound, WindowContainer wc) {
+        if (wc == boundary || boundary == null) {
+            boundaryFound[0] = true;
+            if (!includeBoundary) return null;
+        }
+
+        if (boundaryFound[0]) {
+            return wc.getActivity(callback, traverseTopToBottom);
+        }
+
+        return wc.getActivity(
+                callback, boundary, includeBoundary, traverseTopToBottom, boundaryFound);
+    }
+
+    ActivityRecord getActivityAbove(ActivityRecord r) {
+        return getActivity((above) -> true, r,
+                false /*includeBoundary*/, false /*traverseTopToBottom*/);
+    }
+
+    ActivityRecord getActivityBelow(ActivityRecord r) {
+        return getActivity((below) -> true, r,
+                false /*includeBoundary*/, true /*traverseTopToBottom*/);
+    }
+
+    ActivityRecord getBottomMostActivity() {
+        return getActivity((r) -> true, false /*traverseTopToBottom*/);
+    }
+
+    ActivityRecord getTopMostActivity() {
+        return getActivity((r) -> true, true /*traverseTopToBottom*/);
+    }
+
     ActivityRecord getTopActivity(boolean includeFinishing, boolean includeOverlays) {
         // Break down into 4 calls to avoid object creation due to capturing input params.
         if (includeFinishing) {
@@ -1187,6 +1328,31 @@
         }
     }
 
+    Task getTask(Predicate<Task> callback) {
+        return getTask(callback, true /*traverseTopToBottom*/);
+    }
+
+    Task getTask(Predicate<Task> callback, boolean traverseTopToBottom) {
+        if (traverseTopToBottom) {
+            for (int i = mChildren.size() - 1; i >= 0; --i) {
+                final Task t = mChildren.get(i).getTask(callback, traverseTopToBottom);
+                if (t != null) {
+                    return t;
+                }
+            }
+        } else {
+            final int count = mChildren.size();
+            for (int i = 0; i < count; i++) {
+                final Task t = mChildren.get(i).getTask(callback, traverseTopToBottom);
+                if (t != null) {
+                    return t;
+                }
+            }
+        }
+
+        return null;
+    }
+
     /**
      * For all tasks at or below this container call the callback.
      *
@@ -1412,7 +1578,7 @@
      */
     @CallSuper
     @Override
-    public void writeToProto(ProtoOutputStream proto, long fieldId,
+    public void dumpDebug(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
         boolean isVisible = isVisible();
         if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible) {
@@ -1420,11 +1586,11 @@
         }
 
         final long token = proto.start(fieldId);
-        super.writeToProto(proto, CONFIGURATION_CONTAINER, logLevel);
+        super.dumpDebug(proto, CONFIGURATION_CONTAINER, logLevel);
         proto.write(ORIENTATION, mOrientation);
         proto.write(VISIBLE, isVisible);
         if (mSurfaceAnimator.isAnimating()) {
-            mSurfaceAnimator.writeToProto(proto, SURFACE_ANIMATOR);
+            mSurfaceAnimator.dumpDebug(proto, SURFACE_ANIMATOR);
         }
         proto.end(token);
     }
diff --git a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
index 604eae6..8e070f1 100644
--- a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
+++ b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
@@ -166,12 +166,12 @@
      *                message.
      * @hide
      */
-    void writeToProto(ProtoOutputStream proto, long fieldId) {
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(WIDTH, mWidth);
         proto.write(HEIGHT, mHeight);
         if (mSurfaceAnimator.isAnimating()) {
-            mSurfaceAnimator.writeToProto(proto, SURFACE_ANIMATOR);
+            mSurfaceAnimator.dumpDebug(proto, SURFACE_ANIMATOR);
         }
         proto.end(token);
     }
diff --git a/services/core/java/com/android/server/wm/WindowFrames.java b/services/core/java/com/android/server/wm/WindowFrames.java
index bafa38c..0490bac 100644
--- a/services/core/java/com/android/server/wm/WindowFrames.java
+++ b/services/core/java/com/android/server/wm/WindowFrames.java
@@ -334,19 +334,19 @@
         return mContentChanged;
     }
 
-    public void writeToProto(@NonNull ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(@NonNull ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
-        mParentFrame.writeToProto(proto, PARENT_FRAME);
-        mContentFrame.writeToProto(proto, CONTENT_FRAME);
-        mDisplayFrame.writeToProto(proto, DISPLAY_FRAME);
-        mVisibleFrame.writeToProto(proto, VISIBLE_FRAME);
-        mDecorFrame.writeToProto(proto, DECOR_FRAME);
-        mContainingFrame.writeToProto(proto, CONTAINING_FRAME);
-        mFrame.writeToProto(proto, FRAME);
-        mDisplayCutout.getDisplayCutout().writeToProto(proto, CUTOUT);
-        mContentInsets.writeToProto(proto, CONTENT_INSETS);
-        mVisibleInsets.writeToProto(proto, VISIBLE_INSETS);
-        mStableInsets.writeToProto(proto, STABLE_INSETS);
+        mParentFrame.dumpDebug(proto, PARENT_FRAME);
+        mContentFrame.dumpDebug(proto, CONTENT_FRAME);
+        mDisplayFrame.dumpDebug(proto, DISPLAY_FRAME);
+        mVisibleFrame.dumpDebug(proto, VISIBLE_FRAME);
+        mDecorFrame.dumpDebug(proto, DECOR_FRAME);
+        mContainingFrame.dumpDebug(proto, CONTAINING_FRAME);
+        mFrame.dumpDebug(proto, FRAME);
+        mDisplayCutout.getDisplayCutout().dumpDebug(proto, CUTOUT);
+        mContentInsets.dumpDebug(proto, CONTENT_INSETS);
+        mVisibleInsets.dumpDebug(proto, VISIBLE_INSETS);
+        mStableInsets.dumpDebug(proto, STABLE_INSETS);
 
         proto.end(token);
     }
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 46faf3b..ea90e49 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -550,4 +550,10 @@
      * the next time the activities are opened.
      */
     public abstract void clearSnapshotCache();
+
+    /**
+     * Assigns accessibility ID a window surface as a layer metadata.
+     */
+    public abstract void setAccessibilityIdToSurfaceMetadata(
+            IBinder windowToken, int accessibilityWindowId);
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 3b9b7c8..95eb4dd 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -193,7 +193,6 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
-import android.util.EventLog;
 import android.util.Log;
 import android.util.MergedConfiguration;
 import android.util.Slog;
@@ -265,7 +264,6 @@
 import com.android.internal.view.WindowManagerPolicyThread;
 import com.android.server.AnimationThread;
 import com.android.server.DisplayThread;
-import com.android.server.EventLogTags;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.UiThread;
@@ -1106,6 +1104,7 @@
                 com.android.internal.R.bool.config_hasPermanentDpad);
         mInTouchMode = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_defaultInTouchMode);
+        inputManager.setInTouchMode(mInTouchMode);
         mDrawLockTimeoutMillis = context.getResources().getInteger(
                 com.android.internal.R.integer.config_drawLockTimeoutMillis);
         mAllowAnimationsInLowPowerMode = context.getResources().getBoolean(
@@ -1733,20 +1732,7 @@
             }
         }
 
-        DisplayContent displayContent = mRoot.getDisplayContent(displayId);
-
-        // Create an instance if possible instead of waiting for the ActivityManagerService to drive
-        // the creation.
-        if (displayContent == null) {
-            final Display display = mDisplayManager.getDisplay(displayId);
-
-            if (display != null) {
-                displayContent = mRoot.createDisplayContent(display, null /* activityDisplay */);
-                displayContent.reconfigureDisplayLocked();
-            }
-        }
-
-        return displayContent;
+        return mAtmService.mRootActivityContainer.getActivityDisplayOrCreate(displayId);
     }
 
     private boolean doesAddToastWindowRequireToken(String packageName, int callingUid,
@@ -2352,7 +2338,7 @@
             win.setLastReportedMergedConfiguration(mergedConfiguration);
 
             // Update the last inset values here because the values are sent back to the client.
-            // The last inset values represent the last client state.
+            // The last inset values represent the last client state
             win.updateLastInsetValues();
 
             win.getCompatFrame(outFrame);
@@ -3327,7 +3313,7 @@
                 ProtoLog.e(WM_ERROR, "Boot completed: SurfaceFlinger is dead!");
             }
 
-            EventLog.writeEvent(EventLogTags.WM_BOOT_ANIMATION_DONE, SystemClock.uptimeMillis());
+            EventLogTags.writeWmBootAnimationDone(SystemClock.uptimeMillis());
             Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
             mDisplayEnabled = true;
             ProtoLog.i(WM_DEBUG_SCREEN_ON, "******************** ENABLING SCREEN!");
@@ -3404,6 +3390,7 @@
         synchronized (mGlobalLock) {
             mInTouchMode = mode;
         }
+        mInputManager.setInTouchMode(mode);
     }
 
     public void showEmulatorDisplayOverlayIfNeeded() {
@@ -3545,8 +3532,12 @@
         }
     }
 
-    void setRotateForApp(int displayId,
-            @DisplayRotation.FixedToUserRotation int fixedToUserRotation) {
+    @Override
+    public void setFixedToUserRotation(int displayId, int fixedToUserRotation) {
+        if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
+                "freezeRotation()")) {
+            throw new SecurityException("Requires SET_ORIENTATION permission");
+        }
         synchronized (mGlobalLock) {
             final DisplayContent display = mRoot.getDisplayContent(displayId);
             if (display == null) {
@@ -5775,9 +5766,9 @@
      * @param proto     Stream to write the WindowContainer object to.
      * @param logLevel  Determines the amount of data to be written to the Protobuf.
      */
-    void writeToProtoLocked(ProtoOutputStream proto, @WindowTraceLogLevel int logLevel) {
-        mPolicy.writeToProto(proto, POLICY);
-        mRoot.writeToProto(proto, ROOT_WINDOW_CONTAINER, logLevel);
+    void dumpDebugLocked(ProtoOutputStream proto, @WindowTraceLogLevel int logLevel) {
+        mPolicy.dumpDebug(proto, POLICY);
+        mRoot.dumpDebug(proto, ROOT_WINDOW_CONTAINER, logLevel);
         final DisplayContent topFocusedDisplayContent = mRoot.getTopFocusedDisplayContent();
         if (topFocusedDisplayContent.mCurrentFocus != null) {
             topFocusedDisplayContent.mCurrentFocus.writeIdentifierToProto(proto, FOCUSED_WINDOW);
@@ -6100,7 +6091,7 @@
         if (useProto) {
             final ProtoOutputStream proto = new ProtoOutputStream(fd);
             synchronized (mGlobalLock) {
-                writeToProtoLocked(proto, WindowTraceLogLevel.ALL);
+                dumpDebugLocked(proto, WindowTraceLogLevel.ALL);
             }
             proto.flush();
             return;
@@ -6791,19 +6782,23 @@
                 "setShouldShowWithInsecureKeyguard()")) {
             throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission");
         }
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final DisplayContent displayContent = getDisplayContentOrCreate(displayId, null);
+                if (displayContent == null) {
+                    ProtoLog.w(WM_ERROR, "Attempted to set flag to a display that does not exist: "
+                            + "%d", displayId);
+                    return;
+                }
 
-        synchronized (mGlobalLock) {
-            final DisplayContent displayContent = getDisplayContentOrCreate(displayId, null);
-            if (displayContent == null) {
-                ProtoLog.w(WM_ERROR, "Attempted to set flag to a display that does not exist: %d",
-                        displayId);
-                return;
+                mDisplayWindowSettings.setShouldShowWithInsecureKeyguardLocked(displayContent,
+                        shouldShow);
+
+                displayContent.reconfigureDisplayLocked();
             }
-
-            mDisplayWindowSettings.setShouldShowWithInsecureKeyguardLocked(displayContent,
-                    shouldShow);
-
-            displayContent.reconfigureDisplayLocked();
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
     }
 
@@ -6832,22 +6827,26 @@
         if (!checkCallingPermission(INTERNAL_SYSTEM_WINDOW, "setShouldShowSystemDecors()")) {
             throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission");
         }
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final DisplayContent displayContent = getDisplayContentOrCreate(displayId, null);
+                if (displayContent == null) {
+                    ProtoLog.w(WM_ERROR, "Attempted to set system decors flag to a display that "
+                            + "does not exist: %d", displayId);
+                    return;
+                }
+                if (displayContent.isUntrustedVirtualDisplay()) {
+                    throw new SecurityException("Attempted to set system decors flag to an "
+                            + "untrusted virtual display: " + displayId);
+                }
 
-        synchronized (mGlobalLock) {
-            final DisplayContent displayContent = getDisplayContentOrCreate(displayId, null);
-            if (displayContent == null) {
-                ProtoLog.w(WM_ERROR, "Attempted to set system decors flag to a display that does "
-                        + "not exist: %d", displayId);
-                return;
+                mDisplayWindowSettings.setShouldShowSystemDecorsLocked(displayContent, shouldShow);
+
+                displayContent.reconfigureDisplayLocked();
             }
-            if (displayContent.isUntrustedVirtualDisplay()) {
-                throw new SecurityException("Attempted to set system decors flag to an untrusted "
-                        + "virtual display: " + displayId);
-            }
-
-            mDisplayWindowSettings.setShouldShowSystemDecorsLocked(displayContent, shouldShow);
-
-            displayContent.reconfigureDisplayLocked();
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
     }
 
@@ -6878,23 +6877,26 @@
         if (!checkCallingPermission(INTERNAL_SYSTEM_WINDOW, "setShouldShowIme()")) {
             throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission");
         }
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final DisplayContent displayContent = getDisplayContentOrCreate(displayId, null);
+                if (displayContent == null) {
+                    ProtoLog.w(WM_ERROR, "Attempted to set IME flag to a display that does not "
+                            + "exist: %d", displayId);
+                    return;
+                }
+                if (displayContent.isUntrustedVirtualDisplay()) {
+                    throw new SecurityException("Attempted to set IME flag to an untrusted "
+                            + "virtual display: " + displayId);
+                }
 
-        synchronized (mGlobalLock) {
-            final DisplayContent displayContent = getDisplayContentOrCreate(displayId, null);
-            if (displayContent == null) {
-                ProtoLog.w(WM_ERROR,
-                        "Attempted to set IME flag to a display that does not exist: %d",
-                        displayId);
-                return;
+                mDisplayWindowSettings.setShouldShowImeLocked(displayContent, shouldShow);
+
+                displayContent.reconfigureDisplayLocked();
             }
-            if (displayContent.isUntrustedVirtualDisplay()) {
-                throw new SecurityException("Attempted to set IME flag to an untrusted "
-                        + "virtual display: " + displayId);
-            }
-
-            mDisplayWindowSettings.setShouldShowImeLocked(displayContent, shouldShow);
-
-            displayContent.reconfigureDisplayLocked();
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
     }
 
@@ -7396,6 +7398,27 @@
         public @Nullable KeyInterceptionInfo getKeyInterceptionInfoFromToken(IBinder inputToken) {
             return mKeyInterceptionInfoForToken.get(inputToken);
         }
+
+        @Override
+        public void setAccessibilityIdToSurfaceMetadata(
+                IBinder windowToken, int accessibilityWindowId) {
+            synchronized (mGlobalLock) {
+                final WindowState state = mWindowMap.get(windowToken);
+                if (state == null) {
+                    Slog.w(TAG, "Cannot find window which accessibility connection is added to");
+                    return;
+                }
+                try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) {
+                    t.setMetadata(
+                            state.mSurfaceControl,
+                            SurfaceControl.METADATA_ACCESSIBILITY_ID,
+                            accessibilityWindowId);
+                    t.apply();
+                } finally {
+                    SurfaceControl.closeTransaction();
+                }
+            }
+        }
     }
 
     void registerAppFreezeListener(AppFreezeListener listener) {
@@ -7610,12 +7633,15 @@
             // it as if the host window was tapped.
             touchedWindow = mEmbeddedWindowController.getHostWindow(touchedToken);
         }
-        if (touchedWindow == null || !touchedWindow.canReceiveKeys()) {
+
+        if (touchedWindow == null || !touchedWindow.canReceiveKeys(true /* fromUserTouch */)) {
+            // If the window that received the input event cannot receive keys, don't move the
+            // display it's on to the top since that window won't be able to get focus anyway.
             return;
         }
 
-        handleTaskFocusChange(touchedWindow.getTask());
         handleDisplayFocusChange(touchedWindow);
+        handleTaskFocusChange(touchedWindow.getTask());
     }
 
     private void handleTaskFocusChange(Task task) {
@@ -7643,12 +7669,6 @@
             return;
         }
 
-        if (!window.canReceiveKeys()) {
-            // If the window that received the input event cannot receive keys, don't move the
-            // display it's on to the top since that window won't be able to get focus anyway.
-            return;
-        }
-
         final WindowContainer parent = displayContent.getParent();
         if (parent != null && parent.getTopChild() != displayContent) {
             parent.positionChildAt(WindowContainer.POSITION_TOP, displayContent,
@@ -7660,7 +7680,8 @@
             // to do so because it seems possible to resume activities as part of a larger
             // transaction and it's too early to resume based on current order when performing
             // updateTopResumedActivityIfNeeded().
-            displayContent.mActivityDisplay.ensureActivitiesVisible(null /* starting */,
+            // TODO(display-merge): Remove cast
+            ((ActivityDisplay) displayContent).ensureActivitiesVisible(null /* starting */,
                     0 /* configChanges */, !PRESERVE_WINDOWS, true /* notifyClients */);
         }
     }
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 5da3eb6..619d87b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -321,7 +321,7 @@
         }
     }
 
-    private int runSetFixToUserRotation(PrintWriter pw) {
+    private int runSetFixToUserRotation(PrintWriter pw) throws RemoteException {
         int displayId = Display.DEFAULT_DISPLAY;
         String arg = getNextArgRequired();
         if ("-d".equals(arg)) {
@@ -329,16 +329,16 @@
             arg = getNextArgRequired();
         }
 
-        final @DisplayRotation.FixedToUserRotation  int fixedToUserRotation;
+        final int fixedToUserRotation;
         switch (arg) {
             case "enabled":
-                fixedToUserRotation = DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED;
+                fixedToUserRotation = IWindowManager.FIXED_TO_USER_ROTATION_ENABLED;
                 break;
             case "disabled":
-                fixedToUserRotation = DisplayRotation.FIXED_TO_USER_ROTATION_DISABLED;
+                fixedToUserRotation = IWindowManager.FIXED_TO_USER_ROTATION_DISABLED;
                 break;
             case "default":
-                fixedToUserRotation = DisplayRotation.FIXED_TO_USER_ROTATION_DISABLED;
+                fixedToUserRotation = IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT;
                 break;
             default:
                 getErrPrintWriter().println("Error: expecting enabled, disabled or default, but we "
@@ -346,7 +346,7 @@
                 return -1;
         }
 
-        mInternal.setRotateForApp(displayId, fixedToUserRotation);
+        mInterface.setFixedToUserRotation(displayId, fixedToUserRotation);
         return 0;
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index c1783ef..ddf8e9b 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -722,11 +722,10 @@
         return true;
     }
 
-    ArraySet<Task> getReleaseSomeActivitiesTasks() {
+    void releaseSomeActivities(String reason) {
         // Examine all activities currently running in the process.
-        Task firstTask = null;
-        // Tasks is non-null only if two or more tasks are found.
-        ArraySet<Task> tasks = null;
+        // Candidate activities that can be destroyed.
+        ArrayList<ActivityRecord> candidates = null;
         if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Trying to release some activities in " + this);
         for (int i = 0; i < mActivities.size(); i++) {
             final ActivityRecord r = mActivities.get(i);
@@ -735,33 +734,37 @@
             // down before we try to prune more activities.
             if (r.finishing || r.isState(DESTROYING, DESTROYED)) {
                 if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Abort release; already destroying: " + r);
-                return null;
+                return;
             }
             // Don't consider any activities that are currently not in a state where they
             // can be destroyed.
-            if (r.mVisibleRequested || !r.stopped || !r.hasSavedState()
+            if (r.mVisibleRequested || !r.stopped || !r.hasSavedState() || !r.isDestroyable()
                     || r.isState(STARTED, RESUMED, PAUSING, PAUSED, STOPPING)) {
                 if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Not releasing in-use activity: " + r);
                 continue;
             }
 
-            final Task task = r.getTask();
-            if (task != null) {
-                if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Collecting release task " + task
-                        + " from " + r);
-                if (firstTask == null) {
-                    firstTask = task;
-                } else if (firstTask != task) {
-                    if (tasks == null) {
-                        tasks = new ArraySet<>();
-                        tasks.add(firstTask);
-                    }
-                    tasks.add(task);
+            if (r.getParent() != null) {
+                if (candidates == null) {
+                    candidates = new ArrayList<>();
                 }
+                candidates.add(r);
             }
         }
 
-        return tasks;
+        if (candidates != null) {
+            // Sort based on z-order in hierarchy.
+            candidates.sort(WindowContainer::compareTo);
+            // Release some older activities
+            int maxRelease = Math.max(candidates.size(), 1);
+            do {
+                final ActivityRecord r = candidates.remove(0);
+                if (DEBUG_RELEASE) Slog.v(TAG_RELEASE, "Destroying " + r
+                        + " in state " + r.getState() + " for reason " + reason);
+                r.destroyImmediately(true /*removeFromApp*/, reason);
+                --maxRelease;
+            } while (maxRelease > 0);
+        }
     }
 
     public interface ComputeOomAdjCallback {
@@ -1170,9 +1173,9 @@
         pw.println(prefix + " mLastReportedConfiguration=" + mLastReportedConfiguration);
     }
 
-    void writeToProto(ProtoOutputStream proto, long fieldId) {
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
         if (mListener != null) {
-            mListener.writeToProto(proto, fieldId);
+            mListener.dumpDebug(proto, fieldId);
         }
     }
 }
diff --git a/services/core/java/com/android/server/wm/WindowProcessListener.java b/services/core/java/com/android/server/wm/WindowProcessListener.java
index 1dade15..870cbb0 100644
--- a/services/core/java/com/android/server/wm/WindowProcessListener.java
+++ b/services/core/java/com/android/server/wm/WindowProcessListener.java
@@ -60,7 +60,7 @@
 
     /** App died :(...oh well */
     void appDied();
-    void writeToProto(ProtoOutputStream proto, long fieldId);
+    void dumpDebug(ProtoOutputStream proto, long fieldId);
 
     /**
      * Sets if the process is currently running a remote animation, which is taken a signal for
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 0441669..6a1aa02 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -35,6 +35,7 @@
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
 import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
@@ -983,7 +984,7 @@
                             - mWindowFrames.mVisibleFrame.bottom;
                     if (bottomOverlap > 0) {
                         final int distanceToTop = Math.max(mWindowFrames.mContainingFrame.top
-                                - mWindowFrames.mDisplayFrame.top, 0);
+                                - mWindowFrames.mContentFrame.top, 0);
                         int offs = Math.min(bottomOverlap, distanceToTop);
                         mWindowFrames.mContainingFrame.top -= offs;
                     }
@@ -1308,8 +1309,7 @@
 
         // We update mLastFrame always rather than in the conditional with the last inset
         // variables, because mFrameSizeChanged only tracks the width and height changing.
-        mWindowFrames.mLastFrame.set(mWindowFrames.mFrame);
-        mWindowFrames.mLastRelFrame.set(mWindowFrames.mRelFrame);
+        updateLastFrames();
 
         if (didFrameInsetsChange
                 || winAnimator.mSurfaceResized
@@ -2163,12 +2163,13 @@
             return false;
         }
 
-        // Can be an IME target only if:
-        // 1. FLAG_NOT_FOCUSABLE is not set
-        // 2. FLAG_ALT_FOCUSABLE_IM is not set
-        // 3. not a starting window.
-        if (!WindowManager.LayoutParams.mayUseInputMethod(mAttrs.flags)
-                || mAttrs.type == TYPE_APPLICATION_STARTING) {
+        final int fl = mAttrs.flags & (FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM);
+        final int type = mAttrs.type;
+
+        // Can only be an IME target if both FLAG_NOT_FOCUSABLE and FLAG_ALT_FOCUSABLE_IM are set or
+        // both are cleared...and not a starting window.
+        if (fl != 0 && fl != (FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM)
+                && type != TYPE_APPLICATION_STARTING) {
             return false;
         }
 
@@ -2617,11 +2618,22 @@
 
     @Override
     public boolean canReceiveKeys() {
-        return isVisibleOrAdding()
+        return canReceiveKeys(false /* fromUserTouch */);
+    }
+
+    public boolean canReceiveKeys(boolean fromUserTouch) {
+        final boolean canReceiveKeys = isVisibleOrAdding()
                 && (mViewVisibility == View.VISIBLE) && !mRemoveOnExit
                 && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0)
                 && (mActivityRecord == null || mActivityRecord.windowsAreFocusable())
                 && !cantReceiveTouchInput();
+        if (!canReceiveKeys) {
+            return false;
+        }
+        // Do not allow untrusted virtual display to receive keys unless user intentionally
+        // touches the display.
+        return fromUserTouch || getDisplayContent().isOnTop()
+                || !getDisplayContent().isUntrustedVirtualDisplay();
     }
 
     @Override
@@ -3599,7 +3611,7 @@
 
     @CallSuper
     @Override
-    public void writeToProto(ProtoOutputStream proto, long fieldId,
+    public void dumpDebug(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
         boolean isVisible = isVisible();
         if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible) {
@@ -3607,19 +3619,19 @@
         }
 
         final long token = proto.start(fieldId);
-        super.writeToProto(proto, WINDOW_CONTAINER, logLevel);
+        super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
         writeIdentifierToProto(proto, IDENTIFIER);
         proto.write(DISPLAY_ID, getDisplayId());
         proto.write(STACK_ID, getStackId());
-        mAttrs.writeToProto(proto, ATTRIBUTES);
-        mGivenContentInsets.writeToProto(proto, GIVEN_CONTENT_INSETS);
-        mWindowFrames.writeToProto(proto, WINDOW_FRAMES);
-        mAttrs.surfaceInsets.writeToProto(proto, SURFACE_INSETS);
-        mSurfacePosition.writeToProto(proto, SURFACE_POSITION);
-        mWinAnimator.writeToProto(proto, ANIMATOR);
+        mAttrs.dumpDebug(proto, ATTRIBUTES);
+        mGivenContentInsets.dumpDebug(proto, GIVEN_CONTENT_INSETS);
+        mWindowFrames.dumpDebug(proto, WINDOW_FRAMES);
+        mAttrs.surfaceInsets.dumpDebug(proto, SURFACE_INSETS);
+        mSurfacePosition.dumpDebug(proto, SURFACE_POSITION);
+        mWinAnimator.dumpDebug(proto, ANIMATOR);
         proto.write(ANIMATING_EXIT, mAnimatingExit);
         for (int i = 0; i < mChildren.size(); i++) {
-            mChildren.get(i).writeToProto(proto, CHILD_WINDOWS, logLevel);
+            mChildren.get(i).dumpDebug(proto, CHILD_WINDOWS, logLevel);
         }
         proto.write(REQUESTED_WIDTH, mRequestedWidth);
         proto.write(REQUESTED_HEIGHT, mRequestedHeight);
@@ -4817,6 +4829,12 @@
         return mEmbeddedDisplayContents.remove(dc);
     }
 
+    /** Updates the last frames and relative frames to the current ones. */
+    void updateLastFrames() {
+        mWindowFrames.mLastFrame.set(mWindowFrames.mFrame);
+        mWindowFrames.mLastRelFrame.set(mWindowFrames.mRelFrame);
+    }
+
     /**
      * Updates the last inset values to the current ones.
      */
@@ -5385,10 +5403,10 @@
         }
 
         @Override
-        public void writeToProtoInner(ProtoOutputStream proto) {
+        public void dumpDebugInner(ProtoOutputStream proto) {
             final long token = proto.start(MOVE);
-            mFrom.writeToProto(proto, FROM);
-            mTo.writeToProto(proto, TO);
+            mFrom.dumpDebug(proto, FROM);
+            mTo.dumpDebug(proto, TO);
             proto.write(DURATION_MS, mDuration);
             proto.end(token);
         }
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 94aff7b..175fccb 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -439,10 +439,6 @@
 
         if (!mWin.mActivityRecord.isAnimating(TRANSITION)) {
             mWin.mActivityRecord.clearAllDrawn();
-        } else {
-            // Currently animating, persist current state of allDrawn until animation
-            // is complete.
-            mWin.mActivityRecord.deferClearAllDrawn = true;
         }
     }
 
@@ -1405,14 +1401,14 @@
         return mWin.isAnimating(TRANSITION | PARENTS);
     }
 
-    void writeToProto(ProtoOutputStream proto, long fieldId) {
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
-        mLastClipRect.writeToProto(proto, LAST_CLIP_RECT);
+        mLastClipRect.dumpDebug(proto, LAST_CLIP_RECT);
         if (mSurfaceController != null) {
-            mSurfaceController.writeToProto(proto, SURFACE);
+            mSurfaceController.dumpDebug(proto, SURFACE);
         }
         proto.write(DRAW_STATE, mDrawState);
-        mSystemDecorRect.writeToProto(proto, SYSTEM_DECOR_RECT);
+        mSystemDecorRect.dumpDebug(proto, SYSTEM_DECOR_RECT);
         proto.end(token);
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 0b4ea99..5b8015b 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -510,7 +510,7 @@
         return mSurfaceH;
     }
 
-    void writeToProto(ProtoOutputStream proto, long fieldId) {
+    void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(SHOWN, mSurfaceShown);
         proto.write(LAYER, mSurfaceLayer);
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 287d7cd..53edf9d 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -258,18 +258,18 @@
 
     @CallSuper
     @Override
-    public void writeToProto(ProtoOutputStream proto, long fieldId,
+    public void dumpDebug(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
         if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
             return;
         }
 
         final long token = proto.start(fieldId);
-        super.writeToProto(proto, WINDOW_CONTAINER, logLevel);
+        super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
         proto.write(HASH_CODE, System.identityHashCode(this));
         for (int i = 0; i < mChildren.size(); i++) {
             final WindowState w = mChildren.get(i);
-            w.writeToProto(proto, WINDOWS, logLevel);
+            w.dumpDebug(proto, WINDOWS, logLevel);
         }
         proto.write(WAITING_TO_SHOW, waitingToShow);
         proto.write(PAUSED, paused);
@@ -280,10 +280,11 @@
         super.dump(pw, prefix, dumpAll);
         pw.print(prefix); pw.print("windows="); pw.println(mChildren);
         pw.print(prefix); pw.print("windowType="); pw.print(windowType);
-                pw.print(" hasVisible="); pw.println(hasVisible);
+                pw.print(" hasVisible="); pw.print(hasVisible);
         if (waitingToShow) {
-            pw.print(prefix); pw.print("waitingToShow="); pw.print(waitingToShow);
+            pw.print(" waitingToShow=true");
         }
+        pw.println();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java
index bb66530..0be90fc 100644
--- a/services/core/java/com/android/server/wm/WindowTracing.java
+++ b/services/core/java/com/android/server/wm/WindowTracing.java
@@ -298,9 +298,9 @@
 
             long tokenInner = os.start(WINDOW_MANAGER_SERVICE);
             synchronized (mGlobalLock) {
-                Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeToProtoLocked");
+                Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "dumpDebugLocked");
                 try {
-                    mService.writeToProtoLocked(os, mLogLevel);
+                    mService.dumpDebugLocked(os, mLogLevel);
                 } finally {
                     Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
                 }
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index dd2b27d..fd8094c 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -53,7 +53,6 @@
         "com_android_server_am_LowMemDetector.cpp",
         "onload.cpp",
         ":lib_networkStatsFactory_native",
-        ":tethering-jni-srcs",
     ],
 
     include_dirs: [
@@ -125,6 +124,7 @@
         "android.hardware.gnss@1.0",
         "android.hardware.gnss@1.1",
         "android.hardware.gnss@2.0",
+        "android.hardware.gnss@2.1",
         "android.hardware.gnss.measurement_corrections@1.0",
         "android.hardware.gnss.visibility_control@1.0",
         "android.hardware.input.classifier@1.0",
@@ -133,7 +133,6 @@
         "android.hardware.power@1.0",
         "android.hardware.power@1.1",
         "android.hardware.power.stats@1.0",
-        "android.hardware.tetheroffload.config@1.0",
         "android.hardware.thermal@1.0",
         "android.hardware.tv.cec@1.0",
         "android.hardware.tv.input@1.0",
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index 612a1e7..dcff5a1 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -338,7 +338,7 @@
     if (auto hal = getHal<aidl::IVibrator>()) {
         int32_t lengthMs;
         sp<AidlVibratorCallback> effectCallback = new AidlVibratorCallback(env, vibration);
-        aidl::Effect effectType(static_cast<aidl::Effect>(strength));
+        aidl::Effect effectType(static_cast<aidl::Effect>(effect));
         aidl::EffectStrength effectStrength(static_cast<aidl::EffectStrength>(strength));
 
         auto status = hal->call(&aidl::IVibrator::perform, effectType, effectStrength, effectCallback, &lengthMs);
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index b546a1d..9344a9b 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -1502,6 +1502,13 @@
     im->getInputManager()->getDispatcher()->setInputFilterEnabled(enabled);
 }
 
+static void nativeSetInTouchMode(JNIEnv* /* env */, jclass /* clazz */,
+        jlong ptr, jboolean inTouchMode) {
+    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+    im->getInputManager()->getDispatcher()->setInTouchMode(inTouchMode);
+}
+
 static jint nativeInjectInputEvent(JNIEnv* env, jclass /* clazz */,
         jlong ptr, jobject inputEventObj, jint injectorPid, jint injectorUid,
         jint syncMode, jint timeoutMillis, jint policyFlags) {
@@ -1781,6 +1788,8 @@
             (void*) nativePilferPointers },
     { "nativeSetInputFilterEnabled", "(JZ)V",
             (void*) nativeSetInputFilterEnabled },
+    { "nativeSetInTouchMode", "(JZ)V",
+            (void*) nativeSetInTouchMode },
     { "nativeInjectInputEvent", "(JLandroid/view/InputEvent;IIIII)I",
             (void*) nativeInjectInputEvent },
     { "nativeToggleCapsLock", "(JI)V",
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 3bc2838..6504e31 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -21,10 +21,12 @@
 #include <android/hardware/gnss/1.0/IGnss.h>
 #include <android/hardware/gnss/1.1/IGnss.h>
 #include <android/hardware/gnss/2.0/IGnss.h>
+#include <android/hardware/gnss/2.1/IGnss.h>
 
 #include <android/hardware/gnss/1.0/IGnssMeasurement.h>
 #include <android/hardware/gnss/1.1/IGnssMeasurement.h>
 #include <android/hardware/gnss/2.0/IGnssMeasurement.h>
+#include <android/hardware/gnss/2.1/IGnssMeasurement.h>
 #include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h>
 #include <android/hardware/gnss/visibility_control/1.0/IGnssVisibilityControl.h>
 #include <nativehelper/JNIHelp.h>
@@ -140,7 +142,6 @@
 using android::hardware::gnss::V1_0::IGnssXtraCallback;
 
 using android::hardware::gnss::V2_0::ElapsedRealtimeFlags;
-using android::hardware::gnss::V2_0::IGnssCallback;
 
 using android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections;
 using android::hardware::gnss::measurement_corrections::V1_0::SingleSatCorrection;
@@ -153,7 +154,10 @@
 using IGnss_V1_0 = android::hardware::gnss::V1_0::IGnss;
 using IGnss_V1_1 = android::hardware::gnss::V1_1::IGnss;
 using IGnss_V2_0 = android::hardware::gnss::V2_0::IGnss;
+using IGnss_V2_1 = android::hardware::gnss::V2_1::IGnss;
 using IGnssCallback_V1_0 = android::hardware::gnss::V1_0::IGnssCallback;
+using IGnssCallback_V2_0 = android::hardware::gnss::V2_0::IGnssCallback;
+using IGnssCallback_V2_1 = android::hardware::gnss::V2_1::IGnssCallback;
 using IGnssConfiguration_V1_0 = android::hardware::gnss::V1_0::IGnssConfiguration;
 using IGnssConfiguration_V1_1 = android::hardware::gnss::V1_1::IGnssConfiguration;
 using IGnssConfiguration_V2_0 = android::hardware::gnss::V2_0::IGnssConfiguration;
@@ -162,9 +166,11 @@
 using IGnssMeasurement_V1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
 using IGnssMeasurement_V1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
 using IGnssMeasurement_V2_0 = android::hardware::gnss::V2_0::IGnssMeasurement;
+using IGnssMeasurement_V2_1 = android::hardware::gnss::V2_1::IGnssMeasurement;
 using IGnssMeasurementCallback_V1_0 = android::hardware::gnss::V1_0::IGnssMeasurementCallback;
 using IGnssMeasurementCallback_V1_1 = android::hardware::gnss::V1_1::IGnssMeasurementCallback;
 using IGnssMeasurementCallback_V2_0 = android::hardware::gnss::V2_0::IGnssMeasurementCallback;
+using IGnssMeasurementCallback_V2_1 = android::hardware::gnss::V2_1::IGnssMeasurementCallback;
 using IAGnssRil_V1_0 = android::hardware::gnss::V1_0::IAGnssRil;
 using IAGnssRil_V2_0 = android::hardware::gnss::V2_0::IAGnssRil;
 using IAGnss_V1_0 = android::hardware::gnss::V1_0::IAGnss;
@@ -201,6 +207,7 @@
 sp<IGnss_V1_0> gnssHal = nullptr;
 sp<IGnss_V1_1> gnssHal_V1_1 = nullptr;
 sp<IGnss_V2_0> gnssHal_V2_0 = nullptr;
+sp<IGnss_V2_1> gnssHal_V2_1 = nullptr;
 sp<IGnssXtra> gnssXtraIface = nullptr;
 sp<IAGnssRil_V1_0> agnssRilIface = nullptr;
 sp<IAGnssRil_V2_0> agnssRilIface_V2_0 = nullptr;
@@ -218,6 +225,7 @@
 sp<IGnssMeasurement_V1_0> gnssMeasurementIface = nullptr;
 sp<IGnssMeasurement_V1_1> gnssMeasurementIface_V1_1 = nullptr;
 sp<IGnssMeasurement_V2_0> gnssMeasurementIface_V2_0 = nullptr;
+sp<IGnssMeasurement_V2_1> gnssMeasurementIface_V2_1 = nullptr;
 sp<IGnssNavigationMessage> gnssNavigationMessageIface = nullptr;
 sp<IMeasurementCorrections> gnssCorrectionsIface = nullptr;
 sp<IGnssVisibilityControl> gnssVisibilityControlIface = nullptr;
@@ -582,9 +590,9 @@
 /*
  * GnssCallback class implements the callback methods for IGnss interface.
  */
-struct GnssCallback : public IGnssCallback {
+struct GnssCallback : public IGnssCallback_V2_1 {
     Return<void> gnssLocationCb(const GnssLocation_V1_0& location) override;
-    Return<void> gnssStatusCb(const IGnssCallback::GnssStatusValue status) override;
+    Return<void> gnssStatusCb(const IGnssCallback_V1_0::GnssStatusValue status) override;
     Return<void> gnssSvStatusCb(const IGnssCallback_V1_0::GnssSvStatus& svStatus) override {
         return gnssSvStatusCbImpl(svStatus);
     }
@@ -595,7 +603,7 @@
     Return<void> gnssRequestTimeCb() override;
     Return<void> gnssRequestLocationCb(const bool independentFromGnss) override;
 
-    Return<void> gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) override;
+    Return<void> gnssSetSystemInfoCb(const IGnssCallback_V1_0::GnssSystemInfo& info) override;
 
     // New in 1.1
     Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
@@ -605,10 +613,12 @@
             override;
     Return<void> gnssSetCapabilitiesCb_2_0(uint32_t capabilities) override;
     Return<void> gnssLocationCb_2_0(const GnssLocation_V2_0& location) override;
-    Return<void> gnssSvStatusCb_2_0(const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList) override {
+    Return<void> gnssSvStatusCb_2_0(const hidl_vec<IGnssCallback_V2_0::GnssSvInfo>& svInfoList) override {
         return gnssSvStatusCbImpl(svInfoList);
     }
-
+    Return<void> gnssSvStatusCb_2_1(const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList) override {
+        return gnssSvStatusCbImpl(svInfoList);
+    }
     Return<void> gnssSetCapabilitesCbImpl(uint32_t capabilities, bool hasSubHalCapabilityFlags);
 
     // TODO: Reconsider allocation cost vs threadsafety on these statics
@@ -625,7 +635,11 @@
         return svStatus.numSvs;
     }
 
-    uint32_t getGnssSvInfoListSize(const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList) {
+    uint32_t getGnssSvInfoListSize(const hidl_vec<IGnssCallback_V2_0::GnssSvInfo>& svInfoList) {
+        return svInfoList.size();
+    }
+
+    uint32_t getGnssSvInfoListSize(const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList) {
         return svInfoList.size();
     }
 
@@ -635,17 +649,28 @@
     }
 
     const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
-            const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList, size_t i) {
+            const hidl_vec<IGnssCallback_V2_0::GnssSvInfo>& svInfoList, size_t i) {
         return svInfoList[i].v1_0;
     }
 
+    const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
+            const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList, size_t i) {
+        // TODO(b/144850155): fill baseband CN0 after it's available in Java object.
+        ALOGD("getGnssSvInfoOfIndex %d: baseband C/N0: %f", (int) i, svInfoList[i].basebandCN0DbHz);
+        return svInfoList[i].v2_0.v1_0;
+    }
+
     uint32_t getConstellationType(const IGnssCallback_V1_0::GnssSvStatus& svStatus, size_t i) {
         return static_cast<uint32_t>(svStatus.gnssSvList.data()[i].constellation);
     }
 
-    uint32_t getConstellationType(const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList, size_t i) {
+    uint32_t getConstellationType(const hidl_vec<IGnssCallback_V2_0::GnssSvInfo>& svInfoList, size_t i) {
         return static_cast<uint32_t>(svInfoList[i].constellation);
     }
+
+    uint32_t getConstellationType(const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList, size_t i) {
+        return static_cast<uint32_t>(svInfoList[i].v2_0.constellation);
+    }
 };
 
 Return<void> GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) {
@@ -686,7 +711,7 @@
     return gnssLocationCbImpl<GnssLocation_V2_0>(location);
 }
 
-Return<void> GnssCallback::gnssStatusCb(const IGnssCallback::GnssStatusValue status) {
+Return<void> GnssCallback::gnssStatusCb(const IGnssCallback_V2_0::GnssStatusValue status) {
     JNIEnv* env = getJniEnv();
     env->CallVoidMethod(mCallbacksObj, method_reportStatus, status);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
@@ -704,20 +729,22 @@
     jfloatArray elevArray = env->NewFloatArray(listSize);
     jfloatArray azimArray = env->NewFloatArray(listSize);
     jfloatArray carrierFreqArray = env->NewFloatArray(listSize);
+    jfloatArray basebandCn0Array = env->NewFloatArray(listSize);
 
     jint* svidWithFlags = env->GetIntArrayElements(svidWithFlagArray, 0);
     jfloat* cn0s = env->GetFloatArrayElements(cn0Array, 0);
     jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
     jfloat* azim = env->GetFloatArrayElements(azimArray, 0);
     jfloat* carrierFreq = env->GetFloatArrayElements(carrierFreqArray, 0);
+    jfloat* basebandCn0s = env->GetFloatArrayElements(basebandCn0Array, 0);
 
     /*
      * Read GNSS SV info.
      */
     for (size_t i = 0; i < listSize; ++i) {
         enum ShiftWidth: uint8_t {
-            SVID_SHIFT_WIDTH = 8,
-            CONSTELLATION_TYPE_SHIFT_WIDTH = 4
+            SVID_SHIFT_WIDTH = 12,
+            CONSTELLATION_TYPE_SHIFT_WIDTH = 8
         };
 
         const IGnssCallback_V1_0::GnssSvInfo& info = getGnssSvInfoOfIndex(svStatus, i);
@@ -728,6 +755,8 @@
         elev[i] = info.elevationDegrees;
         azim[i] = info.azimuthDegrees;
         carrierFreq[i] = info.carrierFrequencyHz;
+        // TODO(b/144850155): fill svidWithFlags with hasBasebandCn0DbHz based on HAL versions
+        basebandCn0s[i] = 0.0;
     }
 
     env->ReleaseIntArrayElements(svidWithFlagArray, svidWithFlags, 0);
@@ -735,10 +764,11 @@
     env->ReleaseFloatArrayElements(elevArray, elev, 0);
     env->ReleaseFloatArrayElements(azimArray, azim, 0);
     env->ReleaseFloatArrayElements(carrierFreqArray, carrierFreq, 0);
+    env->ReleaseFloatArrayElements(basebandCn0Array, basebandCn0s, 0);
 
     env->CallVoidMethod(mCallbacksObj, method_reportSvStatus,
             static_cast<jint>(listSize), svidWithFlagArray, cn0Array, elevArray, azimArray,
-            carrierFreqArray);
+            carrierFreqArray, basebandCn0Array);
 
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
     return Void();
@@ -803,7 +833,7 @@
     return Void();
 }
 
-Return<void> GnssCallback::gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) {
+Return<void> GnssCallback::gnssSetSystemInfoCb(const IGnssCallback_V2_0::GnssSystemInfo& info) {
     ALOGD("%s: yearOfHw=%d\n", __func__, info.yearOfHw);
 
     JNIEnv* env = getJniEnv();
@@ -992,7 +1022,9 @@
  * GnssMeasurementCallback implements the callback methods required for the
  * GnssMeasurement interface.
  */
-struct GnssMeasurementCallback : public IGnssMeasurementCallback_V2_0 {
+struct GnssMeasurementCallback : public IGnssMeasurementCallback_V2_1 {
+    Return<void> gnssMeasurementCb_2_1(const IGnssMeasurementCallback_V2_1::GnssData& data)
+            override;
     Return<void> gnssMeasurementCb_2_0(const IGnssMeasurementCallback_V2_0::GnssData& data)
             override;
     Return<void> gnssMeasurementCb(const IGnssMeasurementCallback_V1_1::GnssData& data) override;
@@ -1016,6 +1048,12 @@
     void setMeasurementData(JNIEnv* env, jobject clock, jobjectArray measurementArray);
 };
 
+Return<void> GnssMeasurementCallback::gnssMeasurementCb_2_1(
+        const IGnssMeasurementCallback_V2_1::GnssData& data) {
+    translateAndSetGnssData(data);
+    return Void();
+}
+
 Return<void> GnssMeasurementCallback::gnssMeasurementCb_2_0(
         const IGnssMeasurementCallback_V2_0::GnssData& data) {
     translateAndSetGnssData(data);
@@ -1137,6 +1175,17 @@
     SET(ConstellationType, static_cast<int32_t>(measurement_V2_0->constellation));
 }
 
+// Preallocate object as: JavaObject object(env, "android/location/GnssMeasurement");
+template<>
+void GnssMeasurementCallback::translateSingleGnssMeasurement
+        <IGnssMeasurementCallback_V2_1::GnssMeasurement>(
+        const IGnssMeasurementCallback_V2_1::GnssMeasurement* measurement_V2_1,
+        JavaObject& object) {
+    translateSingleGnssMeasurement(&(measurement_V2_1->v2_0), object);
+    // TODO(b/144850155): fill baseband CN0 after it's available in Java object
+    ALOGD("baseband CN0DbHz = %f\n", measurement_V2_1->basebandCN0DbHz);
+}
+
 template<class T>
 void GnssMeasurementCallback::translateGnssClock(JavaObject& object, const T& data) {
     translateGnssClock(object, data.clock);
@@ -1518,6 +1567,17 @@
 
 /* Initializes the GNSS service handle. */
 static void android_location_GnssLocationProvider_set_gps_service_handle() {
+    ALOGD("Trying IGnss_V2_1::getService()");
+    gnssHal_V2_1 = IGnss_V2_1::getService();
+    if (gnssHal_V2_1 != nullptr) {
+        gnssHal = gnssHal_V2_1;
+        gnssHal_V2_0 = gnssHal_V2_1;
+        gnssHal_V1_1 = gnssHal_V2_1;
+        gnssHal = gnssHal_V2_1;
+        return;
+    }
+
+    ALOGD("gnssHal 2.1 was null, trying 2.0");
     gnssHal_V2_0 = IGnss_V2_0::getService();
     if (gnssHal_V2_0 != nullptr) {
         gnssHal = gnssHal_V2_0;
@@ -1545,7 +1605,7 @@
     method_reportLocation = env->GetMethodID(clazz, "reportLocation",
             "(ZLandroid/location/Location;)V");
     method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
-    method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "(I[I[F[F[F[F)V");
+    method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "(I[I[F[F[F[F[F)V");
     method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II[B)V");
     method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
     method_setTopHalCapabilities = env->GetMethodID(clazz, "setTopHalCapabilities", "(I)V");
@@ -1746,18 +1806,30 @@
     }
 
     // Allow all causal combinations between IGnss.hal and IGnssMeasurement.hal. That means,
+    // 2.1@IGnss can be paired with {1.0, 1,1, 2.0, 2.1}@IGnssMeasurement
     // 2.0@IGnss can be paired with {1.0, 1,1, 2.0}@IGnssMeasurement
     // 1.1@IGnss can be paired {1.0, 1.1}@IGnssMeasurement
     // 1.0@IGnss is paired with 1.0@IGnssMeasurement
     gnssMeasurementIface = nullptr;
-    if (gnssHal_V2_0 != nullptr) {
+    if (gnssHal_V2_1 != nullptr) {
+        auto gnssMeasurement = gnssHal_V2_1->getExtensionGnssMeasurement_2_1();
+        if (!gnssMeasurement.isOk()) {
+            ALOGD("Unable to get a handle to GnssMeasurement_V2_1");
+        } else {
+            gnssMeasurementIface_V2_1 = gnssMeasurement;
+            gnssMeasurementIface_V2_0 = gnssMeasurementIface_V2_1;
+            gnssMeasurementIface_V1_1 = gnssMeasurementIface_V2_0;
+            gnssMeasurementIface = gnssMeasurementIface_V1_1;
+        }
+    }
+    if (gnssHal_V2_0 != nullptr && gnssMeasurementIface == nullptr) {
         auto gnssMeasurement = gnssHal_V2_0->getExtensionGnssMeasurement_2_0();
         if (!gnssMeasurement.isOk()) {
             ALOGD("Unable to get a handle to GnssMeasurement_V2_0");
         } else {
             gnssMeasurementIface_V2_0 = gnssMeasurement;
             gnssMeasurementIface_V1_1 = gnssMeasurementIface_V2_0;
-            gnssMeasurementIface = gnssMeasurementIface_V2_0;
+            gnssMeasurementIface = gnssMeasurementIface_V1_1;
         }
     }
     if (gnssHal_V1_1 != nullptr && gnssMeasurementIface == nullptr) {
@@ -1925,8 +1997,10 @@
     Return<bool> result = false;
 
     // Set top level IGnss.hal callback.
-    sp<IGnssCallback> gnssCbIface = new GnssCallback();
-    if (gnssHal_V2_0 != nullptr) {
+    sp<IGnssCallback_V2_1> gnssCbIface = new GnssCallback();
+    if (gnssHal_V2_1 != nullptr) {
+        result = gnssHal_V2_1->setCallback_2_1(gnssCbIface);
+    } else if (gnssHal_V2_0 != nullptr) {
         result = gnssHal_V2_0->setCallback_2_0(gnssCbIface);
     } else if (gnssHal_V1_1 != nullptr) {
         result = gnssHal_V1_1->setCallback_1_1(gnssCbIface);
@@ -2559,7 +2633,9 @@
     sp<GnssMeasurementCallback> cbIface = new GnssMeasurementCallback();
     Return<IGnssMeasurement_V1_0::GnssMeasurementStatus> result =
             IGnssMeasurement_V1_0::GnssMeasurementStatus::ERROR_GENERIC;
-    if (gnssMeasurementIface_V2_0 != nullptr) {
+    if (gnssMeasurementIface_V2_1 != nullptr) {
+        result = gnssMeasurementIface_V2_1->setCallback_2_1(cbIface, enableFullTracking);
+    } else if (gnssMeasurementIface_V2_0 != nullptr) {
         result = gnssMeasurementIface_V2_0->setCallback_2_0(cbIface, enableFullTracking);
     } else if (gnssMeasurementIface_V1_1 != nullptr) {
         result = gnssMeasurementIface_V1_1->setCallback_1_1(cbIface, enableFullTracking);
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index efffa6c..692c9d2 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -40,7 +40,6 @@
 int register_android_server_VibratorService(JNIEnv* env);
 int register_android_server_location_GnssLocationProvider(JNIEnv* env);
 int register_android_server_connectivity_Vpn(JNIEnv* env);
-int register_android_server_connectivity_tethering_OffloadHardwareInterface(JNIEnv*);
 int register_android_server_TestNetworkService(JNIEnv* env);
 int register_android_server_devicepolicy_CryptoTestHelper(JNIEnv*);
 int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
@@ -88,7 +87,6 @@
     register_android_server_SystemServer(env);
     register_android_server_location_GnssLocationProvider(env);
     register_android_server_connectivity_Vpn(env);
-    register_android_server_connectivity_tethering_OffloadHardwareInterface(env);
     register_android_server_TestNetworkService(env);
     register_android_server_devicepolicy_CryptoTestHelper(env);
     register_android_server_ConsumerIrService(env);
diff --git a/services/core/xsd/platform-compat-config.xsd b/services/core/xsd/platform-compat-config.xsd
index ee39e50..a70568f 100644
--- a/services/core/xsd/platform-compat-config.xsd
+++ b/services/core/xsd/platform-compat-config.xsd
@@ -28,6 +28,7 @@
                 <xs:attribute type="xs:string" name="name" use="required"/>
                 <xs:attribute type="xs:boolean" name="disabled"/>
                 <xs:attribute type="xs:int" name="enableAfterTargetSdk"/>
+                <xs:attribute type="xs:string" name="description"/>
             </xs:extension>
         </xs:simpleContent>
     </xs:complexType>
diff --git a/services/core/xsd/platform-compat-schema/current.txt b/services/core/xsd/platform-compat-schema/current.txt
index 8456785..3a33f63 100644
--- a/services/core/xsd/platform-compat-schema/current.txt
+++ b/services/core/xsd/platform-compat-schema/current.txt
@@ -3,11 +3,13 @@
 
   public class Change {
     ctor public Change();
+    method public String getDescription();
     method public boolean getDisabled();
     method public int getEnableAfterTargetSdk();
     method public long getId();
     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);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b033492..ee0449d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -137,6 +137,10 @@
 import android.app.admin.SystemUpdateInfo;
 import android.app.admin.SystemUpdatePolicy;
 import android.app.backup.IBackupManager;
+import android.app.timedetector.ManualTimeSuggestion;
+import android.app.timedetector.TimeDetector;
+import android.app.timezonedetector.ManualTimeZoneSuggestion;
+import android.app.timezonedetector.TimeZoneDetector;
 import android.app.trust.TrustManager;
 import android.app.usage.UsageStatsManagerInternal;
 import android.compat.annotation.ChangeId;
@@ -1956,6 +1960,14 @@
             return mContext.getSystemService(AlarmManager.class);
         }
 
+        TimeDetector getTimeDetector() {
+            return mContext.getSystemService(TimeDetector.class);
+        }
+
+        TimeZoneDetector getTimeZoneDetector() {
+            return mContext.getSystemService(TimeZoneDetector.class);
+        }
+
         ConnectivityManager getConnectivityManager() {
             return mContext.getSystemService(ConnectivityManager.class);
         }
@@ -2742,6 +2754,9 @@
             return null;
         }
 
+        // Code for handling failure from getActiveAdminWithPolicyForUidLocked to find an admin
+        // that satisfies the required policy.
+        // Throws a security exception with the right error message.
         if (who != null) {
             final int userId = UserHandle.getUserId(callingUid);
             final DevicePolicyData policy = getUserData(userId);
@@ -2757,6 +2772,10 @@
                 throw new SecurityException("Admin " + admin.info.getComponent()
                         + " does not own the profile");
             }
+            if (reqPolicy == DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER) {
+                throw new SecurityException("Admin " + admin.info.getComponent()
+                        + " is not the profile owner on organization-owned device");
+            }
             if (DA_DISALLOWED_POLICIES.contains(reqPolicy) && !isDeviceOwner && !isProfileOwner) {
                 throw new SecurityException("Admin " + admin.info.getComponent()
                         + " is not a device owner or profile owner, so may not use policy: "
@@ -2863,12 +2882,16 @@
         ensureLocked();
         final boolean ownsDevice = isDeviceOwner(admin.info.getComponent(), userId);
         final boolean ownsProfile = isProfileOwner(admin.info.getComponent(), userId);
+        final boolean ownsProfileOnOrganizationOwnedDevice =
+                    isProfileOwnerOfOrganizationOwnedDevice(admin.info.getComponent(), userId);
 
         if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) {
             return ownsDevice;
+        } else if (reqPolicy == DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER) {
+            return ownsDevice || ownsProfileOnOrganizationOwnedDevice;
         } else if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) {
             // DO always has the PO power.
-            return ownsDevice || ownsProfile;
+            return ownsDevice || ownsProfileOnOrganizationOwnedDevice || ownsProfile;
         } else {
             boolean allowedToUsePolicy = ownsDevice || ownsProfile
                     || !DA_DISALLOWED_POLICIES.contains(reqPolicy)
@@ -4322,6 +4345,40 @@
         }
     }
 
+    /**
+     * Get the list of active admins for an affected user:
+     * <ul>
+     * <li>The active admins associated with the userHandle itself</li>
+     * <li>The parent active admins for each managed profile associated with the userHandle</li>
+     * </ul>
+     *
+     * @param userHandle the affected user for whom to get the active admins
+     * @param parent     whether the parent active admins should be included in the list of active
+     *                   admins or not
+     * @return the list of active admins for the affected user
+     */
+    private List<ActiveAdmin> getActiveAdminsForAffectedUser(int userHandle, boolean parent) {
+        if (!parent) {
+            return getUserDataUnchecked(userHandle).mAdminList;
+        }
+        ArrayList<ActiveAdmin> admins = new ArrayList<>();
+        for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) {
+            DevicePolicyData policy = getUserData(userInfo.id);
+            if (!userInfo.isManagedProfile()) {
+                admins.addAll(policy.mAdminList);
+            } else {
+                // For managed profiles, policies set on the parent profile will be included
+                for (int i = 0; i < policy.mAdminList.size(); i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (admin.hasParentActiveAdmin()) {
+                        admins.add(admin.getParentActiveAdmin());
+                    }
+                }
+            }
+        }
+        return admins;
+    }
+
     private boolean isSeparateProfileChallengeEnabled(int userHandle) {
         long ident = mInjector.binderClearCallingIdentity();
         try {
@@ -5073,118 +5130,58 @@
         }
     }
 
-    private boolean canPOorDOCallResetPassword(ActiveAdmin admin, @UserIdInt int userId) {
-        // Only if the admins targets a pre-O SDK
-        return getTargetSdk(admin.info.getPackageName(), userId) < Build.VERSION_CODES.O;
+    private boolean setPasswordPrivileged(@NonNull String password, int flags, int callingUid) {
+        // Only allow setting password on an unsecured user
+        if (isLockScreenSecureUnchecked(UserHandle.getUserId(callingUid))) {
+            throw new SecurityException("Cannot change current password");
+        }
+        return resetPasswordInternal(password, 0, null, flags, callingUid);
     }
 
-    /* PO or DO could do an untrusted reset in certain conditions. */
-    private boolean canUserHaveUntrustedCredentialReset(@UserIdInt int userId) {
-        synchronized (getLockObject()) {
-            // An active DO or PO might be able to fo an untrusted credential reset
-            for (final ActiveAdmin admin : getUserData(userId).mAdminList) {
-                if (!isActiveAdminWithPolicyForUserLocked(admin,
-                          DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, userId)) {
-                    continue;
-                }
-                if (canPOorDOCallResetPassword(admin, userId)) {
-                    return true;
-                }
-            }
-            return false;
-        }
-    }
     @Override
-    public boolean resetPassword(String passwordOrNull, int flags) throws RemoteException {
+    public boolean resetPassword(@Nullable String password, int flags) throws RemoteException {
         if (!mLockPatternUtils.hasSecureLockScreen()) {
             Slog.w(LOG_TAG, "Cannot reset password when the device has no lock screen");
             return false;
         }
-
+        if (password == null) password = "";
         final int callingUid = mInjector.binderGetCallingUid();
         final int userHandle = mInjector.userHandleGetCallingUserId();
 
-        String password = passwordOrNull != null ? passwordOrNull : "";
-
-        // Password resetting to empty/null is not allowed for managed profiles.
-        if (TextUtils.isEmpty(password)) {
-            enforceNotManagedProfile(userHandle, "clear the active password");
+        // As of R, only privlleged caller holding RESET_PASSWORD can call resetPassword() to
+        // set password to an unsecured user.
+        if (mContext.checkCallingPermission(permission.RESET_PASSWORD)
+                == PackageManager.PERMISSION_GRANTED) {
+            return setPasswordPrivileged(password, flags, callingUid);
         }
 
         synchronized (getLockObject()) {
-            // If caller has PO (or DO) it can change the password, so see if that's the case first.
+            // If caller has PO (or DO) throw or fail silently depending on its target SDK level.
             ActiveAdmin admin = getActiveAdminWithPolicyForUidLocked(
                     null, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, callingUid);
-            final boolean preN;
             if (admin != null) {
-                if (!canPOorDOCallResetPassword(admin, userHandle)) {
-                    throw new SecurityException("resetPassword() is deprecated for DPC targeting O"
-                            + " or later");
-                }
-                preN = getTargetSdk(admin.info.getPackageName(),
-                        userHandle) <= android.os.Build.VERSION_CODES.M;
-            } else {
-                // Otherwise, make sure the caller has any active admin with the right policy or
-                // the required permission.
-                admin = getActiveAdminOrCheckPermissionForCallerLocked(
-                        null,
-                        DeviceAdminInfo.USES_POLICY_RESET_PASSWORD,
-                        android.Manifest.permission.RESET_PASSWORD);
-                // Cannot be preN if admin is null because an exception would have been
-                // thrown before getting here
-                preN = admin == null ? false : getTargetSdk(admin.info.getPackageName(),
-                        userHandle) <= android.os.Build.VERSION_CODES.M;
-
-                // As of N, password resetting to empty/null is not allowed anymore.
-                // TODO Should we allow DO/PO to set an empty password?
-                if (TextUtils.isEmpty(password)) {
-                    if (!preN) {
-                        throw new SecurityException("Cannot call with null password");
-                    } else {
-                        Slog.e(LOG_TAG, "Cannot call with null password");
-                        return false;
-                    }
-                }
-                // As of N, password cannot be changed by the admin if it is already set.
-                if (isLockScreenSecureUnchecked(userHandle)) {
-                    if (!preN) {
-                        throw new SecurityException("Cannot change current password");
-                    } else {
-                        Slog.e(LOG_TAG, "Cannot change current password");
-                        return false;
-                    }
-                }
-            }
-            // Do not allow to reset password when current user has a managed profile
-            if (!isManagedProfile(userHandle)) {
-                for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) {
-                    if (userInfo.isManagedProfile()) {
-                        if (!preN) {
-                            throw new IllegalStateException(
-                                    "Cannot reset password on user has managed profile");
-                        } else {
-                            Slog.e(LOG_TAG, "Cannot reset password on user has managed profile");
-                            return false;
-                        }
-                    }
-                }
-            }
-            // Do not allow to reset password when user is locked
-            if (!mUserManager.isUserUnlocked(userHandle)) {
-                if (!preN) {
-                    throw new IllegalStateException("Cannot reset password when user is locked");
-                } else {
-                    Slog.e(LOG_TAG, "Cannot reset password when user is locked");
+                if (getTargetSdk(admin.info.getPackageName(), userHandle) < Build.VERSION_CODES.O) {
+                    Slog.e(LOG_TAG, "DPC can no longer call resetPassword()");
                     return false;
                 }
+                throw new SecurityException("Device admin can no longer call resetPassword()");
             }
-        }
 
-        return resetPasswordInternal(password, 0, null, flags, callingUid, userHandle);
+            // Legacy device admin cannot call resetPassword either
+            admin = getActiveAdminForCallerLocked(
+                    null, DeviceAdminInfo.USES_POLICY_RESET_PASSWORD, false);
+            if (getTargetSdk(admin.info.getPackageName(),
+                    userHandle) <= android.os.Build.VERSION_CODES.M) {
+                Slog.e(LOG_TAG, "Device admin can no longer call resetPassword()");
+                return false;
+            }
+            throw new SecurityException("Device admin can no longer call resetPassword()");
+        }
     }
 
     private boolean resetPasswordInternal(String password, long tokenHandle, byte[] token,
-            int flags, int callingUid, int userHandle) {
+            int flags, int callingUid) {
+        final int userHandle = UserHandle.getUserId(callingUid);
         synchronized (getLockObject()) {
             final PasswordMetrics minMetrics = getPasswordMinimumMetrics(userHandle);
             final List<PasswordValidationError> validationErrors;
@@ -5222,21 +5219,19 @@
         // Don't do this with the lock held, because it is going to call
         // back in to the service.
         final long ident = mInjector.binderClearCallingIdentity();
-        final boolean result;
         final LockscreenCredential newCredential =
                 LockscreenCredential.createPasswordOrNone(password);
         try {
-            if (token == null) {
-                // This is the legacy reset password for DPM. Here we want to be able to override
-                // the old device password without necessarily knowing it.
-                mLockPatternUtils.setLockCredential(
-                        newCredential,
-                        LockscreenCredential.createNone(),
-                        userHandle, /*allowUntrustedChange */true);
-                result = true;
+            if (tokenHandle == 0 || token == null) {
+                if (!mLockPatternUtils.setLockCredential(newCredential,
+                        LockscreenCredential.createNone(), userHandle)) {
+                    return false;
+                }
             } else {
-                result = mLockPatternUtils.setLockCredentialWithToken(newCredential, tokenHandle,
-                        token, userHandle);
+                if (!mLockPatternUtils.setLockCredentialWithToken(newCredential, tokenHandle,
+                        token, userHandle)) {
+                    return false;
+                }
             }
             boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0;
             if (requireEntry) {
@@ -5253,7 +5248,7 @@
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
         }
-        return result;
+        return true;
     }
 
     private boolean isLockScreenSecureUnchecked(int userId) {
@@ -5568,8 +5563,15 @@
         }
     }
 
-    private void enforceProfileOwnerOfCorpOwnedDevice(ActiveAdmin admin) {
-        if (!isProfileOwnerOfOrganizationOwnedDevicte(admin)) {
+    private void enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(ComponentName who) {
+        synchronized (getLockObject()) {
+            getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER);
+        }
+    }
+
+    private void enforceProfileOwnerOfOrganizationOwnedDevice(ActiveAdmin admin) {
+        if (!isProfileOwnerOfOrganizationOwnedDevice(admin)) {
             throw new SecurityException(String.format("Provided admin %s is either not a profile "
                     + "owner or not on a corporate-owned device.", admin));
         }
@@ -6639,7 +6641,7 @@
         }
 
         boolean calledByProfileOwnerOnOrgOwnedDevice =
-                isProfileOwnerOfOrganizationOwnedDevicte(admin);
+                isProfileOwnerOfOrganizationOwnedDevice(admin);
 
         if (calledOnParentInstance && !calledByProfileOwnerOnOrgOwnedDevice) {
             throw new SecurityException("Wiping the entire device can only be done by a profile"
@@ -6679,6 +6681,9 @@
                     mUserManager.setUserRestriction(
                             UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, false,
                             UserHandle.SYSTEM);
+
+                    // Device-wide policies set by the profile owner need to be cleaned up here.
+                    mLockPatternUtils.setDeviceOwnerInfo(null);
                 } finally {
                     mInjector.binderRestoreCallingIdentity(ident);
                 }
@@ -7357,6 +7362,7 @@
             }
         }
 
+        // TODO: (b/145604635) Add upgrade case
         // Turn AUTO_TIME on in settings if it is required
         if (required) {
             long ident = mInjector.binderClearCallingIdentity();
@@ -7400,6 +7406,42 @@
         }
     }
 
+    /**
+     * Set whether auto time is enabled on the device.
+     */
+    @Override
+    public void setAutoTime(ComponentName who, boolean enabled) {
+        if (!mHasFeature) {
+            return;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        // TODO (b/145286957) Refactor security checks
+        enforceDeviceOwnerOrProfileOwnerOnUser0OrProfileOwnerOrganizationOwned();
+
+        mInjector.binderWithCleanCallingIdentity(() ->
+                mInjector.settingsGlobalPutInt(Settings.Global.AUTO_TIME, enabled ? 1 : 0));
+
+        DevicePolicyEventLogger
+                .createEvent(DevicePolicyEnums.SET_AUTO_TIME)
+                .setAdmin(who)
+                .setBoolean(enabled)
+                .write();
+    }
+
+    /**
+     * Returns whether or auto time is used on the device or not.
+     */
+    @Override
+    public boolean getAutoTime(ComponentName who) {
+        if (!mHasFeature) {
+            return false;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        enforceDeviceOwnerOrProfileOwnerOnUser0OrProfileOwnerOrganizationOwned();
+
+        return mInjector.settingsGlobalGetInt(Global.AUTO_TIME, 0) > 0;
+    }
+
     @Override
     public void setForceEphemeralUsers(ComponentName who, boolean forceEphemeralUsers) {
         if (!mHasFeature) {
@@ -7699,22 +7741,25 @@
      * Disables all device cameras according to the specified admin.
      */
     @Override
-    public void setCameraDisabled(ComponentName who, boolean disabled) {
+    public void setCameraDisabled(ComponentName who, boolean disabled, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = mInjector.userHandleGetCallingUserId();
+        int userHandle = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA);
+                    DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA, parent);
+            if (parent) {
+                enforceProfileOwnerOfOrganizationOwnedDevice(ap);
+            }
             if (ap.disableCamera != disabled) {
                 ap.disableCamera = disabled;
                 saveSettingsLocked(userHandle);
             }
         }
         // Tell the user manager that the restrictions have changed.
-        pushUserRestrictions(userHandle);
+        pushUserRestrictions(parent ?  getProfileParentId(userHandle) : userHandle);
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_CAMERA_DISABLED)
                 .setAdmin(who)
@@ -7727,18 +7772,23 @@
      * active admins.
      */
     @Override
-    public boolean getCameraDisabled(ComponentName who, int userHandle) {
-        return getCameraDisabled(who, userHandle, /* mergeDeviceOwnerRestriction= */ true);
+    public boolean getCameraDisabled(ComponentName who, int userHandle, boolean parent) {
+        return getCameraDisabled(who, userHandle, /* mergeDeviceOwnerRestriction= */ true, parent);
     }
 
     private boolean getCameraDisabled(ComponentName who, int userHandle,
-            boolean mergeDeviceOwnerRestriction) {
+            boolean mergeDeviceOwnerRestriction, boolean parent) {
         if (!mHasFeature) {
             return false;
         }
+        if (parent) {
+            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA, parent);
+            enforceProfileOwnerOfOrganizationOwnedDevice(ap);
+        }
         synchronized (getLockObject()) {
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                 return (admin != null) ? admin.disableCamera : false;
             }
             // First, see if DO has set it.  If so, it's device-wide.
@@ -7748,13 +7798,10 @@
                     return true;
                 }
             }
-
-            // Then check each device admin on the user.
-            DevicePolicyData policy = getUserData(userHandle);
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins = getActiveAdminsForAffectedUser(userHandle, parent);
             // Determine whether or not the device camera is disabled for any active admins.
-            final int N = policy.mAdminList.size();
-            for (int i = 0; i < N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
+            for (ActiveAdmin admin: admins) {
                 if (admin.disableCamera) {
                     return true;
                 }
@@ -8020,26 +8067,17 @@
      * {@code getActiveAdminForCallerLocked} or one of the similar variants, not caller-supplied
      * input.
      */
-    private boolean isProfileOwnerOfOrganizationOwnedDevicte(@Nullable ActiveAdmin admin) {
+    private boolean isProfileOwnerOfOrganizationOwnedDevice(@Nullable ActiveAdmin admin) {
         if (admin == null) {
             return false;
         }
 
-        final int adminUserId = admin.getUserHandle().getIdentifier();
+        return isProfileOwnerOfOrganizationOwnedDevice(
+                admin.info.getComponent(), admin.getUserHandle().getIdentifier());
+    }
 
-        if (!isProfileOwner(admin.info.getComponent(), adminUserId)) {
-            Slog.w(LOG_TAG, String.format("%s is not profile owner of user %d",
-                    admin.info.getComponent(), adminUserId));
-            return false;
-        }
-
-        if (!canProfileOwnerAccessDeviceIds(adminUserId)) {
-            Slog.w(LOG_TAG, String.format("Profile owner of user %d does not own the device.",
-                    adminUserId));
-            return false;
-        }
-
-        return true;
+    private boolean isProfileOwnerOfOrganizationOwnedDevice(ComponentName who, int userId) {
+        return isProfileOwner(who, userId) && canProfileOwnerAccessDeviceIds(userId);
     }
 
     @Override
@@ -8328,14 +8366,17 @@
         }
 
         synchronized (getLockObject()) {
-            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
-            long token = mInjector.binderClearCallingIdentity();
-            try {
-                mLockPatternUtils.setDeviceOwnerInfo(info != null ? info.toString() : null);
-            } finally {
-                mInjector.binderRestoreCallingIdentity(token);
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            if (!isProfileOwnerOfOrganizationOwnedDevice(admin) && !isDeviceOwner(admin)) {
+                throw new SecurityException("Only Device Owner or Profile Owner of"
+                        + " organization-owned device can set screen lock info.");
             }
         }
+
+        mInjector.binderWithCleanCallingIdentity(() ->
+                mLockPatternUtils.setDeviceOwnerInfo(info != null ? info.toString() : null));
+
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_DEVICE_OWNER_LOCK_SCREEN_INFO)
                 .setAdmin(who)
@@ -8572,6 +8613,25 @@
         return null;
     }
 
+    @GuardedBy("getLockObject()")
+    ActiveAdmin getProfileOwnerOfOrganizationOwnedDeviceLocked(int userHandle) {
+        final long ident = mInjector.binderClearCallingIdentity();
+        try {
+            for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) {
+                if (userInfo.isManagedProfile()) {
+                    if (getProfileOwner(userInfo.id) != null
+                            && canProfileOwnerAccessDeviceIds(userInfo.id)) {
+                        ComponentName who = getProfileOwner(userInfo.id);
+                        return getActiveAdminUncheckedLocked(who, userInfo.id);
+                    }
+                }
+            }
+        } finally {
+            mInjector.binderRestoreCallingIdentity(ident);
+        }
+        return null;
+    }
+
     @Override
     public String getProfileOwnerName(int userHandle) {
         if (!mHasFeature) {
@@ -8587,20 +8647,42 @@
 
     @Override
     public boolean checkDeviceIdentifierAccess(String packageName, int pid, int uid) {
-        // If the caller is not a system app then it should only be able to check its own device
-        // identifier access.
-        int callingUid = mInjector.binderGetCallingUid();
-        int callingPid = mInjector.binderGetCallingPid();
-        if (UserHandle.getAppId(callingUid) >= Process.FIRST_APPLICATION_UID
-                && (callingUid != uid || callingPid != pid)) {
-            String message = String.format(
-                    "Calling uid %d, pid %d cannot check device identifier access for package %s "
-                            + "(uid=%d, pid=%d)", callingUid, callingPid, packageName, uid, pid);
-            Log.w(LOG_TAG, message);
-            throw new SecurityException(message);
-        }
+        ensureCallerIdentityMatchesIfNotSystem(packageName, pid, uid);
+
         // Verify that the specified packages matches the provided uid.
-        int userId = UserHandle.getUserId(uid);
+        if (!doesPackageMatchUid(packageName, uid)) {
+            return false;
+        }
+        // A device or profile owner must also have the READ_PHONE_STATE permission to access device
+        // identifiers. If the package being checked does not have this permission then deny access.
+        if (mContext.checkPermission(android.Manifest.permission.READ_PHONE_STATE, pid, uid)
+                != PackageManager.PERMISSION_GRANTED) {
+            return false;
+        }
+
+        // Allow access to the device owner or delegate cert installer.
+        ComponentName deviceOwner = getDeviceOwnerComponent(true);
+        if (deviceOwner != null && (deviceOwner.getPackageName().equals(packageName)
+                    || isCallerDelegate(packageName, uid, DELEGATION_CERT_INSTALL))) {
+            return true;
+        }
+        final int userId = UserHandle.getUserId(uid);
+        // Allow access to the profile owner for the specified user, or delegate cert installer
+        // But only if this is an organization-owned device.
+        ComponentName profileOwner = getProfileOwnerAsUser(userId);
+        if (profileOwner != null && canProfileOwnerAccessDeviceIds(userId)
+                && (profileOwner.getPackageName().equals(packageName)
+                || isCallerDelegate(packageName, uid, DELEGATION_CERT_INSTALL))) {
+            return true;
+        }
+
+        Log.w(LOG_TAG, String.format("Package %s (uid=%d, pid=%d) cannot access Device IDs",
+                    packageName, uid, pid));
+        return false;
+    }
+
+    private boolean doesPackageMatchUid(String packageName, int uid) {
+        final int userId = UserHandle.getUserId(uid);
         try {
             ApplicationInfo appInfo = mIPackageManager.getApplicationInfo(packageName, 0, userId);
             // Since this call goes directly to PackageManagerService a NameNotFoundException is not
@@ -8622,29 +8704,22 @@
             Log.e(LOG_TAG, "Exception caught obtaining appInfo for package " + packageName, e);
             return false;
         }
-        // A device or profile owner must also have the READ_PHONE_STATE permission to access device
-        // identifiers. If the package being checked does not have this permission then deny access.
-        if (mContext.checkPermission(android.Manifest.permission.READ_PHONE_STATE, pid, uid)
-                != PackageManager.PERMISSION_GRANTED) {
-            return false;
-        }
+        return true;
+    }
 
-        // Allow access to the device owner or delegate cert installer.
-        ComponentName deviceOwner = getDeviceOwnerComponent(true);
-        if (deviceOwner != null && (deviceOwner.getPackageName().equals(packageName)
-                    || isCallerDelegate(packageName, uid, DELEGATION_CERT_INSTALL))) {
-            return true;
+    private void ensureCallerIdentityMatchesIfNotSystem(String packageName, int pid, int uid) {
+        // If the caller is not a system app then it should only be able to check its own device
+        // identifier access.
+        int callingUid = mInjector.binderGetCallingUid();
+        int callingPid = mInjector.binderGetCallingPid();
+        if (UserHandle.getAppId(callingUid) >= Process.FIRST_APPLICATION_UID
+                && (callingUid != uid || callingPid != pid)) {
+            String message = String.format(
+                    "Calling uid %d, pid %d cannot check device identifier access for package %s "
+                            + "(uid=%d, pid=%d)", callingUid, callingPid, packageName, uid, pid);
+            Log.w(LOG_TAG, message);
+            throw new SecurityException(message);
         }
-        // Allow access to the profile owner for the specified user, or delegate cert installer
-        ComponentName profileOwner = getProfileOwnerAsUser(userId);
-        if (profileOwner != null && (profileOwner.getPackageName().equals(packageName)
-                    || isCallerDelegate(packageName, uid, DELEGATION_CERT_INSTALL))) {
-            return true;
-        }
-
-        Log.w(LOG_TAG, String.format("Package %s (uid=%d, pid=%d) cannot access Device IDs",
-                    packageName, uid, pid));
-        return false;
     }
 
     /**
@@ -8871,6 +8946,28 @@
                 "Only profile owner, device owner and system may call this method.");
     }
 
+    private ActiveAdmin enforceDeviceOwnerOrProfileOwnerOnUser0OrProfileOwnerOrganizationOwned() {
+        synchronized (getLockObject()) {
+            // Check if there is a device owner
+            ActiveAdmin deviceOwner = getActiveAdminWithPolicyForUidLocked(null,
+                    DeviceAdminInfo.USES_POLICY_DEVICE_OWNER, mInjector.binderGetCallingUid());
+            if (deviceOwner != null) return deviceOwner;
+
+            ActiveAdmin profileOwner = getActiveAdminWithPolicyForUidLocked(null,
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, mInjector.binderGetCallingUid());
+
+            // Check if there is a profile owner of an organization owned device
+            if (isProfileOwnerOfOrganizationOwnedDevice(profileOwner)) return profileOwner;
+
+            // Check if there is a profile owner called on user 0
+            if (profileOwner != null) {
+                enforceCallerSystemUserHandle();
+                return profileOwner;
+            }
+        }
+        throw new SecurityException("No active admin found");
+    }
+
     private void enforceProfileOwnerOrFullCrossUsersPermission(int userId) {
         if (userId == mInjector.userHandleGetCallingUserId()) {
             synchronized (getLockObject()) {
@@ -10222,9 +10319,8 @@
     private void pushUserRestrictions(int userId) {
         synchronized (getLockObject()) {
             final boolean isDeviceOwner = mOwners.isDeviceOwnerUserId(userId);
-            final Bundle userRestrictions;
-            // Whether device owner enforces camera restriction.
-            boolean disallowCameraGlobally = false;
+            Bundle userRestrictions = null;
+            final int restrictionOwnerType;
 
             if (isDeviceOwner) {
                 final ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
@@ -10232,33 +10328,63 @@
                     return; // Shouldn't happen.
                 }
                 userRestrictions = deviceOwner.userRestrictions;
-                // DO can disable camera globally.
-                disallowCameraGlobally = deviceOwner.disableCamera;
+                addOrRemoveDisableCameraRestriction(userRestrictions, deviceOwner);
+                restrictionOwnerType = UserManagerInternal.OWNER_TYPE_DEVICE_OWNER;
             } else {
-                final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId);
-                userRestrictions = profileOwner != null ? profileOwner.userRestrictions : null;
+                final ActiveAdmin profileOwnerOfOrganizationOwnedDevice =
+                        getProfileOwnerOfOrganizationOwnedDeviceLocked(userId);
+
+                // If profile owner of an organization owned device, the restrictions will be
+                // pushed to the parent instance.
+                if (profileOwnerOfOrganizationOwnedDevice != null && !isManagedProfile(userId)) {
+                    restrictionOwnerType =
+                          UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE;
+                    final ActiveAdmin parent = profileOwnerOfOrganizationOwnedDevice
+                            .getParentActiveAdmin();
+                    userRestrictions = parent.userRestrictions;
+                    userRestrictions = addOrRemoveDisableCameraRestriction(userRestrictions,
+                            parent);
+                } else {
+                    final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId);
+
+                    if (profileOwner != null) {
+                        userRestrictions = profileOwner.userRestrictions;
+                        restrictionOwnerType = UserManagerInternal.OWNER_TYPE_PROFILE_OWNER;
+                    } else {
+                        restrictionOwnerType = UserManagerInternal.OWNER_TYPE_NO_OWNER;
+                    }
+                    userRestrictions = addOrRemoveDisableCameraRestriction(
+                            userRestrictions, userId);
+                }
             }
-
-            // Whether any admin enforces camera restriction.
-            final int cameraRestrictionScope =
-                    getCameraRestrictionScopeLocked(userId, disallowCameraGlobally);
-
             mUserManagerInternal.setDevicePolicyUserRestrictions(userId, userRestrictions,
-                    isDeviceOwner, cameraRestrictionScope);
+                    restrictionOwnerType);
         }
     }
 
-    /**
-     * Get the scope of camera restriction for a given user if any.
-     */
-    private int getCameraRestrictionScopeLocked(int userId, boolean disallowCameraGlobally) {
-        if (disallowCameraGlobally) {
-            return UserManagerInternal.CAMERA_DISABLED_GLOBALLY;
-        } else if (getCameraDisabled(
-                /* who= */ null, userId, /* mergeDeviceOwnerRestriction= */ false)) {
-            return UserManagerInternal.CAMERA_DISABLED_LOCALLY;
+    private Bundle addOrRemoveDisableCameraRestriction(Bundle userRestrictions, ActiveAdmin admin) {
+        if (userRestrictions == null) {
+            userRestrictions = new Bundle();
         }
-        return UserManagerInternal.CAMERA_NOT_DISABLED;
+        if (admin.disableCamera) {
+            userRestrictions.putBoolean(UserManager.DISALLOW_CAMERA, true);
+        } else {
+            userRestrictions.remove(UserManager.DISALLOW_CAMERA);
+        }
+        return userRestrictions;
+    }
+
+    private Bundle addOrRemoveDisableCameraRestriction(Bundle userRestrictions, int userId) {
+        if (userRestrictions == null) {
+            userRestrictions = new Bundle();
+        }
+        if (getCameraDisabled(/* who= */ null, userId, /* mergeDeviceOwnerRestriction= */
+                false)) {
+            userRestrictions.putBoolean(UserManager.DISALLOW_CAMERA, true);
+        } else {
+            userRestrictions.remove(UserManager.DISALLOW_CAMERA);
+        }
+        return userRestrictions;
     }
 
     @Override
@@ -10987,31 +11113,20 @@
     @Override
     public void setLocationEnabled(ComponentName who, boolean locationEnabled) {
         Preconditions.checkNotNull(who, "ComponentName is null");
-        int userId = mInjector.userHandleGetCallingUserId();
+        enforceDeviceOwner(who);
 
-        synchronized (getLockObject()) {
-            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+        UserHandle userHandle = mInjector.binderGetCallingUserHandle();
+        mInjector.binderWithCleanCallingIdentity(
+                () -> mInjector.getLocationManager().setLocationEnabledForUser(locationEnabled,
+                        userHandle));
 
-            if (!isDeviceOwner(who, userId) && !isCurrentUserDemo()) {
-                throw new SecurityException(
-                        "Permission denial: Profile owners cannot update location settings");
-            }
-        }
-
-        long ident = mInjector.binderClearCallingIdentity();
-        try {
-            mInjector.getLocationManager().setLocationEnabledForUser(
-                    locationEnabled, UserHandle.of(userId));
-            DevicePolicyEventLogger
-                    .createEvent(DevicePolicyEnums.SET_SECURE_SETTING)
-                    .setAdmin(who)
-                    .setStrings(Settings.Secure.LOCATION_MODE, Integer.toString(
-                            locationEnabled ? Settings.Secure.LOCATION_MODE_ON
-                                    : Settings.Secure.LOCATION_MODE_OFF))
-                    .write();
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
-        }
+        DevicePolicyEventLogger
+                .createEvent(DevicePolicyEnums.SET_SECURE_SETTING)
+                .setAdmin(who)
+                .setStrings(Settings.Secure.LOCATION_MODE, Integer.toString(
+                        locationEnabled ? Settings.Secure.LOCATION_MODE_ON
+                                : Settings.Secure.LOCATION_MODE_OFF))
+                .write();
     }
 
     @Override
@@ -11022,7 +11137,10 @@
         if (mInjector.settingsGlobalGetInt(Global.AUTO_TIME, 0) == 1) {
             return false;
         }
-        mInjector.binderWithCleanCallingIdentity(() -> mInjector.getAlarmManager().setTime(millis));
+        ManualTimeSuggestion manualTimeSuggestion = TimeDetector.createManualTimeSuggestion(
+                millis, "DevicePolicyManagerService: setTime");
+        mInjector.binderWithCleanCallingIdentity(
+                () -> mInjector.getTimeDetector().suggestManualTime(manualTimeSuggestion));
         return true;
     }
 
@@ -11034,8 +11152,11 @@
         if (mInjector.settingsGlobalGetInt(Global.AUTO_TIME_ZONE, 0) == 1) {
             return false;
         }
+        ManualTimeZoneSuggestion manualTimeZoneSuggestion =
+                TimeZoneDetector.createManualTimeZoneSuggestion(
+                        timeZone, "DevicePolicyManagerService: setTimeZone");
         mInjector.binderWithCleanCallingIdentity(() ->
-            mInjector.getAlarmManager().setTimeZone(timeZone));
+                mInjector.getTimeZoneDetector().suggestManualTimeZone(manualTimeZoneSuggestion));
         return true;
     }
 
@@ -11566,11 +11687,6 @@
         }
 
         @Override
-        public boolean canUserHaveUntrustedCredentialReset(@UserIdInt int userId) {
-            return DevicePolicyManagerService.this.canUserHaveUntrustedCredentialReset(userId);
-        }
-
-        @Override
         public CharSequence getPrintingDisabledReasonForUser(@UserIdInt int userId) {
             synchronized (getLockObject()) {
                 if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_PRINTING,
@@ -12288,7 +12404,7 @@
     @Override
     public String getWifiMacAddress(ComponentName admin) {
         // Make sure caller has DO.
-        enforceDeviceOwner(admin);
+        enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(admin);
 
         final long ident = mInjector.binderClearCallingIdentity();
         try {
@@ -13783,7 +13899,7 @@
             if (policy.mPasswordTokenHandle != 0) {
                 final String password = passwordOrNull != null ? passwordOrNull : "";
                 return resetPasswordInternal(password, policy.mPasswordTokenHandle, token,
-                        flags, mInjector.binderGetCallingUid(), userHandle);
+                        flags, mInjector.binderGetCallingUid());
             } else {
                 Slog.w(LOG_TAG, "No saved token handle");
             }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index f46857a..21cacd45 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -43,9 +43,11 @@
 import android.hardware.display.DisplayManagerInternal;
 import android.net.ConnectivityModuleConnector;
 import android.net.NetworkStackClient;
+import android.net.TetheringManager;
 import android.os.BaseBundle;
 import android.os.Binder;
 import android.os.Build;
+import android.os.Debug;
 import android.os.Environment;
 import android.os.FactoryTest;
 import android.os.FileUtils;
@@ -268,6 +270,8 @@
             "com.android.internal.car.CarServiceHelperService";
     private static final String TIME_DETECTOR_SERVICE_CLASS =
             "com.android.server.timedetector.TimeDetectorService$Lifecycle";
+    private static final String TIME_ZONE_DETECTOR_SERVICE_CLASS =
+            "com.android.server.timezonedetector.TimeZoneDetectorService$Lifecycle";
     private static final String ACCESSIBILITY_MANAGER_SERVICE_CLASS =
             "com.android.server.accessibility.AccessibilityManagerService$Lifecycle";
     private static final String ADB_SERVICE_CLASS =
@@ -444,10 +448,6 @@
             // Mmmmmm... more memory!
             VMRuntime.getRuntime().clearGrowthLimit();
 
-            // The system server has to run all of the time, so it needs to be
-            // as efficient as possible with its memory usage.
-            VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
-
             // Some devices rely on runtime fingerprint generation, so make sure
             // we've defined it before booting further.
             Build.ensureFingerprintProperty();
@@ -499,6 +499,24 @@
             LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
             // Prepare the thread pool for init tasks that can be parallelized
             SystemServerInitThreadPool.start();
+            // Attach JVMTI agent if this is a debuggable build and the system property is set.
+            if (Build.IS_DEBUGGABLE) {
+                // Property is of the form "library_path=parameters".
+                String jvmtiAgent = SystemProperties.get("persist.sys.dalvik.jvmtiagent");
+                if (!jvmtiAgent.isEmpty()) {
+                    int equalIndex = jvmtiAgent.indexOf('=');
+                    String libraryPath = jvmtiAgent.substring(0, equalIndex);
+                    String parameterList =
+                            jvmtiAgent.substring(equalIndex + 1, jvmtiAgent.length());
+                    // Attach the agent.
+                    try {
+                        Debug.attachJvmtiAgent(libraryPath, parameterList, null);
+                    } catch (Exception e) {
+                        Slog.e("System", "*************************************************");
+                        Slog.e("System", "********** Failed to load jvmti plugin: " + jvmtiAgent);
+                    }
+                }
+            }
         } finally {
             t.traceEnd();  // InitBeforeStartServices
         }
@@ -1111,9 +1129,10 @@
             SignedConfigService.registerUpdateReceiver(mSystemContext);
             t.traceEnd();
 
-        } catch (RuntimeException e) {
+        } catch (Throwable e) {
             Slog.e("System", "******************************************");
-            Slog.e("System", "************ Failure starting core service", e);
+            Slog.e("System", "************ Failure starting core service");
+            throw e;
         }
 
         // Before things start rolling, be sure we have decided whether
@@ -1480,6 +1499,14 @@
             }
             t.traceEnd();
 
+            t.traceBegin("StartTimeZoneDetectorService");
+            try {
+                mSystemServiceManager.startService(TIME_ZONE_DETECTOR_SERVICE_CLASS);
+            } catch (Throwable e) {
+                reportWtf("starting StartTimeZoneDetectorService service", e);
+            }
+            t.traceEnd();
+
             if (!isWatch) {
                 t.traceBegin("StartSearchManagerService");
                 try {
@@ -2204,6 +2231,15 @@
             }
             t.traceEnd();
 
+            t.traceBegin("StartTethering");
+            try {
+                // Tethering must start after ConnectivityService and NetworkStack.
+                TetheringManager.getInstance().start();
+            } catch (Throwable e) {
+                reportWtf("starting Tethering", e);
+            }
+            t.traceEnd();
+
             t.traceBegin("MakeCountryDetectionServiceReady");
             try {
                 if (countryDetectorF != null) {
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 7ef9f44..3babb0b 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -9,8 +9,8 @@
     name: "services.net",
     srcs: [
         ":net-module-utils-srcs",
-        ":tethering-servicesnet-srcs",
         ":services.net-sources",
+        ":tethering-manager",
     ],
     static_libs: [
         "dnsresolver_aidl_interface-V2-java",
diff --git a/services/net/java/android/net/ip/IpClientCallbacks.java b/services/net/java/android/net/ip/IpClientCallbacks.java
index db01ae4..61cd88a 100644
--- a/services/net/java/android/net/ip/IpClientCallbacks.java
+++ b/services/net/java/android/net/ip/IpClientCallbacks.java
@@ -17,8 +17,11 @@
 package android.net.ip;
 
 import android.net.DhcpResults;
+import android.net.Layer2PacketParcelable;
 import android.net.LinkProperties;
 
+import java.util.List;
+
 /**
  * Callbacks for handling IpClient events.
  *
@@ -116,4 +119,9 @@
      * whenever 464xlat is being started or stopped.
      */
     public void setNeighborDiscoveryOffload(boolean enable) {}
+
+    /**
+     * Invoked on starting preconnection process.
+     */
+    public void onPreconnectionStart(List<Layer2PacketParcelable> packets) {}
 }
diff --git a/services/net/java/android/net/ip/IpClientManager.java b/services/net/java/android/net/ip/IpClientManager.java
index 1e653cd..4b7ed3c 100644
--- a/services/net/java/android/net/ip/IpClientManager.java
+++ b/services/net/java/android/net/ip/IpClientManager.java
@@ -234,7 +234,7 @@
                     slot, KeepalivePacketDataUtil.toStableParcelable(pkt));
             return true;
         } catch (RemoteException e) {
-            log("Error adding Keepalive Packet Filter ", e);
+            log("Error adding NAT-T Keepalive Packet Filter ", e);
             return false;
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -272,4 +272,22 @@
             Binder.restoreCallingIdentity(token);
         }
     }
+
+    /**
+     * Notify IpClient that preconnection is complete and that the link is ready for use.
+     * The success parameter indicates whether the packets passed in by 'onPreconnectionStart'
+     * were successfully sent to the network or not.
+     */
+    public boolean notifyPreconnectionComplete(boolean success) {
+        final long token = Binder.clearCallingIdentity();
+        try {
+            mIpClient.notifyPreconnectionComplete(success);
+            return true;
+        } catch (RemoteException e) {
+            log("Error notifying IpClient Preconnection completed", e);
+            return false;
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
 }
diff --git a/services/net/java/android/net/ip/IpClientUtil.java b/services/net/java/android/net/ip/IpClientUtil.java
index 714ade1..4d60e62 100644
--- a/services/net/java/android/net/ip/IpClientUtil.java
+++ b/services/net/java/android/net/ip/IpClientUtil.java
@@ -20,12 +20,14 @@
 
 import android.content.Context;
 import android.net.DhcpResultsParcelable;
+import android.net.Layer2PacketParcelable;
 import android.net.LinkProperties;
 import android.net.NetworkStackClient;
 import android.os.ConditionVariable;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.List;
 
 
 /**
@@ -176,6 +178,12 @@
             mCb.setNeighborDiscoveryOffload(enable);
         }
 
+        // Invoked on starting preconnection process.
+        @Override
+        public void onPreconnectionStart(List<Layer2PacketParcelable> packets) {
+            mCb.onPreconnectionStart(packets);
+        }
+
         @Override
         public int getInterfaceVersion() {
             return this.VERSION;
diff --git a/services/net/java/android/net/util/VersionedBroadcastListener.java b/services/net/java/android/net/util/VersionedBroadcastListener.java
deleted file mode 100644
index 107c404..0000000
--- a/services/net/java/android/net/util/VersionedBroadcastListener.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.util;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Handler;
-import android.util.Log;
-
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.Consumer;
-
-
-/**
- * A utility class that runs the provided callback on the provided handler when
- * intents matching the provided filter arrive. Intents received by a stale
- * receiver are safely ignored.
- *
- * Calls to startListening() and stopListening() must happen on the same thread.
- *
- * @hide
- */
-public class VersionedBroadcastListener {
-    private static final boolean DBG = false;
-
-    public interface IntentCallback {
-        public void run(Intent intent);
-    }
-
-    private final String mTag;
-    private final Context mContext;
-    private final Handler mHandler;
-    private final IntentFilter mFilter;
-    private final Consumer<Intent> mCallback;
-    private final AtomicInteger mGenerationNumber;
-    private BroadcastReceiver mReceiver;
-
-    public VersionedBroadcastListener(String tag, Context ctx, Handler handler,
-            IntentFilter filter, Consumer<Intent> callback) {
-        mTag = tag;
-        mContext = ctx;
-        mHandler = handler;
-        mFilter = filter;
-        mCallback = callback;
-        mGenerationNumber = new AtomicInteger(0);
-    }
-
-    public void startListening() {
-        if (DBG) Log.d(mTag, "startListening");
-        if (mReceiver != null) return;
-
-        mReceiver = new Receiver(mTag, mGenerationNumber, mCallback);
-        mContext.registerReceiver(mReceiver, mFilter, null, mHandler);
-    }
-
-    public void stopListening() {
-        if (DBG) Log.d(mTag, "stopListening");
-        if (mReceiver == null) return;
-
-        mGenerationNumber.incrementAndGet();
-        mContext.unregisterReceiver(mReceiver);
-        mReceiver = null;
-    }
-
-    private static class Receiver extends BroadcastReceiver {
-        public final String tag;
-        public final AtomicInteger atomicGenerationNumber;
-        public final Consumer<Intent> callback;
-        // Used to verify this receiver is still current.
-        public final int generationNumber;
-
-        public Receiver(
-                String tag, AtomicInteger atomicGenerationNumber, Consumer<Intent> callback) {
-            this.tag = tag;
-            this.atomicGenerationNumber = atomicGenerationNumber;
-            this.callback = callback;
-            generationNumber = atomicGenerationNumber.incrementAndGet();
-        }
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            final int currentGenerationNumber = atomicGenerationNumber.get();
-
-            if (DBG) {
-                Log.d(tag, "receiver generationNumber=" + generationNumber +
-                        ", current generationNumber=" + currentGenerationNumber);
-            }
-            if (generationNumber != currentGenerationNumber) return;
-
-            callback.accept(intent);
-        }
-    }
-}
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java b/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java
index 2cebbeb..223a98b 100644
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java
@@ -29,6 +29,9 @@
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
 
+import java.util.Map;
+import java.util.Set;
+
 @Implements(PerformUnifiedRestoreTask.class)
 public class ShadowPerformUnifiedRestoreTask {
     @Nullable private static ShadowPerformUnifiedRestoreTask sLastShadow;
@@ -64,7 +67,8 @@
             int pmToken,
             boolean isFullSystemRestore,
             @Nullable String[] filterSet,
-            OnTaskFinishedListener listener) {
+            OnTaskFinishedListener listener,
+            Map<String, Set<String>> excludedKeys) {
         mBackupManagerService = backupManagerService;
         mPackage = targetPackage;
         mIsFullSystemRestore = isFullSystemRestore;
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 6c09239..8e6114a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -1053,6 +1053,35 @@
 
     @SuppressWarnings("GuardedBy")
     @Test
+    public void testUpdateOomAdj_DoOne_Service_Chain_BoundByFgService_Cycle_2() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        bindService(app, client, null, 0, mock(IBinder.class));
+        bindService(client, app, null, 0, mock(IBinder.class));
+        ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+                MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+        bindService(client2, client, null, 0, mock(IBinder.class));
+        client.setHasForegroundServices(true, 0);
+        ArrayList<ProcessRecord> lru = sService.mProcessList.mLruProcesses;
+        lru.clear();
+        lru.add(app);
+        lru.add(client);
+        lru.add(client2);
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, true, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(client, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+        assertProcStates(client2, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+                SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
     public void testUpdateOomAdj_DoOne_Service_Chain_BoundByFgService_Cycle_Branch() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 9e255fe..3518dc5 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -53,9 +53,12 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class LocalDisplayAdapterTest {
-    private static final long HANDLER_WAIT_MS = 100;
+    private static final Long DISPLAY_MODEL = Long.valueOf(0xAAAAAAAAL);
+    private static final int PORT_A = 0;
+    private static final int PORT_B = 0x80;
+    private static final int PORT_C = 0xFF;
 
-    private static final int PHYSICAL_DISPLAY_ID_MODEL_SHIFT = 8;
+    private static final long HANDLER_WAIT_MS = 100;
 
     private StaticMockitoSession mMockitoSession;
 
@@ -74,7 +77,7 @@
 
     private TestListener mListener = new TestListener();
 
-    private LinkedList<Long> mDisplayIds = new LinkedList<>();
+    private LinkedList<DisplayAddress.Physical> mAddresses = new LinkedList<>();
 
     @Before
     public void setUp() throws Exception {
@@ -106,30 +109,22 @@
      */
     @Test
     public void testPrivateDisplay() throws Exception {
-        // needs default one always
-        final long displayId0 = 0;
-        setUpDisplay(new DisplayConfig(displayId0, createDummyDisplayInfo()));
-        final long displayId1 = 1;
-        setUpDisplay(new DisplayConfig(displayId1, createDummyDisplayInfo()));
-        final long displayId2 = 2;
-        setUpDisplay(new DisplayConfig(displayId2, createDummyDisplayInfo()));
+        setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_A), createDummyDisplayInfo()));
+        setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_B), createDummyDisplayInfo()));
+        setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_C), createDummyDisplayInfo()));
         updateAvailableDisplays();
-        // display 1 should be marked as private while display 2 is not.
-        doReturn(new int[]{(int) displayId1}).when(mMockedResources)
+        doReturn(new int[]{ PORT_B }).when(mMockedResources)
                 .getIntArray(com.android.internal.R.array.config_localPrivateDisplayPorts);
         mAdapter.registerLocked();
 
         waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
 
         // This should be public
-        assertDisplay(mListener.addedDisplays.get(0).getDisplayDeviceInfoLocked(), displayId0,
-                false);
+        assertDisplay(mListener.addedDisplays.get(0).getDisplayDeviceInfoLocked(), PORT_A, false);
         // This should be private
-        assertDisplay(mListener.addedDisplays.get(1).getDisplayDeviceInfoLocked(), displayId1,
-                true);
+        assertDisplay(mListener.addedDisplays.get(1).getDisplayDeviceInfoLocked(), PORT_B, true);
         // This should be public
-        assertDisplay(mListener.addedDisplays.get(2).getDisplayDeviceInfoLocked(), displayId2,
-                false);
+        assertDisplay(mListener.addedDisplays.get(2).getDisplayDeviceInfoLocked(), PORT_C, false);
     }
 
     /**
@@ -137,11 +132,8 @@
      */
     @Test
     public void testPublicDisplaysForNoConfigLocalPrivateDisplayPorts() throws Exception {
-        // needs default one always
-        final long displayId0 = 0;
-        setUpDisplay(new DisplayConfig(displayId0, createDummyDisplayInfo()));
-        final long displayId1 = 1;
-        setUpDisplay(new DisplayConfig(displayId1, createDummyDisplayInfo()));
+        setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_A), createDummyDisplayInfo()));
+        setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_C), createDummyDisplayInfo()));
         updateAvailableDisplays();
         // config_localPrivateDisplayPorts is null
         mAdapter.registerLocked();
@@ -149,35 +141,36 @@
         waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
 
         // This should be public
-        assertDisplay(mListener.addedDisplays.get(0).getDisplayDeviceInfoLocked(), displayId0,
-                false);
+        assertDisplay(mListener.addedDisplays.get(0).getDisplayDeviceInfoLocked(), PORT_A, false);
         // This should be public
-        assertDisplay(mListener.addedDisplays.get(1).getDisplayDeviceInfoLocked(), displayId1,
-                false);
+        assertDisplay(mListener.addedDisplays.get(1).getDisplayDeviceInfoLocked(), PORT_C, false);
     }
 
-    private void assertDisplay(DisplayDeviceInfo info, long expectedPort, boolean shouldBePrivate) {
-        DisplayAddress.Physical physical = (DisplayAddress.Physical) info.address;
-        assertNotNull(physical);
-        assertEquals(expectedPort, physical.getPort());
+    private static void assertDisplay(
+            DisplayDeviceInfo info, int expectedPort, boolean shouldBePrivate) {
+        final DisplayAddress.Physical address = (DisplayAddress.Physical) info.address;
+        assertNotNull(address);
+        assertEquals((byte) expectedPort, address.getPort());
+        assertEquals(DISPLAY_MODEL, address.getModel());
         assertEquals(shouldBePrivate, (info.flags & DisplayDeviceInfo.FLAG_PRIVATE) != 0);
     }
 
     private class DisplayConfig {
-        public final long displayId;
+        public final DisplayAddress.Physical address;
         public final IBinder displayToken = new Binder();
         public final SurfaceControl.PhysicalDisplayInfo displayInfo;
 
-        private DisplayConfig(long displayId, SurfaceControl.PhysicalDisplayInfo displayInfo) {
-            this.displayId = displayId | (0x1 << PHYSICAL_DISPLAY_ID_MODEL_SHIFT);
+        private DisplayConfig(
+                DisplayAddress.Physical address, SurfaceControl.PhysicalDisplayInfo displayInfo) {
+            this.address = address;
             this.displayInfo = displayInfo;
         }
     }
 
     private void setUpDisplay(DisplayConfig config) {
-        mDisplayIds.add(config.displayId);
-        doReturn(config.displayToken).when(
-                () -> SurfaceControl.getPhysicalDisplayToken(config.displayId));
+        mAddresses.add(config.address);
+        doReturn(config.displayToken).when(() ->
+                SurfaceControl.getPhysicalDisplayToken(config.address.getPhysicalDisplayId()));
         doReturn(new SurfaceControl.PhysicalDisplayInfo[]{
                 config.displayInfo
         }).when(() -> SurfaceControl.getDisplayConfigs(config.displayToken));
@@ -192,16 +185,20 @@
     }
 
     private void updateAvailableDisplays() {
-        long[] ids = new long[mDisplayIds.size()];
+        long[] ids = new long[mAddresses.size()];
         int i = 0;
-        for (long id : mDisplayIds) {
-            ids[i] = id;
+        for (DisplayAddress.Physical address : mAddresses) {
+            ids[i] = address.getPhysicalDisplayId();
             i++;
         }
         doReturn(ids).when(() -> SurfaceControl.getPhysicalDisplayIds());
     }
 
-    private SurfaceControl.PhysicalDisplayInfo createDummyDisplayInfo() {
+    private static DisplayAddress.Physical createDisplayAddress(int port) {
+        return DisplayAddress.fromPortAndModel((byte) port, DISPLAY_MODEL);
+    }
+
+    private static SurfaceControl.PhysicalDisplayInfo createDummyDisplayInfo() {
         SurfaceControl.PhysicalDisplayInfo info = new SurfaceControl.PhysicalDisplayInfo();
         info.density = 100;
         info.xDpi = 100;
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 0be5fe0..cf7919b 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -41,6 +41,7 @@
         "hamcrest-library",
         "servicestests-utils",
         "xml-writer-device-lib",
+        "service-appsearch",
         "service-jobscheduler",
     ],
 
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index c1bbb30..3a07a69 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -34,12 +34,13 @@
     <uses-permission android:name="android.permission.REORDER_TASKS" />
     <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
     <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
-    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+    <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.MANAGE_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
     <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
     <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
+    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
     <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java
index 37f5b87..3352177 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java
@@ -16,18 +16,39 @@
 
 package com.android.server.accessibility;
 
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 import android.accessibilityservice.AccessibilityService;
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+import android.app.RemoteAction;
 import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.drawable.Icon;
 import android.os.Handler;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+
+import androidx.test.InstrumentationRegistry;
 
 import com.android.internal.util.ScreenshotHelper;
+import com.android.server.LocalServices;
+import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 
 import org.junit.Before;
@@ -35,55 +56,290 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 /**
  * Tests for SystemActionPerformer
  */
 public class SystemActionPerformerTest {
-    SystemActionPerformer mSystemActionPerformer;
+    private static final int LATCH_TIMEOUT_MS = 500;
+    private static final int LEGACY_SYSTEM_ACTION_COUNT = 9;
+    private static final int NEW_ACTION_ID = 20;
+    private static final String LABEL_1 = "label1";
+    private static final String LABEL_2 = "label2";
+    private static final String INTENT_ACTION1 = "TESTACTION1";
+    private static final String INTENT_ACTION2 = "TESTACTION2";
+    private static final String DESCRIPTION1 = "description1";
+    private static final String DESCRIPTION2 = "description2";
+    private static final PendingIntent TEST_PENDING_INTENT_1 = PendingIntent.getBroadcast(
+            InstrumentationRegistry.getTargetContext(), 0, new Intent(INTENT_ACTION1), 0);
+    private static final RemoteAction NEW_TEST_ACTION_1 = new RemoteAction(
+            Icon.createWithContentUri("content://test"),
+            LABEL_1,
+            DESCRIPTION1,
+            TEST_PENDING_INTENT_1);
+    private static final PendingIntent TEST_PENDING_INTENT_2 = PendingIntent.getBroadcast(
+            InstrumentationRegistry.getTargetContext(), 0, new Intent(INTENT_ACTION2), 0);
+    private static final RemoteAction NEW_TEST_ACTION_2 = new RemoteAction(
+            Icon.createWithContentUri("content://test"),
+            LABEL_2,
+            DESCRIPTION2,
+            TEST_PENDING_INTENT_2);
 
-    @Mock Context mMockContext;
-    @Mock WindowManagerInternal mMockWindowManagerInternal;
-    @Mock StatusBarManager mMockStatusBarManager;
-    @Mock ScreenshotHelper mMockScreenshotHelper;
+    private static final AccessibilityAction NEW_ACCESSIBILITY_ACTION =
+            new AccessibilityAction(NEW_ACTION_ID, LABEL_1);
+    private static final AccessibilityAction LEGACY_NOTIFICATIONS_ACCESSIBILITY_ACTION =
+            new AccessibilityAction(AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS, LABEL_1);
+    private static final AccessibilityAction LEGACY_HOME_ACCESSIBILITY_ACTION =
+            new AccessibilityAction(AccessibilityService.GLOBAL_ACTION_HOME, LABEL_2);
+
+    private SystemActionPerformer mSystemActionPerformer;
+
+    @Mock private Context mMockContext;
+    @Mock private StatusBarManagerInternal mMockStatusBarManagerInternal;
+    @Mock private WindowManagerInternal mMockWindowManagerInternal;
+    @Mock private StatusBarManager mMockStatusBarManager;
+    @Mock private ScreenshotHelper mMockScreenshotHelper;
+    @Mock private SystemActionPerformer.SystemActionsChangedListener mMockListener;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
+        LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
+        LocalServices.addService(StatusBarManagerInternal.class, mMockStatusBarManagerInternal);
+    }
 
-        when(mMockContext.getSystemService(android.app.Service.STATUS_BAR_SERVICE))
-                .thenReturn(mMockStatusBarManager);
+    private void setupWithMockContext() {
+        doReturn(mMockStatusBarManager).when(
+                mMockContext).getSystemService(android.app.Service.STATUS_BAR_SERVICE);
+        doReturn(InstrumentationRegistry.getContext().getResources()).when(
+                mMockContext).getResources();
+        mSystemActionPerformer = new SystemActionPerformer(
+                mMockContext,
+                mMockWindowManagerInternal,
+                () -> mMockScreenshotHelper,
+                mMockListener);
+    }
 
-        mSystemActionPerformer =
-                new SystemActionPerformer(mMockContext, mMockWindowManagerInternal,
-                        () -> mMockScreenshotHelper);
+    private void setupWithRealContext() {
+        mSystemActionPerformer = new SystemActionPerformer(
+                InstrumentationRegistry.getContext(),
+                mMockWindowManagerInternal,
+                () -> mMockScreenshotHelper,
+                mMockListener);
+    }
+
+    // We need below two help functions because AccessbilityAction.equals function only compares
+    // action ids. To verify the test result here, we are also looking at action labels.
+    private void assertHasLegacyAccessibilityAction(
+            List<AccessibilityAction> actions, AccessibilityAction action) {
+        boolean foundAction = false;
+        for (AccessibilityAction a : actions) {
+            if ((a.getId() == action.getId()) && (a.getLabel().equals(action.getLabel()))) {
+                foundAction = true;
+                break;
+            }
+        }
+        assertTrue(foundAction);
+    }
+
+    private void assertHasNoLegacyAccessibilityAction(
+            List<AccessibilityAction> actions, AccessibilityAction action) {
+        boolean foundAction = false;
+        for (AccessibilityAction a : actions) {
+            if ((a.getId() == action.getId()) && (a.getLabel().equals(action.getLabel()))) {
+                foundAction = true;
+                break;
+            }
+        }
+        assertFalse(foundAction);
     }
 
     @Test
-    public void testNotifications_expandsNotificationPanel() {
+    public void testRegisterSystemAction_addedIntoAvailableSystemActions() {
+        setupWithRealContext();
+        // Before any new system action is registered, getSystemActions returns all legacy actions
+        List<AccessibilityAction> actions = mSystemActionPerformer.getSystemActions();
+        assertEquals(LEGACY_SYSTEM_ACTION_COUNT, actions.size());
+        // Register a new system action
+        mSystemActionPerformer.registerSystemAction(NEW_ACTION_ID, NEW_TEST_ACTION_1);
+        actions = mSystemActionPerformer.getSystemActions();
+        assertEquals(LEGACY_SYSTEM_ACTION_COUNT + 1, actions.size());
+        assertThat(actions, hasItem(NEW_ACCESSIBILITY_ACTION));
+    }
+
+    @Test
+    public void testRegisterSystemAction_overrideLegacyAction() {
+        setupWithRealContext();
+        // Before any new system action is registered, getSystemActions returns all legacy actions
+        List<AccessibilityAction> actions = mSystemActionPerformer.getSystemActions();
+        assertEquals(LEGACY_SYSTEM_ACTION_COUNT, actions.size());
+        // Overriding a legacy system action using legacy notification action id
+        mSystemActionPerformer.registerSystemAction(
+                AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS, NEW_TEST_ACTION_1);
+        actions = mSystemActionPerformer.getSystemActions();
+        assertEquals(LEGACY_SYSTEM_ACTION_COUNT, actions.size());
+        assertHasLegacyAccessibilityAction(actions, LEGACY_NOTIFICATIONS_ACCESSIBILITY_ACTION);
+    }
+
+    @Test
+    public void testUnregisterSystemAction_removeFromAvailableSystemActions() {
+        setupWithRealContext();
+        // Before any new system action is registered, getSystemActions returns all legacy actions
+        List<AccessibilityAction> actions = mSystemActionPerformer.getSystemActions();
+        assertEquals(LEGACY_SYSTEM_ACTION_COUNT, actions.size());
+        // Register a new system action
+        mSystemActionPerformer.registerSystemAction(NEW_ACTION_ID, NEW_TEST_ACTION_1);
+        actions = mSystemActionPerformer.getSystemActions();
+        assertEquals(LEGACY_SYSTEM_ACTION_COUNT + 1, actions.size());
+
+        mSystemActionPerformer.unregisterSystemAction(NEW_ACTION_ID);
+        actions = mSystemActionPerformer.getSystemActions();
+        assertEquals(LEGACY_SYSTEM_ACTION_COUNT, actions.size());
+        assertThat(actions, is(not(hasItem(NEW_ACCESSIBILITY_ACTION))));
+    }
+
+    @Test
+    public void testUnregisterSystemAction_removeOverrideForLegacyAction() {
+        setupWithRealContext();
+
+        // Overriding a legacy system action
+        mSystemActionPerformer.registerSystemAction(
+                AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS, NEW_TEST_ACTION_1);
+        List<AccessibilityAction> actions = mSystemActionPerformer.getSystemActions();
+        assertEquals(LEGACY_SYSTEM_ACTION_COUNT, actions.size());
+        assertHasLegacyAccessibilityAction(actions, LEGACY_NOTIFICATIONS_ACCESSIBILITY_ACTION);
+
+        // Remove the overriding action using legacy action id
+        mSystemActionPerformer.unregisterSystemAction(
+                AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS);
+        actions = mSystemActionPerformer.getSystemActions();
+        assertEquals(LEGACY_SYSTEM_ACTION_COUNT, actions.size());
+        assertHasNoLegacyAccessibilityAction(actions, LEGACY_NOTIFICATIONS_ACCESSIBILITY_ACTION);
+    }
+
+    @Test
+    public void testPerformSystemActionNewAction() throws CanceledException {
+        setupWithRealContext();
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        mSystemActionPerformer.registerSystemAction(NEW_ACTION_ID, NEW_TEST_ACTION_1);
+        TestBroadcastReceiver br = new TestBroadcastReceiver(latch);
+        br.register(InstrumentationRegistry.getTargetContext());
+        mSystemActionPerformer.performSystemAction(NEW_ACTION_ID);
+        try {
+            latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            fail("RemoteAction should be triggered.");
+        } finally {
+            br.unregister(InstrumentationRegistry.getTargetContext());
+        }
+    }
+
+    @Test
+    public void testPerformSystemActionOverrideLegacyActionUsingLegacyActionId()
+            throws CanceledException {
+        setupWithRealContext();
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        mSystemActionPerformer.registerSystemAction(
+                AccessibilityService.GLOBAL_ACTION_RECENTS, NEW_TEST_ACTION_1);
+        TestBroadcastReceiver br = new TestBroadcastReceiver(latch);
+        br.register(InstrumentationRegistry.getTargetContext());
+        mSystemActionPerformer.performSystemAction(AccessibilityService.GLOBAL_ACTION_RECENTS);
+        try {
+            latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            fail("RemoteAction should be triggered.");
+        } finally {
+            br.unregister(InstrumentationRegistry.getTargetContext());
+        }
+        verify(mMockStatusBarManagerInternal, never()).toggleRecentApps();
+        // Now revert to legacy action
+        mSystemActionPerformer.unregisterSystemAction(AccessibilityService.GLOBAL_ACTION_RECENTS);
+        mSystemActionPerformer.performSystemAction(AccessibilityService.GLOBAL_ACTION_RECENTS);
+        verify(mMockStatusBarManagerInternal).toggleRecentApps();
+    }
+
+    @Test
+    public void testNotifications_expandsNotificationPanel_legacy() {
+        setupWithMockContext();
         mSystemActionPerformer
                 .performSystemAction(AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS);
         verify(mMockStatusBarManager).expandNotificationsPanel();
     }
 
     @Test
-    public void testQuickSettings_requestsQuickSettingsPanel() {
+    public void testQuickSettings_requestsQuickSettingsPanel_legacy() {
+        setupWithMockContext();
         mSystemActionPerformer
                 .performSystemAction(AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS);
         verify(mMockStatusBarManager).expandSettingsPanel();
     }
 
     @Test
-    public void testPowerDialog_requestsFromWindowManager() {
+    public void testRecentApps_legacy() {
+        setupWithRealContext();
+        mSystemActionPerformer.performSystemAction(AccessibilityService.GLOBAL_ACTION_RECENTS);
+        verify(mMockStatusBarManagerInternal).toggleRecentApps();
+    }
+
+    @Test
+    public void testPowerDialog_requestsFromWindowManager_legacy() {
+        setupWithMockContext();
         mSystemActionPerformer.performSystemAction(AccessibilityService.GLOBAL_ACTION_POWER_DIALOG);
         verify(mMockWindowManagerInternal).showGlobalActions();
     }
 
     @Test
-    public void testScreenshot_requestsFromScreenshotHelper() {
+    public void testToggleSplitScreen_legacy() {
+        setupWithRealContext();
+        mSystemActionPerformer.performSystemAction(
+                AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN);
+        verify(mMockStatusBarManagerInternal).toggleSplitScreen();
+    }
+
+    @Test
+    public void testScreenshot_requestsFromScreenshotHelper_legacy() {
+        setupWithMockContext();
         mSystemActionPerformer.performSystemAction(
                 AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT);
         verify(mMockScreenshotHelper).takeScreenshot(
                 eq(android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN), anyBoolean(),
                 anyBoolean(), any(Handler.class), any());
     }
+
+    // PendingIntent is a final class and cannot be mocked. So we are using this
+    // Broadcast receiver to verify the registered remote action is called correctly.
+    private static final class TestBroadcastReceiver extends BroadcastReceiver {
+        private CountDownLatch mLatch;
+        private boolean mRegistered;
+        private final IntentFilter mFilter;
+
+        TestBroadcastReceiver(CountDownLatch latch) {
+            mLatch = latch;
+            mRegistered = false;
+            mFilter = new IntentFilter(INTENT_ACTION1);
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            mLatch.countDown();
+        }
+
+        void register(Context context) {
+            if (!mRegistered) {
+                context.registerReceiver(this, mFilter);
+                mRegistered = true;
+            }
+        }
+
+        void unregister(Context context) {
+            if (mRegistered) {
+                context.unregisterReceiver(this);
+            }
+        }
+    }
 }
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
new file mode 100644
index 0000000..6f2de7f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java
@@ -0,0 +1,125 @@
+/*
+ * 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 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);
+        for (SearchResultProto.ResultProto result : results.getResultsList()) {
+            uris.add(result.getDocument().getUri());
+        }
+        return uris;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/backup/DataChangedJournalTest.java b/services/tests/servicestests/src/com/android/server/backup/DataChangedJournalTest.java
index f588c4f..4e7fe44 100644
--- a/services/tests/servicestests/src/com/android/server/backup/DataChangedJournalTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/DataChangedJournalTest.java
@@ -18,6 +18,9 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertEquals;
+
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
@@ -50,6 +53,7 @@
     @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
 
     @Mock private Consumer<String> mConsumer;
+    @Mock private File invalidFile;
 
     private File mFile;
     private DataChangedJournal mJournal;
@@ -131,4 +135,10 @@
     public void toString_isSameAsFileToString() throws Exception {
         assertThat(mJournal.toString()).isEqualTo(mFile.toString());
     }
+
+    public void listJournals_invalidJournalFile_returnsEmptyList() throws Exception {
+        when(invalidFile.listFiles()).thenReturn(null);
+
+        assertEquals(0, DataChangedJournal.listJournals(invalidFile).size());
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/backup/UserBackupPreferencesTest.java b/services/tests/servicestests/src/com/android/server/backup/UserBackupPreferencesTest.java
new file mode 100644
index 0000000..d6efe35
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/backup/UserBackupPreferencesTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.backup;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class UserBackupPreferencesTest {
+    private static final String EXCLUDED_PACKAGE_1 = "package1";
+    private static final String EXCLUDED_PACKAGE_2 = "package2";
+    private static final List<String> EXCLUDED_KEYS_1 = Arrays.asList("key1", "key2");
+    private static final List<String> EXCLUDED_KEYS_2 = Arrays.asList("key1");
+
+    @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+
+    private UserBackupPreferences mExcludedRestoreKeysStorage;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mExcludedRestoreKeysStorage =
+                new UserBackupPreferences(
+                        InstrumentationRegistry.getContext(), mTemporaryFolder.newFolder());
+    }
+
+    @Test
+    public void testGetExcludedKeysForPackages_returnsExcludedKeys() {
+        mExcludedRestoreKeysStorage.addExcludedKeys(EXCLUDED_PACKAGE_1, EXCLUDED_KEYS_1);
+        mExcludedRestoreKeysStorage.addExcludedKeys(EXCLUDED_PACKAGE_2, EXCLUDED_KEYS_2);
+
+        Map<String, Set<String>> excludedKeys =
+                mExcludedRestoreKeysStorage.getExcludedRestoreKeysForPackages(EXCLUDED_PACKAGE_1);
+        assertTrue(excludedKeys.containsKey(EXCLUDED_PACKAGE_1));
+        assertFalse(excludedKeys.containsKey(EXCLUDED_PACKAGE_2));
+        assertEquals(new HashSet<>(EXCLUDED_KEYS_1), excludedKeys.get(EXCLUDED_PACKAGE_1));
+    }
+
+    @Test
+    public void testGetExcludedKeysForPackages_withEmpty_list_returnsAllExcludedKeys() {
+        mExcludedRestoreKeysStorage.addExcludedKeys(EXCLUDED_PACKAGE_1, EXCLUDED_KEYS_1);
+        mExcludedRestoreKeysStorage.addExcludedKeys(EXCLUDED_PACKAGE_2, EXCLUDED_KEYS_2);
+
+        Map<String, Set<String>> excludedKeys =
+                mExcludedRestoreKeysStorage.getAllExcludedRestoreKeys();
+        assertTrue(excludedKeys.containsKey(EXCLUDED_PACKAGE_1));
+        assertTrue(excludedKeys.containsKey(EXCLUDED_PACKAGE_2));
+        assertEquals(new HashSet<>(EXCLUDED_KEYS_1), excludedKeys.get(EXCLUDED_PACKAGE_1));
+        assertEquals(new HashSet<>(EXCLUDED_KEYS_2), excludedKeys.get(EXCLUDED_PACKAGE_2));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java b/services/tests/servicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java
new file mode 100644
index 0000000..6359edf
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.backup.restore;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import android.app.backup.BackupDataInput;
+import android.app.backup.BackupDataOutput;
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayDeque;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class PerformUnifiedRestoreTaskTest {
+    private static final String PACKAGE_NAME = "package";
+    private static final String INCLUDED_KEY = "included_key";
+    private static final String EXCLUDED_KEY_1 = "excluded_key_1";
+    private static final String EXCLUDED_KEY_2 = "excluded_key_2";
+
+    @Mock private BackupDataInput mBackupDataInput;
+    @Mock private BackupDataOutput mBackupDataOutput;
+
+    private Set<String> mExcludedkeys = new HashSet<>();
+    private Map<String, String> mBackupData = new HashMap<>();
+    // Mock BackupDataInput reads backup data from here.
+    private Queue<String> mBackupDataSource;
+    // Mock BackupDataOutput will write backup data here.
+    private Set<String> mBackupDataDump;
+    private PerformUnifiedRestoreTask mRestoreTask;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        populateTestData();
+
+        mBackupDataSource = new ArrayDeque<>(mBackupData.keySet());
+        when(mBackupDataInput.readNextHeader()).then(new Answer<Boolean>() {
+            @Override
+            public Boolean answer(InvocationOnMock invocation) throws Throwable {
+                return !mBackupDataSource.isEmpty();
+            }
+        });
+        when(mBackupDataInput.getKey()).then(new Answer<String>() {
+            @Override
+            public String answer(InvocationOnMock invocation) throws Throwable {
+                return mBackupDataSource.poll();
+            }
+        });
+        when(mBackupDataInput.getDataSize()).thenReturn(0);
+
+        mBackupDataDump = new HashSet<>();
+        ArgumentCaptor<String> keyCaptor = ArgumentCaptor.forClass(String.class);
+        when(mBackupDataOutput.writeEntityHeader(keyCaptor.capture(), anyInt())).then(
+                new Answer<Void>() {
+                    @Override
+                    public Void answer(InvocationOnMock invocation) throws Throwable {
+                        mBackupDataDump.add(keyCaptor.getValue());
+                        return null;
+                    }
+                });
+
+        mRestoreTask = new PerformUnifiedRestoreTask(Collections.singletonMap(
+                PACKAGE_NAME, mExcludedkeys));
+    }
+
+    private void populateTestData() {
+        mBackupData = new HashMap<>();
+        mBackupData.put(INCLUDED_KEY, "1");
+        mBackupData.put(EXCLUDED_KEY_1, "2");
+        mBackupData.put(EXCLUDED_KEY_2, "3");
+
+        mExcludedkeys = new HashSet<>();
+        mExcludedkeys.add(EXCLUDED_KEY_1);
+        mExcludedkeys.add(EXCLUDED_KEY_2);
+    }
+
+    @Test
+    public void testFilterExcludedKeys() throws Exception {
+        mRestoreTask.filterExcludedKeys(PACKAGE_NAME, mBackupDataInput, mBackupDataOutput);
+
+        // Verify only the correct were written into BackupDataOutput object.
+        Set<String> allowedBackupKeys = new HashSet<>(mBackupData.keySet());
+        allowedBackupKeys.removeAll(mExcludedkeys);
+        assertEquals(allowedBackupKeys, mBackupDataDump);
+    }
+}
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 f8c87fc..7267976 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -73,36 +73,36 @@
     @Test
     public void testDisabledChangeDisabled() {
         CompatConfig pc = new CompatConfig();
-        pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true));
+        pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true, ""));
         assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isFalse();
     }
 
     @Test
     public void testTargetSdkChangeDisabled() {
         CompatConfig pc = new CompatConfig();
-        pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, false));
+        pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, false, null));
         assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse();
     }
 
     @Test
     public void testTargetSdkChangeEnabled() {
         CompatConfig pc = new CompatConfig();
-        pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, false));
+        pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, false, ""));
         assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isTrue();
     }
 
     @Test
     public void testDisabledOverrideTargetSdkChange() {
         CompatConfig pc = new CompatConfig();
-        pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, true));
+        pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, true, null));
         assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isFalse();
     }
 
     @Test
     public void testGetDisabledChanges() {
         CompatConfig pc = new CompatConfig();
-        pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true));
-        pc.addChange(new CompatChange(2345L, "OTHER_CHANGE", -1, false));
+        pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true, null));
+        pc.addChange(new CompatChange(2345L, "OTHER_CHANGE", -1, false, null));
         assertThat(pc.getDisabledChanges(
                 makeAppInfo("com.some.package", 2))).asList().containsExactly(1234L);
     }
@@ -110,9 +110,9 @@
     @Test
     public void testGetDisabledChangesSorted() {
         CompatConfig pc = new CompatConfig();
-        pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, true));
-        pc.addChange(new CompatChange(123L, "OTHER_CHANGE", 2, true));
-        pc.addChange(new CompatChange(12L, "THIRD_CHANGE", 2, true));
+        pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, true, null));
+        pc.addChange(new CompatChange(123L, "OTHER_CHANGE", 2, true, null));
+        pc.addChange(new CompatChange(12L, "THIRD_CHANGE", 2, true, null));
         assertThat(pc.getDisabledChanges(
                 makeAppInfo("com.some.package", 2))).asList().containsExactly(12L, 123L, 1234L);
     }
@@ -120,7 +120,7 @@
     @Test
     public void testPackageOverrideEnabled() {
         CompatConfig pc = new CompatConfig();
-        pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true)); // disabled
+        pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true, null)); // disabled
         pc.addOverride(1234L, "com.some.package", true);
         assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isTrue();
         assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isFalse();
@@ -129,7 +129,7 @@
     @Test
     public void testPackageOverrideDisabled() {
         CompatConfig pc = new CompatConfig();
-        pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false));
+        pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false, null));
         pc.addOverride(1234L, "com.some.package", false);
         assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse();
         assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isTrue();
@@ -152,7 +152,7 @@
     @Test
     public void testRemovePackageOverride() {
         CompatConfig pc = new CompatConfig();
-        pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false));
+        pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false, null));
         pc.addOverride(1234L, "com.some.package", false);
         pc.removeOverride(1234L, "com.some.package");
         assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isTrue();
@@ -161,8 +161,8 @@
     @Test
     public void testLookupChangeId() {
         CompatConfig pc = new CompatConfig();
-        pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false));
-        pc.addChange(new CompatChange(2345L, "ANOTHER_CHANGE", -1, false));
+        pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false, null));
+        pc.addChange(new CompatChange(2345L, "ANOTHER_CHANGE", -1, false, null));
         assertThat(pc.lookupChangeId("MY_CHANGE")).isEqualTo(1234L);
     }
 
@@ -174,8 +174,9 @@
 
     @Test
     public void testReadConfig() {
-        Change[] changes = {new Change(1234L, "MY_CHANGE1", false, 2), new Change(1235L,
-                "MY_CHANGE2", true, null), new Change(1236L, "MY_CHANGE3", false, null)};
+        Change[] changes = {new Change(1234L, "MY_CHANGE1", false, 2, null), new Change(1235L,
+                "MY_CHANGE2", true, null, "description"), new Change(1236L, "MY_CHANGE3", false,
+                null, "")};
 
         File dir = createTempDir();
         writeChangesToFile(changes, new File(dir.getPath() + "/platform_compat_config.xml"));
@@ -191,9 +192,9 @@
 
     @Test
     public void testReadConfigMultipleFiles() {
-        Change[] changes1 = {new Change(1234L, "MY_CHANGE1", false, 2)};
-        Change[] changes2 = {new Change(1235L, "MY_CHANGE2", true, null), new Change(1236L,
-                "MY_CHANGE3", false, null)};
+        Change[] changes1 = {new Change(1234L, "MY_CHANGE1", false, 2, null)};
+        Change[] changes2 = {new Change(1235L, "MY_CHANGE2", true, null, ""), new Change(1236L,
+                "MY_CHANGE3", false, null, null)};
 
         File dir = createTempDir();
         writeChangesToFile(changes1,
diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
new file mode 100644
index 0000000..c406876
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
@@ -0,0 +1,272 @@
+/*
+ * 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.compat;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.internal.verification.VerificationModeFactory.times;
+import static org.testng.Assert.assertThrows;
+
+import android.compat.Compatibility;
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+import com.android.internal.compat.CompatibilityChangeConfig;
+
+import com.google.common.collect.ImmutableSet;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class PlatformCompatTest {
+    private static final String PACKAGE_NAME = "my.package";
+
+    @Mock
+    private Context mContext;
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    CompatChange.ChangeListener mListener1, mListener2;
+
+
+    @Before
+    public void setUp() throws Exception {
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        when(mPackageManager.getPackageUid(eq(PACKAGE_NAME), eq(0))).thenThrow(
+                new PackageManager.NameNotFoundException());
+        CompatConfig.get().clearChanges();
+    }
+
+    @Test
+    public void testRegisterListenerToSameIdThrows() {
+        PlatformCompat pc = new PlatformCompat(mContext);
+
+        // Registering a listener to change 1 is successful.
+        pc.registerListener(1, mListener1);
+        // Registering a listener to change 2 is successful.
+        pc.registerListener(2, mListener1);
+        // Trying to register another listener to change id 1 fails.
+        assertThrows(IllegalStateException.class, () -> pc.registerListener(1, mListener1));
+    }
+
+    @Test
+    public void testRegisterListenerReturn() {
+        PlatformCompat pc = new PlatformCompat(mContext);
+
+        pc.setOverrides(
+                new CompatibilityChangeConfig(
+                        new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
+                PACKAGE_NAME);
+
+        // Change id 1 is known (added in setOverrides).
+        assertThat(pc.registerListener(1, mListener1)).isTrue();
+        // Change 2 is unknown.
+        assertThat(pc.registerListener(2, mListener1)).isFalse();
+    }
+
+    @Test
+    public void testListenerCalledOnSetOverrides() {
+        PlatformCompat pc = new PlatformCompat(mContext);
+
+        pc.registerListener(1, mListener1);
+        pc.registerListener(2, mListener1);
+
+        pc.setOverrides(
+                new CompatibilityChangeConfig(
+                        new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
+                PACKAGE_NAME);
+
+        verify(mListener1, times(2)).onCompatChange(PACKAGE_NAME);
+    }
+
+    @Test
+    public void testListenerNotCalledOnWrongPackage() {
+        PlatformCompat pc = new PlatformCompat(mContext);
+
+        pc.registerListener(1, mListener1);
+        pc.registerListener(2, mListener1);
+
+        pc.setOverridesForTest(
+                new CompatibilityChangeConfig(
+                        new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
+                PACKAGE_NAME);
+
+        verify(mListener1, never()).onCompatChange("other.package");
+    }
+
+    @Test
+    public void testListenerCalledOnSetOverridesTwoListeners() {
+        PlatformCompat pc = new PlatformCompat(mContext);
+        pc.registerListener(1, mListener1);
+
+        final ImmutableSet<Long> enabled = ImmutableSet.of(1L);
+        final ImmutableSet<Long> disabled = ImmutableSet.of(2L);
+
+        pc.setOverrides(
+                new CompatibilityChangeConfig(
+                        new Compatibility.ChangeConfig(enabled, disabled)),
+                PACKAGE_NAME);
+
+        verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
+        verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
+
+        reset(mListener1);
+        reset(mListener2);
+
+        pc.registerListener(2, mListener2);
+
+        pc.setOverrides(
+                new CompatibilityChangeConfig(
+                        new Compatibility.ChangeConfig(enabled, disabled)),
+                PACKAGE_NAME);
+
+        verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
+        verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);
+    }
+
+    @Test
+    public void testListenerCalledOnSetOverridesForTest() {
+        PlatformCompat pc = new PlatformCompat(mContext);
+
+        pc.registerListener(1, mListener1);
+        pc.registerListener(2, mListener1);
+
+        pc.setOverridesForTest(
+                new CompatibilityChangeConfig(
+                        new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
+                PACKAGE_NAME);
+
+        verify(mListener1, times(2)).onCompatChange(PACKAGE_NAME);
+    }
+
+    @Test
+    public void testListenerCalledOnSetOverridesTwoListenersForTest() {
+        PlatformCompat pc = new PlatformCompat(mContext);
+        pc.registerListener(1, mListener1);
+
+        final ImmutableSet<Long> enabled = ImmutableSet.of(1L);
+        final ImmutableSet<Long> disabled = ImmutableSet.of(2L);
+
+        pc.setOverridesForTest(
+                new CompatibilityChangeConfig(
+                        new Compatibility.ChangeConfig(enabled, disabled)),
+                PACKAGE_NAME);
+
+        verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
+        verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
+
+        reset(mListener1);
+        reset(mListener2);
+
+        pc.registerListener(2, mListener2);
+        pc.setOverridesForTest(
+                new CompatibilityChangeConfig(
+                        new Compatibility.ChangeConfig(enabled, disabled)),
+                PACKAGE_NAME);
+
+        verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
+        verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);
+    }
+
+    @Test
+    public void testListenerCalledOnClearOverrides() {
+        PlatformCompat pc = new PlatformCompat(mContext);
+
+        pc.registerListener(1, mListener1);
+        pc.registerListener(2, mListener2);
+
+        pc.setOverrides(
+                new CompatibilityChangeConfig(
+                        new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
+                PACKAGE_NAME);
+        verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
+        verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
+
+        reset(mListener1);
+        reset(mListener2);
+
+        pc.clearOverrides(PACKAGE_NAME);
+        verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
+        verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
+    }
+
+    @Test
+    public void testListenerCalledOnClearOverridesMultipleOverrides() {
+        PlatformCompat pc = new PlatformCompat(mContext);
+
+        pc.registerListener(1, mListener1);
+        pc.registerListener(2, mListener2);
+
+        pc.setOverrides(
+                new CompatibilityChangeConfig(
+                        new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
+                PACKAGE_NAME);
+        verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
+        verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);
+
+        reset(mListener1);
+        reset(mListener2);
+
+        pc.clearOverrides(PACKAGE_NAME);
+        verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
+        verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);
+    }
+
+    @Test
+    public void testListenerCalledOnClearOverrideExists() {
+        PlatformCompat pc = new PlatformCompat(mContext);
+
+        pc.registerListener(1, mListener1);
+        pc.registerListener(2, mListener2);
+
+        pc.setOverrides(
+                new CompatibilityChangeConfig(
+                        new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
+                PACKAGE_NAME);
+        verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
+        verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
+
+        reset(mListener1);
+        reset(mListener2);
+
+        pc.clearOverride(1, PACKAGE_NAME);
+        verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
+        verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
+    }
+
+    @Test
+    public void testListenerCalledOnClearOverrideDoesntExist() {
+        PlatformCompat pc = new PlatformCompat(mContext);
+
+        pc.registerListener(1, mListener1);
+
+        pc.clearOverride(1, PACKAGE_NAME);
+        // Listener not called when a non existing override is removed.
+        verify(mListener1, never()).onCompatChange(PACKAGE_NAME);
+    }
+
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
index c5fb0bd..5f1f308 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
@@ -23,7 +23,6 @@
 
 import android.app.admin.DevicePolicyManagerInternal;
 import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -39,6 +38,9 @@
 import java.util.Set;
 
 public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
+
+    private static final String USER_TYPE_EMPTY = "";
+
     private DpmMockContext mContext;
 
     @Override
@@ -52,9 +54,10 @@
     }
 
     public void testMigration() throws Exception {
-        final File user10dir = getServices().addUser(10, 0);
-        final File user11dir = getServices().addUser(11, UserInfo.FLAG_MANAGED_PROFILE);
-        getServices().addUser(12, 0);
+        final File user10dir = getServices().addUser(10, 0, USER_TYPE_EMPTY);
+        final File user11dir = getServices().addUser(11, 0,
+                UserManager.USER_TYPE_PROFILE_MANAGED);
+        getServices().addUser(12, 0, USER_TYPE_EMPTY);
 
         setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
         setUpPackageManagerForAdmin(admin2, UserHandle.getUid(10, 123));
@@ -273,7 +276,8 @@
     // Test setting default restrictions for managed profile.
     public void testMigration3_managedProfileOwner() throws Exception {
         // Create a managed profile user.
-        final File user10dir = getServices().addUser(10, UserInfo.FLAG_MANAGED_PROFILE);
+        final File user10dir = getServices().addUser(10, 0,
+                UserManager.USER_TYPE_PROFILE_MANAGED);
         // Profile owner package for managed profile user.
         setUpPackageManagerForAdmin(admin1, UserHandle.getUid(10, 123));
         // Set up fake UserManager to make it look like a managed profile.
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 64ea59d..ac555fd 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -22,6 +22,8 @@
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.backup.IBackupManager;
+import android.app.timedetector.TimeDetector;
+import android.app.timezonedetector.TimeZoneDetector;
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.Context;
 import android.content.Intent;
@@ -229,6 +231,16 @@
         AlarmManager getAlarmManager() {return services.alarmManager;}
 
         @Override
+        TimeDetector getTimeDetector() {
+            return services.timeDetector;
+        }
+
+        @Override
+        TimeZoneDetector getTimeZoneDetector() {
+            return services.timeZoneDetector;
+        }
+
+        @Override
         LockPatternUtils newLockPatternUtils() {
             return services.lockPatternUtils;
         }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index ed55aeb..43d8f92 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -26,9 +26,6 @@
 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
 import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
 import static android.app.admin.PasswordMetrics.computeForPassword;
-import static android.os.UserManagerInternal.CAMERA_DISABLED_GLOBALLY;
-import static android.os.UserManagerInternal.CAMERA_DISABLED_LOCALLY;
-import static android.os.UserManagerInternal.CAMERA_NOT_DISABLED;
 
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
 import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
@@ -66,6 +63,9 @@
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.app.admin.PasswordMetrics;
+import android.app.timedetector.ManualTimeSuggestion;
+import android.app.timezonedetector.ManualTimeZoneSuggestion;
+import android.app.timezonedetector.TimeZoneDetector;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -82,6 +82,7 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.UserManagerInternal;
 import android.platform.test.annotations.Presubmit;
 import android.provider.Settings;
 import android.security.KeyChain;
@@ -139,6 +140,8 @@
             permission.MANAGE_USERS, permission.INTERACT_ACROSS_USERS_FULL);
     public static final String NOT_DEVICE_OWNER_MSG = "does not own the device";
     public static final String NOT_PROFILE_OWNER_MSG = "does not own the profile";
+    public static final String NOT_ORG_OWNED_PROFILE_OWNER_MSG =
+            "not the profile owner on organization-owned device";
     public static final String ONGOING_CALL_MSG = "ongoing call on the device";
 
     // TODO replace all instances of this with explicit {@link #mServiceContext}.
@@ -148,6 +151,7 @@
     private DpmMockContext mServiceContext;
     private DpmMockContext mAdmin1Context;
     public DevicePolicyManager dpm;
+    public DevicePolicyManager parentDpm;
     public DevicePolicyManagerServiceTestable dpms;
 
     /*
@@ -237,6 +241,9 @@
 
         dpm = new DevicePolicyManagerTestable(mContext, dpms);
 
+        parentDpm = new DevicePolicyManagerTestable(mServiceContext, dpms,
+                /* parentInstance= */true);
+
         mContext.binder.restoreCallingIdentity(ident);
     }
 
@@ -266,7 +273,8 @@
                 anyString(), any(UserHandle.class));
 
         // Add the first secondary user.
-        getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0);
+        getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0,
+                UserManager.USER_TYPE_FULL_SECONDARY);
     }
 
     private void setAsProfileOwner(ComponentName admin) {
@@ -327,7 +335,7 @@
 
     public void testLoadAdminData_noAdmins() throws Exception {
         final int ANOTHER_USER_ID = 15;
-        getServices().addUser(ANOTHER_USER_ID, 0);
+        getServices().addUser(ANOTHER_USER_ID, 0, "");
 
         initializeDpms();
 
@@ -474,7 +482,7 @@
         final int ANOTHER_USER_ID = 100;
         final int ANOTHER_ADMIN_UID = UserHandle.getUid(ANOTHER_USER_ID, 20456);
 
-        getServices().addUser(ANOTHER_USER_ID, 0); // Add one more user.
+        getServices().addUser(ANOTHER_USER_ID, 0, ""); // Add one more user.
 
         // Set up pacakge manager for the other user.
         setUpPackageManagerForAdmin(admin2, ANOTHER_ADMIN_UID);
@@ -1154,9 +1162,8 @@
                 MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
 
         verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
-                eq(UserHandle.USER_SYSTEM),
-                eq(null),
-                eq(true), eq(CAMERA_NOT_DISABLED));
+                eq(UserHandle.USER_SYSTEM), eq(null),
+                eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
 
         verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                 null, UserHandle.USER_SYSTEM);
@@ -1341,7 +1348,7 @@
         final int ANOTHER_USER_ID = 100;
         final int ANOTHER_ADMIN_UID = UserHandle.getUid(ANOTHER_USER_ID, 456);
 
-        getServices().addUser(ANOTHER_USER_ID, 0); // Add one more user.
+        getServices().addUser(ANOTHER_USER_ID, 0, ""); // Add one more user.
 
         mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
         mContext.callerPermissions.add(permission.MANAGE_USERS);
@@ -1725,8 +1732,7 @@
         verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
                 MockUtils.checkUserRestrictions(defaultRestrictions),
-                eq(true) /* isDeviceOwner */,
-                eq(CAMERA_NOT_DISABLED)
+                eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER)
         );
         reset(getServices().userManagerInternal);
 
@@ -1741,7 +1747,7 @@
         verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER),
-                eq(true), eq(CAMERA_NOT_DISABLED));
+                eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
         reset(getServices().userManagerInternal);
 
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
@@ -1749,7 +1755,7 @@
                 eq(UserHandle.USER_SYSTEM),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS,
                         UserManager.DISALLOW_ADD_USER),
-                eq(true), eq(CAMERA_NOT_DISABLED));
+                eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
         reset(getServices().userManagerInternal);
 
         DpmTestUtils.assertRestrictions(
@@ -1767,7 +1773,7 @@
         verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
-                eq(true), eq(CAMERA_NOT_DISABLED));
+                eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
         reset(getServices().userManagerInternal);
 
         DpmTestUtils.assertRestrictions(
@@ -1783,7 +1789,7 @@
         verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
                 MockUtils.checkUserRestrictions(),
-                eq(true), eq(CAMERA_NOT_DISABLED));
+                eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
         reset(getServices().userManagerInternal);
 
         assertNoDeviceOwnerRestrictions();
@@ -1797,7 +1803,7 @@
                 eq(UserHandle.USER_SYSTEM),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
                         UserManager.DISALLOW_UNMUTE_MICROPHONE),
-                eq(true), eq(CAMERA_NOT_DISABLED));
+                eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
         reset(getServices().userManagerInternal);
 
         dpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME);
@@ -1809,7 +1815,7 @@
         verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER),
-                eq(true), eq(CAMERA_NOT_DISABLED));
+                eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
         reset(getServices().userManagerInternal);
 
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_FUN);
@@ -1817,16 +1823,16 @@
                 eq(UserHandle.USER_SYSTEM),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
                         UserManager.DISALLOW_ADD_USER),
-                eq(true), eq(CAMERA_NOT_DISABLED));
+                eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
         reset(getServices().userManagerInternal);
 
         dpm.setCameraDisabled(admin1, true);
         verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
-                // DISALLOW_CAMERA will be applied to both local and global.
+                // DISALLOW_CAMERA will be applied globally.
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
-                        UserManager.DISALLOW_ADD_USER),
-                eq(true), eq(CAMERA_DISABLED_GLOBALLY));
+                        UserManager.DISALLOW_ADD_USER, UserManager.DISALLOW_CAMERA),
+                eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
         reset(getServices().userManagerInternal);
     }
 
@@ -1872,7 +1878,7 @@
         verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(DpmMockContext.CALLER_USER_HANDLE),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES),
-                eq(false), eq(CAMERA_NOT_DISABLED));
+                eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER));
         reset(getServices().userManagerInternal);
 
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
@@ -1880,7 +1886,7 @@
                 eq(DpmMockContext.CALLER_USER_HANDLE),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
                         UserManager.DISALLOW_OUTGOING_CALLS),
-                eq(false), eq(CAMERA_NOT_DISABLED));
+                eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER));
         reset(getServices().userManagerInternal);
 
         DpmTestUtils.assertRestrictions(
@@ -1903,7 +1909,7 @@
         verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(DpmMockContext.CALLER_USER_HANDLE),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
-                eq(false), eq(CAMERA_NOT_DISABLED));
+                eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER));
         reset(getServices().userManagerInternal);
 
         DpmTestUtils.assertRestrictions(
@@ -1924,7 +1930,7 @@
         verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(DpmMockContext.CALLER_USER_HANDLE),
                 MockUtils.checkUserRestrictions(),
-                eq(false), eq(CAMERA_NOT_DISABLED));
+                eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER));
         reset(getServices().userManagerInternal);
 
         DpmTestUtils.assertRestrictions(
@@ -1946,20 +1952,47 @@
                 eq(DpmMockContext.CALLER_USER_HANDLE),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
                         UserManager.DISALLOW_UNMUTE_MICROPHONE),
-                eq(false), eq(CAMERA_NOT_DISABLED));
+                eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER));
         reset(getServices().userManagerInternal);
 
         dpm.setCameraDisabled(admin1, true);
         verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(DpmMockContext.CALLER_USER_HANDLE),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
-                        UserManager.DISALLOW_UNMUTE_MICROPHONE),
-                eq(false), eq(CAMERA_DISABLED_LOCALLY));
+                        UserManager.DISALLOW_UNMUTE_MICROPHONE, UserManager.DISALLOW_CAMERA),
+                eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER));
         reset(getServices().userManagerInternal);
 
         // TODO Make sure restrictions are written to the file.
     }
 
+    // TODO: (b/138709470) test addUserRestriction as PO of an organization-owned device
+    public void testSetUserRestriction_asPoOfOrgOwnedDevice() throws Exception {
+        final int MANAGED_PROFILE_USER_ID = DpmMockContext.CALLER_USER_HANDLE;
+        final int MANAGED_PROFILE_ADMIN_UID =
+                UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID);
+        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
+
+        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
+        configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+
+        when(getServices().userManager.getProfileParent(MANAGED_PROFILE_USER_ID))
+                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
+
+        parentDpm.setCameraDisabled(admin1, true);
+        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
+                eq(UserHandle.USER_SYSTEM),
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA),
+                eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE));
+        reset(getServices().userManagerInternal);
+
+        parentDpm.setCameraDisabled(admin1, false);
+        verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
+                eq(UserHandle.USER_SYSTEM),
+                MockUtils.checkUserRestrictions(),
+                eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE));
+        reset(getServices().userManagerInternal);
+    }
 
     public void testDefaultEnabledUserRestrictions() throws Exception {
         mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
@@ -1994,8 +2027,7 @@
         verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
                 MockUtils.checkUserRestrictions(defaultRestrictions),
-                eq(true) /* isDeviceOwner */,
-                eq(CAMERA_NOT_DISABLED)
+                eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER)
         );
         reset(getServices().userManagerInternal);
 
@@ -2035,10 +2067,9 @@
                 dpm.getUserRestrictions(admin1)
             );
             verify(getServices().userManagerInternal, atLeast(1)).setDevicePolicyUserRestrictions(
-                eq(UserHandle.USER_SYSTEM),
-                MockUtils.checkUserRestrictions(newDefaultEnabledRestriction),
-                eq(true) /* isDeviceOwner */,
-                eq(CAMERA_NOT_DISABLED)
+                    eq(UserHandle.USER_SYSTEM),
+                    MockUtils.checkUserRestrictions(newDefaultEnabledRestriction),
+                    eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER)
             );
             reset(getServices().userManagerInternal);
 
@@ -2087,12 +2118,14 @@
         assertTrue(dpm.isAdminActive(admin1));
 
         // Test 2. Caller has DA, but not DO.
-        assertExpectException(SecurityException.class, /* messageRegex= */ NOT_DEVICE_OWNER_MSG,
+        assertExpectException(SecurityException.class,
+                /* messageRegex= */ NOT_ORG_OWNED_PROFILE_OWNER_MSG,
                 () -> dpm.getWifiMacAddress(admin1));
 
         // Test 3. Caller has PO, but not DO.
         assertTrue(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM));
-        assertExpectException(SecurityException.class, /* messageRegex= */ NOT_DEVICE_OWNER_MSG,
+        assertExpectException(SecurityException.class,
+                /* messageRegex= */ NOT_ORG_OWNED_PROFILE_OWNER_MSG,
                 () -> dpm.getWifiMacAddress(admin1));
 
         // Remove PO.
@@ -2114,6 +2147,15 @@
         assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress(admin1));
     }
 
+    public void testGetMacAddressByOrgOwnedPO() throws Exception {
+        setupProfileOwner();
+        configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+
+        final String[] macAddresses = new String[]{"11:22:33:44:55:66"};
+        when(getServices().wifiManager.getFactoryMacAddresses()).thenReturn(macAddresses);
+        assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress(admin1));
+    }
+
     public void testReboot() throws Exception {
         mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
@@ -2608,6 +2650,16 @@
         mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
     }
 
+    private void setupProfileOwnerOnUser0() throws Exception {
+        mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS);
+
+        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
+        dpm.setActiveAdmin(admin1, false);
+        assertTrue(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM));
+
+        mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
+    }
+
     private void setupDeviceOwner() throws Exception {
         mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS);
 
@@ -3584,11 +3636,60 @@
             Settings.System.SCREEN_BRIGHTNESS, "0", DpmMockContext.CALLER_USER_HANDLE);
     }
 
+    public void testSetAutoTimeModifiesSetting() throws Exception {
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        setupDeviceOwner();
+        dpm.setAutoTime(admin1, true);
+        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 1);
+
+        dpm.setAutoTime(admin1, false);
+        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 0);
+    }
+
+    public void testSetAutoTimeWithPOOnUser0() throws Exception {
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        setupProfileOwnerOnUser0();
+        dpm.setAutoTime(admin1, true);
+        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 1);
+
+        dpm.setAutoTime(admin1, false);
+        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 0);
+    }
+
+    public void testSetAutoTimeFailWithPONotOnUser0() throws Exception {
+        setupProfileOwner();
+        assertExpectException(SecurityException.class, null, () -> dpm.setAutoTime(admin1, false));
+        verify(getServices().settings, never()).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 0);
+    }
+
+    public void testSetAutoTimeWithPOOfOrganizationOwnedDevice() throws Exception {
+        setupProfileOwner();
+        configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+
+        dpm.setAutoTime(admin1, true);
+        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 1);
+
+        dpm.setAutoTime(admin1, false);
+        verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 0);
+    }
+
     public void testSetTime() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setupDeviceOwner();
         dpm.setTime(admin1, 0);
-        verify(getServices().alarmManager).setTime(0);
+
+        BaseMatcher<ManualTimeSuggestion> hasZeroTime = new BaseMatcher<ManualTimeSuggestion>() {
+            @Override
+            public boolean matches(Object item) {
+                final ManualTimeSuggestion suggestion = (ManualTimeSuggestion) item;
+                return suggestion.getUtcTime().getValue() == 0;
+            }
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("ManualTimeSuggestion{utcTime.value=0}");
+            }
+        };
+        verify(getServices().timeDetector).suggestManualTime(argThat(hasZeroTime));
     }
 
     public void testSetTimeFailWithPO() throws Exception {
@@ -3608,7 +3709,9 @@
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setupDeviceOwner();
         dpm.setTimeZone(admin1, "Asia/Shanghai");
-        verify(getServices().alarmManager).setTimeZone("Asia/Shanghai");
+        ManualTimeZoneSuggestion suggestion =
+                TimeZoneDetector.createManualTimeZoneSuggestion("Asia/Shanghai", "Test debug info");
+        verify(getServices().timeZoneDetector).suggestManualTimeZone(suggestion);
     }
 
     public void testSetTimeZoneFailWithPO() throws Exception {
@@ -3758,7 +3861,7 @@
 
         // Add a secondary user, it should never talk with.
         final int ANOTHER_USER_ID = 36;
-        getServices().addUser(ANOTHER_USER_ID, 0);
+        getServices().addUser(ANOTHER_USER_ID, 0, UserManager.USER_TYPE_FULL_SECONDARY);
 
         // Since the managed profile is not affiliated, they should not be allowed to talk to each
         // other.
@@ -5103,8 +5206,8 @@
     }
 
     public void testRevertProfileOwnership_adminAndProfileMigrated() throws Exception {
-        getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, UserInfo.FLAG_MANAGED_PROFILE,
-                UserHandle.USER_SYSTEM);
+        getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0,
+                UserManager.USER_TYPE_PROFILE_MANAGED, UserHandle.USER_SYSTEM);
         DpmTestUtils.writeInputStreamToFile(
                 getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_migrated),
                 getProfileOwnerPoliciesFile());
@@ -5115,8 +5218,8 @@
     }
 
     public void testRevertProfileOwnership_profileNotMigrated() throws Exception {
-        getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, UserInfo.FLAG_MANAGED_PROFILE,
-                UserHandle.USER_SYSTEM);
+        getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0,
+                UserManager.USER_TYPE_PROFILE_MANAGED, UserHandle.USER_SYSTEM);
         DpmTestUtils.writeInputStreamToFile(
                 getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_migrated),
                 getProfileOwnerPoliciesFile());
@@ -5127,8 +5230,8 @@
     }
 
     public void testRevertProfileOwnership_adminAndProfileNotMigrated() throws Exception {
-        getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, UserInfo.FLAG_MANAGED_PROFILE,
-                UserHandle.USER_SYSTEM);
+        getServices().addUser(DpmMockContext.CALLER_USER_HANDLE, 0,
+                UserManager.USER_TYPE_PROFILE_MANAGED, UserHandle.USER_SYSTEM);
         DpmTestUtils.writeInputStreamToFile(
                 getRawStream(com.android.frameworks.servicestests.R.raw.active_admin_not_migrated),
                 getProfileOwnerPoliciesFile());
@@ -5302,11 +5405,7 @@
         mServiceContext.permissions.add(permission.REQUEST_PASSWORD_COMPLEXITY);
         setAsProfileOwner(admin1);
 
-        new DevicePolicyManagerTestable(
-                mServiceContext,
-                dpms,
-                /* parentInstance= */ true)
-                .getPasswordComplexity();
+        parentDpm.getPasswordComplexity();
 
         assertEquals(PASSWORD_COMPLEXITY_NONE, dpm.getPasswordComplexity());
     }
@@ -5582,7 +5681,8 @@
     private void addManagedProfile(
             ComponentName admin, int adminUid, ComponentName copyFromAdmin) throws Exception {
         final int userId = UserHandle.getUserId(adminUid);
-        getServices().addUser(userId, UserInfo.FLAG_MANAGED_PROFILE, UserHandle.USER_SYSTEM);
+        getServices().addUser(userId, 0, UserManager.USER_TYPE_PROFILE_MANAGED,
+                UserHandle.USER_SYSTEM);
         mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS);
         setUpPackageManagerForFakeAdmin(admin, adminUid, copyFromAdmin);
         dpm.setActiveAdmin(admin, false, userId);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index bd513dc..1a67576 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -207,6 +207,8 @@
         switch (name) {
             case Context.ALARM_SERVICE:
                 return mMockSystemServices.alarmManager;
+            case Context.TIME_DETECTOR_SERVICE:
+                return mMockSystemServices.timeDetector;
             case Context.USER_SERVICE:
                 return mMockSystemServices.userManager;
             case Context.POWER_SERVICE:
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index b0d0303..7a2350e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -31,6 +31,8 @@
 import android.app.IActivityTaskManager;
 import android.app.NotificationManager;
 import android.app.backup.IBackupManager;
+import android.app.timedetector.TimeDetector;
+import android.app.timezonedetector.TimeZoneDetector;
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.BroadcastReceiver;
 import android.content.ContentValues;
@@ -111,6 +113,8 @@
     public final TelephonyManager telephonyManager;
     public final AccountManager accountManager;
     public final AlarmManager alarmManager;
+    public final TimeDetector timeDetector;
+    public final TimeZoneDetector timeZoneDetector;
     public final KeyChain.KeyChainConnection keyChainConnection;
     /** Note this is a partial mock, not a real mock. */
     public final PackageManager packageManager;
@@ -152,6 +156,8 @@
         telephonyManager = mock(TelephonyManager.class);
         accountManager = mock(AccountManager.class);
         alarmManager = mock(AlarmManager.class);
+        timeDetector = mock(TimeDetector.class);
+        timeZoneDetector = mock(TimeZoneDetector.class);
         keyChainConnection = mock(KeyChain.KeyChainConnection.class, RETURNS_DEEP_STUBS);
 
         // Package manager is huge, so we use a partial mock instead.
@@ -179,8 +185,8 @@
 
         // Add the system user with a fake profile group already set up (this can happen in the real
         // world if a managed profile is added and then removed).
-        systemUserDataDir =
-                addUser(UserHandle.USER_SYSTEM, UserInfo.FLAG_PRIMARY, UserHandle.USER_SYSTEM);
+        systemUserDataDir = addUser(UserHandle.USER_SYSTEM, UserInfo.FLAG_PRIMARY,
+                UserManager.USER_TYPE_FULL_SYSTEM, UserHandle.USER_SYSTEM);
 
         // System user is always running.
         setUserRunning(UserHandle.USER_SYSTEM, true);
@@ -202,26 +208,21 @@
         mBroadcastReceivers.removeIf(r -> r.receiver == receiver);
     }
 
-    public File addUser(int userId, int flags) {
-        return addUser(userId, flags, UserInfo.NO_PROFILE_GROUP_ID);
+    public File addUser(int userId, int flags, String type) {
+        return addUser(userId, flags, type, UserInfo.NO_PROFILE_GROUP_ID);
     }
 
-    public File addUser(int userId, int flags, int profileGroupId) {
+    public File addUser(int userId, int flags, String type, int profileGroupId) {
         // Set up (default) UserInfo for CALLER_USER_HANDLE.
         final UserInfo uh = new UserInfo(userId, "user" + userId, flags);
+
+        uh.userType = type;
         uh.profileGroupId = profileGroupId;
         when(userManager.getUserInfo(eq(userId))).thenReturn(uh);
-
         mUserInfos.add(uh);
         when(userManager.getUsers()).thenReturn(mUserInfos);
         when(userManager.getUsers(anyBoolean())).thenReturn(mUserInfos);
         when(userManager.isUserRunning(eq(new UserHandle(userId)))).thenReturn(true);
-        when(userManager.getUserInfo(anyInt())).thenAnswer(
-                invocation -> {
-                    final int userId1 = (int) invocation.getArguments()[0];
-                    return getUserInfo(userId1);
-                }
-        );
         when(userManager.getProfileParent(anyInt())).thenAnswer(
                 invocation -> {
                     final int userId1 = (int) invocation.getArguments()[0];
@@ -302,7 +303,7 @@
      */
     public void addUsers(int... userIds) {
         for (final int userId : userIds) {
-            addUser(userId, 0);
+            addUser(userId, 0, "");
         }
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
new file mode 100644
index 0000000..269f918
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -0,0 +1,137 @@
+/*
+ * 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.display;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.SparseArray;
+import android.view.Display;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DisplayModeDirectorTest {
+    private Context mContext;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+    }
+
+    private DisplayModeDirector createDisplayModeDirectorWithDisplayFpsRange(
+            int minFps, int maxFps) {
+        DisplayModeDirector director =
+                new DisplayModeDirector(mContext, new Handler(Looper.getMainLooper()));
+        int displayId = 0;
+        int numModes = maxFps - minFps + 1;
+        Display.Mode[] modes = new Display.Mode[numModes];
+        for (int i = minFps; i <= maxFps; i++) {
+            modes[i - minFps] = new Display.Mode(
+                    /*modeId=*/i, /*width=*/1000, /*height=*/1000, /*refreshRate=*/i);
+        }
+        SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<Display.Mode[]>();
+        supportedModesByDisplay.put(displayId, modes);
+        director.injectSupportedModesByDisplay(supportedModesByDisplay);
+        SparseArray<Display.Mode> defaultModesByDisplay = new SparseArray<Display.Mode>();
+        defaultModesByDisplay.put(displayId, modes[0]);
+        director.injectDefaultModeByDisplay(defaultModesByDisplay);
+        return director;
+    }
+
+    private int[] intRange(int min, int max) {
+        int[] range = new int[max - min + 1];
+        for (int i = min; i <= max; i++) {
+            range[i - min] = i;
+        }
+        return range;
+    }
+
+    @Test
+    public void testDisplayModeVoting() {
+        int displayId = 0;
+
+        // With no votes present, DisplayModeDirector should allow any refresh rate.
+        assertEquals(new DisplayModeDirector.DesiredDisplayConfigSpecs(/*defaultModeId=*/60,
+                             new DisplayModeDirector.RefreshRateRange(0f, Float.POSITIVE_INFINITY),
+                             intRange(60, 90)),
+                createDisplayModeDirectorWithDisplayFpsRange(60, 90).getDesiredDisplayConfigSpecs(
+                        displayId));
+
+        int numPriorities =
+                DisplayModeDirector.Vote.MAX_PRIORITY - DisplayModeDirector.Vote.MIN_PRIORITY + 1;
+
+        // Ensure vote priority works as expected. As we add new votes with higher priority, they
+        // should take precedence over lower priority votes.
+        {
+            int minFps = 60;
+            int maxFps = 90;
+            DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(60, 90);
+            assertTrue(2 * numPriorities < maxFps - minFps + 1);
+            SparseArray<DisplayModeDirector.Vote> votes =
+                    new SparseArray<DisplayModeDirector.Vote>();
+            SparseArray<SparseArray<DisplayModeDirector.Vote>> votesByDisplay =
+                    new SparseArray<SparseArray<DisplayModeDirector.Vote>>();
+            votesByDisplay.put(displayId, votes);
+            for (int i = 0; i < numPriorities; i++) {
+                int priority = DisplayModeDirector.Vote.MIN_PRIORITY + i;
+                votes.put(
+                        priority, DisplayModeDirector.Vote.forRefreshRates(minFps + i, maxFps - i));
+                director.injectVotesByDisplay(votesByDisplay);
+                assertEquals(
+                        new DisplayModeDirector.DesiredDisplayConfigSpecs(
+                                /*defaultModeId=*/minFps + i,
+                                new DisplayModeDirector.RefreshRateRange(minFps + i, maxFps - i),
+                                intRange(minFps + i, maxFps - i)),
+                        director.getDesiredDisplayConfigSpecs(displayId));
+            }
+        }
+
+        // Ensure lower priority votes are able to influence the final decision, even in the
+        // presence of higher priority votes.
+        {
+            assertTrue(numPriorities >= 2);
+            DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(60, 90);
+            SparseArray<DisplayModeDirector.Vote> votes =
+                    new SparseArray<DisplayModeDirector.Vote>();
+            SparseArray<SparseArray<DisplayModeDirector.Vote>> votesByDisplay =
+                    new SparseArray<SparseArray<DisplayModeDirector.Vote>>();
+            votesByDisplay.put(displayId, votes);
+            votes.put(DisplayModeDirector.Vote.MAX_PRIORITY,
+                    DisplayModeDirector.Vote.forRefreshRates(65, 85));
+            votes.put(DisplayModeDirector.Vote.MIN_PRIORITY,
+                    DisplayModeDirector.Vote.forRefreshRates(70, 80));
+            director.injectVotesByDisplay(votesByDisplay);
+            assertEquals(
+                    new DisplayModeDirector.DesiredDisplayConfigSpecs(/*defaultModeId=*/70,
+                            new DisplayModeDirector.RefreshRateRange(70, 80), intRange(70, 80)),
+                    director.getDesiredDisplayConfigSpecs(displayId));
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java
new file mode 100644
index 0000000..88b6d70
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleBinaryParserTest.java
@@ -0,0 +1,628 @@
+/*
+ * 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.integrity.parser;
+
+import static com.android.server.integrity.model.ComponentBitSize.ATOMIC_FORMULA_START;
+import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_END;
+import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_START;
+import static com.android.server.integrity.model.ComponentBitSize.CONNECTOR_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.DEFAULT_FORMAT_VERSION;
+import static com.android.server.integrity.model.ComponentBitSize.EFFECT_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.FORMAT_VERSION_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.KEY_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.OPERATOR_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.SEPARATOR_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BITS;
+import static com.android.server.integrity.utils.TestUtils.getBits;
+import static com.android.server.integrity.utils.TestUtils.getBytes;
+import static com.android.server.integrity.utils.TestUtils.getValueBits;
+import static com.android.server.testutils.TestUtils.assertExpectException;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.integrity.AtomicFormula;
+import android.content.integrity.CompoundFormula;
+import android.content.integrity.Rule;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+@RunWith(JUnit4.class)
+public class RuleBinaryParserTest {
+
+    private static final String COMPOUND_FORMULA_START_BITS =
+            getBits(COMPOUND_FORMULA_START, SEPARATOR_BITS);
+    private static final String COMPOUND_FORMULA_END_BITS =
+            getBits(COMPOUND_FORMULA_END, SEPARATOR_BITS);
+    private static final String ATOMIC_FORMULA_START_BITS =
+            getBits(ATOMIC_FORMULA_START, SEPARATOR_BITS);
+    private static final int INVALID_FORMULA_SEPARATOR_VALUE = 3;
+    private static final String INVALID_FORMULA_SEPARATOR_BITS =
+            getBits(INVALID_FORMULA_SEPARATOR_VALUE, SEPARATOR_BITS);
+
+    private static final String NOT = getBits(CompoundFormula.NOT, CONNECTOR_BITS);
+    private static final String AND = getBits(CompoundFormula.AND, CONNECTOR_BITS);
+    private static final String OR = getBits(CompoundFormula.OR, CONNECTOR_BITS);
+    private static final int INVALID_CONNECTOR_VALUE = 3;
+    private static final String INVALID_CONNECTOR =
+            getBits(INVALID_CONNECTOR_VALUE, CONNECTOR_BITS);
+
+    private static final String PACKAGE_NAME = getBits(AtomicFormula.PACKAGE_NAME, KEY_BITS);
+    private static final String APP_CERTIFICATE = getBits(AtomicFormula.APP_CERTIFICATE, KEY_BITS);
+    private static final String VERSION_CODE = getBits(AtomicFormula.VERSION_CODE, KEY_BITS);
+    private static final String PRE_INSTALLED = getBits(AtomicFormula.PRE_INSTALLED, KEY_BITS);
+    private static final int INVALID_KEY_VALUE = 6;
+    private static final String INVALID_KEY = getBits(INVALID_KEY_VALUE, KEY_BITS);
+
+    private static final String EQ = getBits(AtomicFormula.EQ, OPERATOR_BITS);
+    private static final int INVALID_OPERATOR_VALUE = 5;
+    private static final String INVALID_OPERATOR = getBits(INVALID_OPERATOR_VALUE, OPERATOR_BITS);
+
+    private static final String IS_NOT_HASHED = "0";
+
+    private static final String DENY = getBits(Rule.DENY, EFFECT_BITS);
+    private static final int INVALID_EFFECT_VALUE = 5;
+    private static final String INVALID_EFFECT = getBits(INVALID_EFFECT_VALUE, EFFECT_BITS);
+
+    private static final String START_BIT = "1";
+    private static final String END_BIT = "1";
+    private static final String INVALID_MARKER_BIT = "0";
+
+    private static final byte[] DEFAULT_FORMAT_VERSION_BYTES =
+            getBytes(getBits(DEFAULT_FORMAT_VERSION, FORMAT_VERSION_BITS));
+
+    @Test
+    public void testBinaryStream_validCompoundFormula() throws Exception {
+        String packageName = "com.test.app";
+        String ruleBits =
+                START_BIT
+                        + COMPOUND_FORMULA_START_BITS
+                        + NOT
+                        + ATOMIC_FORMULA_START_BITS
+                        + PACKAGE_NAME
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(packageName.length(), VALUE_SIZE_BITS)
+                        + getValueBits(packageName)
+                        + COMPOUND_FORMULA_END_BITS
+                        + DENY
+                        + END_BIT;
+        byte[] ruleBytes = getBytes(ruleBits);
+        ByteBuffer rule =
+                ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
+        rule.put(DEFAULT_FORMAT_VERSION_BYTES);
+        rule.put(ruleBytes);
+        RuleParser binaryParser = new RuleBinaryParser();
+        InputStream inputStream = new ByteArrayInputStream(rule.array());
+        Rule expectedRule =
+                new Rule(
+                        new CompoundFormula(
+                                CompoundFormula.NOT,
+                                Collections.singletonList(
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.PACKAGE_NAME,
+                                                packageName,
+                                                /* isHashedValue= */ false))),
+                        Rule.DENY);
+
+        List<Rule> rules = binaryParser.parse(inputStream);
+
+        assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+    }
+
+    @Test
+    public void testBinaryString_validCompoundFormula_notConnector() throws Exception {
+        String packageName = "com.test.app";
+        String ruleBits =
+                START_BIT
+                        + COMPOUND_FORMULA_START_BITS
+                        + NOT
+                        + ATOMIC_FORMULA_START_BITS
+                        + PACKAGE_NAME
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(packageName.length(), VALUE_SIZE_BITS)
+                        + getValueBits(packageName)
+                        + COMPOUND_FORMULA_END_BITS
+                        + DENY
+                        + END_BIT;
+        byte[] ruleBytes = getBytes(ruleBits);
+        ByteBuffer rule =
+                ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
+        rule.put(DEFAULT_FORMAT_VERSION_BYTES);
+        rule.put(ruleBytes);
+        RuleParser binaryParser = new RuleBinaryParser();
+        Rule expectedRule =
+                new Rule(
+                        new CompoundFormula(
+                                CompoundFormula.NOT,
+                                Collections.singletonList(
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.PACKAGE_NAME,
+                                                packageName,
+                                                /* isHashedValue= */ false))),
+                        Rule.DENY);
+
+        List<Rule> rules = binaryParser.parse(rule.array());
+
+        assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+    }
+
+    @Test
+    public void testBinaryString_validCompoundFormula_andConnector() throws Exception {
+        String packageName = "com.test.app";
+        String appCertificate = "test_cert";
+        String ruleBits =
+                START_BIT
+                        + COMPOUND_FORMULA_START_BITS
+                        + AND
+                        + ATOMIC_FORMULA_START_BITS
+                        + PACKAGE_NAME
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(packageName.length(), VALUE_SIZE_BITS)
+                        + getValueBits(packageName)
+                        + ATOMIC_FORMULA_START_BITS
+                        + APP_CERTIFICATE
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(appCertificate.length(), VALUE_SIZE_BITS)
+                        + getValueBits(appCertificate)
+                        + COMPOUND_FORMULA_END_BITS
+                        + DENY
+                        + END_BIT;
+        byte[] ruleBytes = getBytes(ruleBits);
+        ByteBuffer rule =
+                ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
+        rule.put(DEFAULT_FORMAT_VERSION_BYTES);
+        rule.put(ruleBytes);
+        RuleParser binaryParser = new RuleBinaryParser();
+        Rule expectedRule =
+                new Rule(
+                        new CompoundFormula(
+                                CompoundFormula.AND,
+                                Arrays.asList(
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.PACKAGE_NAME,
+                                                packageName,
+                                                /* isHashedValue= */ false),
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.APP_CERTIFICATE,
+                                                appCertificate,
+                                                /* isHashedValue= */ false))),
+                        Rule.DENY);
+        List<Rule> rules = binaryParser.parse(rule.array());
+
+        assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+    }
+
+    @Test
+    public void testBinaryString_validCompoundFormula_orConnector() throws Exception {
+        String packageName = "com.test.app";
+        String appCertificate = "test_cert";
+        String ruleBits =
+                START_BIT
+                        + COMPOUND_FORMULA_START_BITS
+                        + OR
+                        + ATOMIC_FORMULA_START_BITS
+                        + PACKAGE_NAME
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(packageName.length(), VALUE_SIZE_BITS)
+                        + getValueBits(packageName)
+                        + ATOMIC_FORMULA_START_BITS
+                        + APP_CERTIFICATE
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(appCertificate.length(), VALUE_SIZE_BITS)
+                        + getValueBits(appCertificate)
+                        + COMPOUND_FORMULA_END_BITS
+                        + DENY
+                        + END_BIT;
+        byte[] ruleBytes = getBytes(ruleBits);
+        ByteBuffer rule =
+                ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
+        rule.put(DEFAULT_FORMAT_VERSION_BYTES);
+        rule.put(ruleBytes);
+        RuleParser binaryParser = new RuleBinaryParser();
+        Rule expectedRule =
+                new Rule(
+                        new CompoundFormula(
+                                CompoundFormula.OR,
+                                Arrays.asList(
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.PACKAGE_NAME,
+                                                packageName,
+                                                /* isHashedValue= */ false),
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.APP_CERTIFICATE,
+                                                appCertificate,
+                                                /* isHashedValue= */ false))),
+                        Rule.DENY);
+
+        List<Rule> rules = binaryParser.parse(rule.array());
+
+        assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+    }
+
+    @Test
+    public void testBinaryString_validAtomicFormula_stringValue() throws Exception {
+        String packageName = "com.test.app";
+        String ruleBits =
+                START_BIT
+                        + ATOMIC_FORMULA_START_BITS
+                        + PACKAGE_NAME
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(packageName.length(), VALUE_SIZE_BITS)
+                        + getValueBits(packageName)
+                        + DENY
+                        + END_BIT;
+        byte[] ruleBytes = getBytes(ruleBits);
+        ByteBuffer rule =
+                ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
+        rule.put(DEFAULT_FORMAT_VERSION_BYTES);
+        rule.put(ruleBytes);
+        RuleParser binaryParser = new RuleBinaryParser();
+        Rule expectedRule =
+                new Rule(
+                        new AtomicFormula.StringAtomicFormula(
+                                AtomicFormula.PACKAGE_NAME,
+                                packageName,
+                                /* isHashedValue= */ false),
+                        Rule.DENY);
+
+        List<Rule> rules = binaryParser.parse(rule.array());
+
+        assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+    }
+
+    @Test
+    public void testBinaryString_validAtomicFormula_integerValue() throws Exception {
+        String versionCode = "1";
+        String ruleBits =
+                START_BIT
+                        + ATOMIC_FORMULA_START_BITS
+                        + VERSION_CODE
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(versionCode.length(), VALUE_SIZE_BITS)
+                        + getValueBits(versionCode)
+                        + DENY
+                        + END_BIT;
+        byte[] ruleBytes = getBytes(ruleBits);
+        ByteBuffer rule =
+                ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
+        rule.put(DEFAULT_FORMAT_VERSION_BYTES);
+        rule.put(ruleBytes);
+        RuleParser binaryParser = new RuleBinaryParser();
+        Rule expectedRule =
+                new Rule(
+                        new AtomicFormula.IntAtomicFormula(
+                                AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1),
+                        Rule.DENY);
+
+        List<Rule> rules = binaryParser.parse(rule.array());
+
+        assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+    }
+
+    @Test
+    public void testBinaryString_validAtomicFormula_booleanValue() throws Exception {
+        String isPreInstalled = "1";
+        String ruleBits =
+                START_BIT
+                        + ATOMIC_FORMULA_START_BITS
+                        + PRE_INSTALLED
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(isPreInstalled.length(), VALUE_SIZE_BITS)
+                        + getValueBits(isPreInstalled)
+                        + DENY
+                        + END_BIT;
+        byte[] ruleBytes = getBytes(ruleBits);
+        ByteBuffer rule =
+                ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
+        rule.put(DEFAULT_FORMAT_VERSION_BYTES);
+        rule.put(ruleBytes);
+        RuleParser binaryParser = new RuleBinaryParser();
+        Rule expectedRule =
+                new Rule(
+                        new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true),
+                        Rule.DENY);
+
+        List<Rule> rules = binaryParser.parse(rule.array());
+
+        assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
+    }
+
+    @Test
+    public void testBinaryString_invalidAtomicFormula() throws Exception {
+        String versionCode = "test";
+        String ruleBits =
+                START_BIT
+                        + ATOMIC_FORMULA_START_BITS
+                        + VERSION_CODE
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(versionCode.length(), VALUE_SIZE_BITS)
+                        + getValueBits(versionCode)
+                        + DENY
+                        + END_BIT;
+        byte[] ruleBytes = getBytes(ruleBits);
+        ByteBuffer rule =
+                ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
+        rule.put(DEFAULT_FORMAT_VERSION_BYTES);
+        rule.put(ruleBytes);
+        RuleParser binaryParser = new RuleBinaryParser();
+
+        assertExpectException(
+                RuleParseException.class,
+                /* expectedExceptionMessageRegex */ "For input string:",
+                () -> binaryParser.parse(rule.array()));
+    }
+
+    @Test
+    public void testBinaryString_withNoRuleList() throws RuleParseException {
+        ByteBuffer rule = ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length);
+        rule.put(DEFAULT_FORMAT_VERSION_BYTES);
+        RuleParser binaryParser = new RuleBinaryParser();
+
+        List<Rule> rules = binaryParser.parse(rule.array());
+
+        assertThat(rules).isEmpty();
+    }
+
+    @Test
+    public void testBinaryString_withEmptyRule() throws RuleParseException {
+        String ruleBits = START_BIT;
+        byte[] ruleBytes = getBytes(ruleBits);
+        ByteBuffer rule =
+                ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
+        rule.put(DEFAULT_FORMAT_VERSION_BYTES);
+        rule.put(ruleBytes);
+        RuleParser binaryParser = new RuleBinaryParser();
+
+        assertExpectException(
+                RuleParseException.class,
+                /* expectedExceptionMessageRegex */ "Invalid byte index",
+                () -> binaryParser.parse(rule.array()));
+    }
+
+    @Test
+    public void testBinaryString_invalidCompoundFormula_invalidNumberOfFormulas() throws Exception {
+        String packageName = "com.test.app";
+        String appCertificate = "test_cert";
+        String ruleBits =
+                START_BIT
+                        + COMPOUND_FORMULA_START_BITS
+                        + NOT
+                        + ATOMIC_FORMULA_START_BITS
+                        + PACKAGE_NAME
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(packageName.length(), VALUE_SIZE_BITS)
+                        + getValueBits(packageName)
+                        + ATOMIC_FORMULA_START_BITS
+                        + APP_CERTIFICATE
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(appCertificate.length(), VALUE_SIZE_BITS)
+                        + getValueBits(appCertificate)
+                        + COMPOUND_FORMULA_END_BITS
+                        + DENY
+                        + END_BIT;
+        byte[] ruleBytes = getBytes(ruleBits);
+        ByteBuffer rule =
+                ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
+        rule.put(DEFAULT_FORMAT_VERSION_BYTES);
+        rule.put(ruleBytes);
+        RuleParser binaryParser = new RuleBinaryParser();
+
+        assertExpectException(
+                RuleParseException.class,
+                /* expectedExceptionMessageRegex */ "Connector NOT must have 1 formula only",
+                () -> binaryParser.parse(rule.array()));
+    }
+
+    @Test
+    public void testBinaryString_invalidRule_invalidOperator() throws Exception {
+        String versionCode = "1";
+        String ruleBits =
+                START_BIT
+                        + COMPOUND_FORMULA_START_BITS
+                        + NOT
+                        + ATOMIC_FORMULA_START_BITS
+                        + VERSION_CODE
+                        + INVALID_OPERATOR
+                        + IS_NOT_HASHED
+                        + getBits(versionCode.length(), VALUE_SIZE_BITS)
+                        + getValueBits(versionCode)
+                        + COMPOUND_FORMULA_END_BITS
+                        + DENY
+                        + END_BIT;
+        byte[] ruleBytes = getBytes(ruleBits);
+        ByteBuffer rule =
+                ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
+        rule.put(DEFAULT_FORMAT_VERSION_BYTES);
+        rule.put(ruleBytes);
+        RuleParser binaryParser = new RuleBinaryParser();
+
+        assertExpectException(
+                RuleParseException.class,
+                /* expectedExceptionMessageRegex */ String.format(
+                        "Unknown operator: %d", INVALID_OPERATOR_VALUE),
+                () -> binaryParser.parse(rule.array()));
+    }
+
+    @Test
+    public void testBinaryString_invalidRule_invalidEffect() throws Exception {
+        String packageName = "com.test.app";
+        String ruleBits =
+                START_BIT
+                        + COMPOUND_FORMULA_START_BITS
+                        + NOT
+                        + ATOMIC_FORMULA_START_BITS
+                        + PACKAGE_NAME
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(packageName.length(), VALUE_SIZE_BITS)
+                        + getValueBits(packageName)
+                        + COMPOUND_FORMULA_END_BITS
+                        + INVALID_EFFECT
+                        + END_BIT;
+        byte[] ruleBytes = getBytes(ruleBits);
+        ByteBuffer rule =
+                ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
+        rule.put(DEFAULT_FORMAT_VERSION_BYTES);
+        rule.put(ruleBytes);
+        RuleParser binaryParser = new RuleBinaryParser();
+
+        assertExpectException(
+                RuleParseException.class,
+                /* expectedExceptionMessageRegex */ String.format(
+                        "Unknown effect: %d", INVALID_EFFECT_VALUE),
+                () -> binaryParser.parse(rule.array()));
+    }
+
+    @Test
+    public void testBinaryString_invalidRule_invalidConnector() throws Exception {
+        String packageName = "com.test.app";
+        String ruleBits =
+                START_BIT
+                        + COMPOUND_FORMULA_START_BITS
+                        + INVALID_CONNECTOR
+                        + ATOMIC_FORMULA_START_BITS
+                        + PACKAGE_NAME
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(packageName.length(), VALUE_SIZE_BITS)
+                        + getValueBits(packageName)
+                        + COMPOUND_FORMULA_END_BITS
+                        + DENY
+                        + END_BIT;
+        byte[] ruleBytes = getBytes(ruleBits);
+        ByteBuffer rule =
+                ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
+        rule.put(DEFAULT_FORMAT_VERSION_BYTES);
+        rule.put(ruleBytes);
+        RuleParser binaryParser = new RuleBinaryParser();
+
+        assertExpectException(
+                RuleParseException.class,
+                /* expectedExceptionMessageRegex */ String.format(
+                        "Unknown connector: %d", INVALID_CONNECTOR_VALUE),
+                () -> binaryParser.parse(rule.array()));
+    }
+
+    @Test
+    public void testBinaryString_invalidRule_invalidKey() throws Exception {
+        String packageName = "com.test.app";
+        String ruleBits =
+                START_BIT
+                        + COMPOUND_FORMULA_START_BITS
+                        + NOT
+                        + ATOMIC_FORMULA_START_BITS
+                        + INVALID_KEY
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(packageName.length(), VALUE_SIZE_BITS)
+                        + getValueBits(packageName)
+                        + COMPOUND_FORMULA_END_BITS
+                        + DENY
+                        + END_BIT;
+        byte[] ruleBytes = getBytes(ruleBits);
+        ByteBuffer rule =
+                ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
+        rule.put(DEFAULT_FORMAT_VERSION_BYTES);
+        rule.put(ruleBytes);
+        RuleParser binaryParser = new RuleBinaryParser();
+
+        assertExpectException(
+                RuleParseException.class,
+                /* expectedExceptionMessageRegex */ String.format(
+                        "Unknown key: %d", INVALID_KEY_VALUE),
+                () -> binaryParser.parse(rule.array()));
+    }
+
+    @Test
+    public void testBinaryString_invalidRule_invalidSeparator() throws Exception {
+        String packageName = "com.test.app";
+        String ruleBits =
+                START_BIT
+                        + INVALID_FORMULA_SEPARATOR_BITS
+                        + NOT
+                        + ATOMIC_FORMULA_START_BITS
+                        + PACKAGE_NAME
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(packageName.length(), VALUE_SIZE_BITS)
+                        + getValueBits(packageName)
+                        + COMPOUND_FORMULA_END_BITS
+                        + DENY
+                        + END_BIT;
+        byte[] ruleBytes = getBytes(ruleBits);
+        ByteBuffer rule =
+                ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
+        rule.put(DEFAULT_FORMAT_VERSION_BYTES);
+        rule.put(ruleBytes);
+        RuleParser binaryParser = new RuleBinaryParser();
+
+        assertExpectException(
+                RuleParseException.class,
+                /* expectedExceptionMessageRegex */ String.format(
+                        "Unknown formula separator: %d", INVALID_FORMULA_SEPARATOR_VALUE),
+                () -> binaryParser.parse(rule.array()));
+    }
+
+    @Test
+    public void testBinaryString_invalidRule_invalidEndMarker() throws Exception {
+        String packageName = "com.test.app";
+        String ruleBits =
+                START_BIT
+                        + COMPOUND_FORMULA_START_BITS
+                        + NOT
+                        + ATOMIC_FORMULA_START_BITS
+                        + PACKAGE_NAME
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(packageName.length(), VALUE_SIZE_BITS)
+                        + getValueBits(packageName)
+                        + COMPOUND_FORMULA_END_BITS
+                        + DENY
+                        + INVALID_MARKER_BIT;
+        byte[] ruleBytes = getBytes(ruleBits);
+        ByteBuffer rule =
+                ByteBuffer.allocate(DEFAULT_FORMAT_VERSION_BYTES.length + ruleBytes.length);
+        rule.put(DEFAULT_FORMAT_VERSION_BYTES);
+        rule.put(ruleBytes);
+        RuleParser binaryParser = new RuleBinaryParser();
+
+        assertExpectException(
+                RuleParseException.class,
+                /* expectedExceptionMessageRegex */ "A rule must end with a '1' bit",
+                () -> binaryParser.parse(rule.array()));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java
index 495923d..a14197b 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java
@@ -30,6 +30,7 @@
 
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
@@ -109,7 +110,7 @@
                                                 /* isHashedValue= */ false))),
                         Rule.DENY);
 
-        List<Rule> rules = xmlParser.parse(ruleXmlCompoundFormula);
+        List<Rule> rules = xmlParser.parse(ruleXmlCompoundFormula.getBytes(StandardCharsets.UTF_8));
 
         assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
     }
@@ -154,7 +155,7 @@
                                                 "test_cert",
                                                 /* isHashedValue= */ false))),
                         Rule.DENY);
-        List<Rule> rules = xmlParser.parse(ruleXmlCompoundFormula);
+        List<Rule> rules = xmlParser.parse(ruleXmlCompoundFormula.getBytes(StandardCharsets.UTF_8));
 
         assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
     }
@@ -200,7 +201,7 @@
                                                 /* isHashedValue= */ false))),
                         Rule.DENY);
 
-        List<Rule> rules = xmlParser.parse(ruleXmlCompoundFormula);
+        List<Rule> rules = xmlParser.parse(ruleXmlCompoundFormula.getBytes(StandardCharsets.UTF_8));
 
         assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
     }
@@ -237,7 +238,7 @@
                                                 /* isHashedValue= */ false))),
                         Rule.DENY);
 
-        List<Rule> rules = xmlParser.parse(ruleXmlCompoundFormula);
+        List<Rule> rules = xmlParser.parse(ruleXmlCompoundFormula.getBytes(StandardCharsets.UTF_8));
 
         assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
     }
@@ -273,7 +274,7 @@
         assertExpectException(
                 RuleParseException.class,
                 /* expectedExceptionMessageRegex */ "Connector NOT must have 1 formula only",
-                () -> xmlParser.parse(ruleXmlCompoundFormula));
+                () -> xmlParser.parse(ruleXmlCompoundFormula.getBytes(StandardCharsets.UTF_8)));
     }
 
     @Test
@@ -302,7 +303,7 @@
         assertExpectException(
                 RuleParseException.class,
                 /* expectedExceptionMessageRegex */ "For input string: \"INVALID_OPERATOR\"",
-                () -> xmlParser.parse(ruleXmlCompoundFormula));
+                () -> xmlParser.parse(ruleXmlCompoundFormula.getBytes(StandardCharsets.UTF_8)));
     }
 
     @Test
@@ -330,7 +331,7 @@
         assertExpectException(
                 RuleParseException.class,
                 /* expectedExceptionMessageRegex */ "For input string: \"INVALID_EFFECT\"",
-                () -> xmlParser.parse(ruleXmlCompoundFormula));
+                () -> xmlParser.parse(ruleXmlCompoundFormula.getBytes(StandardCharsets.UTF_8)));
     }
 
     @Test
@@ -360,7 +361,7 @@
         assertExpectException(
                 RuleParseException.class,
                 /* expectedExceptionMessageRegex */ "Found unexpected tag: InvalidAtomicFormula",
-                () -> xmlParser.parse(ruleXmlCompoundFormula));
+                () -> xmlParser.parse(ruleXmlCompoundFormula.getBytes(StandardCharsets.UTF_8)));
     }
 
     @Test
@@ -387,7 +388,7 @@
                                 /* isHashedValue= */ false),
                         Rule.DENY);
 
-        List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
+        List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula.getBytes(StandardCharsets.UTF_8));
 
         assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
     }
@@ -415,7 +416,7 @@
                                 AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1),
                         Rule.DENY);
 
-        List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
+        List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula.getBytes(StandardCharsets.UTF_8));
 
         assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
     }
@@ -441,7 +442,7 @@
                         new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true),
                         Rule.DENY);
 
-        List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
+        List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula.getBytes(StandardCharsets.UTF_8));
 
         assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
     }
@@ -470,7 +471,7 @@
                                 /* isHashedValue= */ false),
                         Rule.DENY);
 
-        List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
+        List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula.getBytes(StandardCharsets.UTF_8));
 
         assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
     }
@@ -495,7 +496,7 @@
         assertExpectException(
                 RuleParseException.class,
                 /* expectedExceptionMessageRegex */ "Found unexpected key: -1",
-                () -> xmlParser.parse(ruleXmlAtomicFormula));
+                () -> xmlParser.parse(ruleXmlAtomicFormula.getBytes(StandardCharsets.UTF_8)));
     }
 
     @Test
@@ -517,7 +518,7 @@
         assertExpectException(
                 RuleParseException.class,
                 /* expectedExceptionMessageRegex */ "Unknown effect: -1",
-                () -> xmlParser.parse(ruleXmlAtomicFormula));
+                () -> xmlParser.parse(ruleXmlAtomicFormula.getBytes(StandardCharsets.UTF_8)));
     }
 
     @Test
@@ -545,7 +546,7 @@
         assertExpectException(
                 RuleParseException.class,
                 /* expectedExceptionMessageRegex */ "Unknown connector: -1",
-                () -> xmlParser.parse(ruleXmlCompoundFormula));
+                () -> xmlParser.parse(ruleXmlCompoundFormula.getBytes(StandardCharsets.UTF_8)));
     }
 
     @Test
@@ -569,7 +570,7 @@
         assertExpectException(
                 RuleParseException.class,
                 /* expectedExceptionMessageRegex */ "For input string: \"com.app.test\"",
-                () -> xmlParser.parse(ruleXmlAtomicFormula));
+                () -> xmlParser.parse(ruleXmlAtomicFormula.getBytes(StandardCharsets.UTF_8)));
     }
 
     @Test
@@ -595,7 +596,7 @@
         assertExpectException(
                 RuleParseException.class,
                 /* expectedExceptionMessageRegex */ "Rules must start with RuleList <RL> tag",
-                () -> xmlParser.parse(ruleXmlWithNoRuleList));
+                () -> xmlParser.parse(ruleXmlWithNoRuleList.getBytes(StandardCharsets.UTF_8)));
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java
new file mode 100644
index 0000000..901277d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java
@@ -0,0 +1,444 @@
+/*
+ * 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.integrity.serializer;
+
+import static com.android.server.integrity.model.ComponentBitSize.ATOMIC_FORMULA_START;
+import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_END;
+import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_START;
+import static com.android.server.integrity.model.ComponentBitSize.CONNECTOR_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.DEFAULT_FORMAT_VERSION;
+import static com.android.server.integrity.model.ComponentBitSize.EFFECT_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.FORMAT_VERSION_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.KEY_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.OPERATOR_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.SEPARATOR_BITS;
+import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BITS;
+import static com.android.server.integrity.utils.TestUtils.getBits;
+import static com.android.server.integrity.utils.TestUtils.getBytes;
+import static com.android.server.integrity.utils.TestUtils.getValueBits;
+import static com.android.server.testutils.TestUtils.assertExpectException;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.integrity.AppInstallMetadata;
+import android.content.integrity.AtomicFormula;
+import android.content.integrity.CompoundFormula;
+import android.content.integrity.Formula;
+import android.content.integrity.Rule;
+
+import androidx.annotation.NonNull;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Optional;
+
+@RunWith(JUnit4.class)
+public class RuleBinarySerializerTest {
+
+    private static final String COMPOUND_FORMULA_START_BITS =
+            getBits(COMPOUND_FORMULA_START, SEPARATOR_BITS);
+    private static final String COMPOUND_FORMULA_END_BITS =
+            getBits(COMPOUND_FORMULA_END, SEPARATOR_BITS);
+    private static final String ATOMIC_FORMULA_START_BITS =
+            getBits(ATOMIC_FORMULA_START, SEPARATOR_BITS);
+
+    private static final String NOT = getBits(CompoundFormula.NOT, CONNECTOR_BITS);
+    private static final String AND = getBits(CompoundFormula.AND, CONNECTOR_BITS);
+    private static final String OR = getBits(CompoundFormula.OR, CONNECTOR_BITS);
+
+    private static final String PACKAGE_NAME = getBits(AtomicFormula.PACKAGE_NAME, KEY_BITS);
+    private static final String APP_CERTIFICATE = getBits(AtomicFormula.APP_CERTIFICATE, KEY_BITS);
+    private static final String VERSION_CODE = getBits(AtomicFormula.VERSION_CODE, KEY_BITS);
+    private static final String PRE_INSTALLED = getBits(AtomicFormula.PRE_INSTALLED, KEY_BITS);
+
+    private static final String EQ = getBits(AtomicFormula.EQ, OPERATOR_BITS);
+
+    private static final String IS_NOT_HASHED = "0";
+
+    private static final String DENY = getBits(Rule.DENY, EFFECT_BITS);
+
+    private static final String START_BIT = "1";
+    private static final String END_BIT = "1";
+
+    private static final byte[] DEFAULT_FORMAT_VERSION_BYTES =
+            getBytes(getBits(DEFAULT_FORMAT_VERSION, FORMAT_VERSION_BITS));
+
+    @Test
+    public void testBinaryString_serializeEmptyRule() throws Exception {
+        Rule rule = null;
+        RuleSerializer binarySerializer = new RuleBinarySerializer();
+
+        assertExpectException(
+                RuleSerializeException.class,
+                /* expectedExceptionMessageRegex= */ "Null rule can not be serialized",
+                () ->
+                        binarySerializer.serialize(
+                                Collections.singletonList(rule),
+                                /* formatVersion= */ Optional.empty()));
+    }
+
+    @Test
+    public void testBinaryStream_serializeValidCompoundFormula() throws Exception {
+        String packageName = "com.test.app";
+        Rule rule =
+                new Rule(
+                        new CompoundFormula(
+                                CompoundFormula.NOT,
+                                Collections.singletonList(
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.PACKAGE_NAME,
+                                                packageName,
+                                                /* isHashedValue= */ false))),
+                        Rule.DENY);
+        RuleSerializer binarySerializer = new RuleBinarySerializer();
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        String expectedBits =
+                START_BIT
+                        + COMPOUND_FORMULA_START_BITS
+                        + NOT
+                        + ATOMIC_FORMULA_START_BITS
+                        + PACKAGE_NAME
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(packageName.length(), VALUE_SIZE_BITS)
+                        + getValueBits(packageName)
+                        + COMPOUND_FORMULA_END_BITS
+                        + DENY
+                        + END_BIT;
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES);
+        byteArrayOutputStream.write(getBytes(expectedBits));
+        byte[] expectedRules = byteArrayOutputStream.toByteArray();
+
+        binarySerializer.serialize(
+                Collections.singletonList(rule),
+                /* formatVersion= */ Optional.empty(),
+                outputStream);
+
+        byte[] actualRules = outputStream.toByteArray();
+        assertThat(actualRules).isEqualTo(expectedRules);
+    }
+
+    @Test
+    public void testBinaryString_serializeValidCompoundFormula_notConnector() throws Exception {
+        String packageName = "com.test.app";
+        Rule rule =
+                new Rule(
+                        new CompoundFormula(
+                                CompoundFormula.NOT,
+                                Collections.singletonList(
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.PACKAGE_NAME,
+                                                packageName,
+                                                /* isHashedValue= */ false))),
+                        Rule.DENY);
+        RuleSerializer binarySerializer = new RuleBinarySerializer();
+        String expectedBits =
+                START_BIT
+                        + COMPOUND_FORMULA_START_BITS
+                        + NOT
+                        + ATOMIC_FORMULA_START_BITS
+                        + PACKAGE_NAME
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(packageName.length(), VALUE_SIZE_BITS)
+                        + getValueBits(packageName)
+                        + COMPOUND_FORMULA_END_BITS
+                        + DENY
+                        + END_BIT;
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES);
+        byteArrayOutputStream.write(getBytes(expectedBits));
+        byte[] expectedRules = byteArrayOutputStream.toByteArray();
+
+        byte[] actualRules =
+                binarySerializer.serialize(
+                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
+
+        assertThat(actualRules).isEqualTo(expectedRules);
+    }
+
+    @Test
+    public void testBinaryString_serializeValidCompoundFormula_andConnector() throws Exception {
+        String packageName = "com.test.app";
+        String appCertificate = "test_cert";
+        Rule rule =
+                new Rule(
+                        new CompoundFormula(
+                                CompoundFormula.AND,
+                                Arrays.asList(
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.PACKAGE_NAME,
+                                                packageName,
+                                                /* isHashedValue= */ false),
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.APP_CERTIFICATE,
+                                                appCertificate,
+                                                /* isHashedValue= */ false))),
+                        Rule.DENY);
+        RuleSerializer binarySerializer = new RuleBinarySerializer();
+        String expectedBits =
+                START_BIT
+                        + COMPOUND_FORMULA_START_BITS
+                        + AND
+                        + ATOMIC_FORMULA_START_BITS
+                        + PACKAGE_NAME
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(packageName.length(), VALUE_SIZE_BITS)
+                        + getValueBits(packageName)
+                        + ATOMIC_FORMULA_START_BITS
+                        + APP_CERTIFICATE
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(appCertificate.length(), VALUE_SIZE_BITS)
+                        + getValueBits(appCertificate)
+                        + COMPOUND_FORMULA_END_BITS
+                        + DENY
+                        + END_BIT;
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES);
+        byteArrayOutputStream.write(getBytes(expectedBits));
+        byte[] expectedRules = byteArrayOutputStream.toByteArray();
+
+        byte[] actualRules =
+                binarySerializer.serialize(
+                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
+
+        assertThat(actualRules).isEqualTo(expectedRules);
+    }
+
+    @Test
+    public void testBinaryString_serializeValidCompoundFormula_orConnector() throws Exception {
+        String packageName = "com.test.app";
+        String appCertificate = "test_cert";
+        Rule rule =
+                new Rule(
+                        new CompoundFormula(
+                                CompoundFormula.OR,
+                                Arrays.asList(
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.PACKAGE_NAME,
+                                                packageName,
+                                                /* isHashedValue= */ false),
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.APP_CERTIFICATE,
+                                                appCertificate,
+                                                /* isHashedValue= */ false))),
+                        Rule.DENY);
+        RuleSerializer binarySerializer = new RuleBinarySerializer();
+        String expectedBits =
+                START_BIT
+                        + COMPOUND_FORMULA_START_BITS
+                        + OR
+                        + ATOMIC_FORMULA_START_BITS
+                        + PACKAGE_NAME
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(packageName.length(), VALUE_SIZE_BITS)
+                        + getValueBits(packageName)
+                        + ATOMIC_FORMULA_START_BITS
+                        + APP_CERTIFICATE
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(appCertificate.length(), VALUE_SIZE_BITS)
+                        + getValueBits(appCertificate)
+                        + COMPOUND_FORMULA_END_BITS
+                        + DENY
+                        + END_BIT;
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES);
+        byteArrayOutputStream.write(getBytes(expectedBits));
+        byte[] expectedRules = byteArrayOutputStream.toByteArray();
+
+        byte[] actualRules =
+                binarySerializer.serialize(
+                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
+
+        assertThat(actualRules).isEqualTo(expectedRules);
+    }
+
+    @Test
+    public void testBinaryString_serializeValidAtomicFormula_stringValue() throws Exception {
+        String packageName = "com.test.app";
+        Rule rule =
+                new Rule(
+                        new AtomicFormula.StringAtomicFormula(
+                                AtomicFormula.PACKAGE_NAME,
+                                packageName,
+                                /* isHashedValue= */ false),
+                        Rule.DENY);
+        RuleSerializer binarySerializer = new RuleBinarySerializer();
+        String expectedBits =
+                START_BIT
+                        + ATOMIC_FORMULA_START_BITS
+                        + PACKAGE_NAME
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(packageName.length(), VALUE_SIZE_BITS)
+                        + getValueBits(packageName)
+                        + DENY
+                        + END_BIT;
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES);
+        byteArrayOutputStream.write(getBytes(expectedBits));
+        byte[] expectedRules = byteArrayOutputStream.toByteArray();
+
+        byte[] actualRules =
+                binarySerializer.serialize(
+                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
+
+        assertThat(actualRules).isEqualTo(expectedRules);
+    }
+
+    @Test
+    public void testBinaryString_serializeValidAtomicFormula_integerValue() throws Exception {
+        String versionCode = "1";
+        Rule rule =
+                new Rule(
+                        new AtomicFormula.IntAtomicFormula(
+                                AtomicFormula.VERSION_CODE,
+                                AtomicFormula.EQ,
+                                Integer.parseInt(versionCode)),
+                        Rule.DENY);
+        RuleSerializer binarySerializer = new RuleBinarySerializer();
+        String expectedBits =
+                START_BIT
+                        + ATOMIC_FORMULA_START_BITS
+                        + VERSION_CODE
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(versionCode.length(), VALUE_SIZE_BITS)
+                        + getValueBits(versionCode)
+                        + DENY
+                        + END_BIT;
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES);
+        byteArrayOutputStream.write(getBytes(expectedBits));
+        byte[] expectedRules = byteArrayOutputStream.toByteArray();
+
+        byte[] actualRules =
+                binarySerializer.serialize(
+                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
+
+        assertThat(actualRules).isEqualTo(expectedRules);
+    }
+
+    @Test
+    public void testBinaryString_serializeValidAtomicFormula_booleanValue() throws Exception {
+        String preInstalled = "1";
+        Rule rule =
+                new Rule(
+                        new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true),
+                        Rule.DENY);
+        RuleSerializer binarySerializer = new RuleBinarySerializer();
+        String expectedBits =
+                START_BIT
+                        + ATOMIC_FORMULA_START_BITS
+                        + PRE_INSTALLED
+                        + EQ
+                        + IS_NOT_HASHED
+                        + getBits(preInstalled.length(), VALUE_SIZE_BITS)
+                        + getValueBits(preInstalled)
+                        + DENY
+                        + END_BIT;
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES);
+        byteArrayOutputStream.write(getBytes(expectedBits));
+        byte[] expectedRules = byteArrayOutputStream.toByteArray();
+
+        byte[] actualRules =
+                binarySerializer.serialize(
+                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
+
+        assertThat(actualRules).isEqualTo(expectedRules);
+    }
+
+    @Test
+    public void testBinaryString_serializeInvalidFormulaType() throws Exception {
+        Formula invalidFormula = getInvalidFormula();
+        Rule rule = new Rule(invalidFormula, Rule.DENY);
+        RuleSerializer binarySerializer = new RuleBinarySerializer();
+
+        assertExpectException(
+                RuleSerializeException.class,
+                /* expectedExceptionMessageRegex= */ "Invalid formula type",
+                () ->
+                        binarySerializer.serialize(
+                                Collections.singletonList(rule),
+                                /* formatVersion= */ Optional.empty()));
+    }
+
+    @Test
+    public void testBinaryString_serializeFormatVersion() throws Exception {
+        int formatVersion = 1;
+        RuleSerializer binarySerializer = new RuleBinarySerializer();
+        String expectedBits = getBits(formatVersion, FORMAT_VERSION_BITS);
+        byte[] expectedRules = getBytes(expectedBits);
+
+        byte[] actualRules =
+                binarySerializer.serialize(
+                        Collections.emptyList(), /* formatVersion= */ Optional.of(formatVersion));
+
+        assertThat(actualRules).isEqualTo(expectedRules);
+    }
+
+    private static Formula getInvalidFormula() {
+        return new Formula() {
+            @Override
+            public boolean isSatisfied(AppInstallMetadata appInstallMetadata) {
+                return false;
+            }
+
+            @Override
+            public int getTag() {
+                return 0;
+            }
+
+            @Override
+            public int hashCode() {
+                return super.hashCode();
+            }
+
+            @Override
+            public boolean equals(Object obj) {
+                return super.equals(obj);
+            }
+
+            @NonNull
+            @Override
+            protected Object clone() throws CloneNotSupportedException {
+                return super.clone();
+            }
+
+            @Override
+            public String toString() {
+                return super.toString();
+            }
+
+            @Override
+            protected void finalize() throws Throwable {
+                super.finalize();
+            }
+        };
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexTypeIdentifierTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexTypeIdentifierTest.java
new file mode 100644
index 0000000..18b91b0
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexTypeIdentifierTest.java
@@ -0,0 +1,218 @@
+/*
+ * 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.integrity.serializer;
+
+import static com.android.server.testutils.TestUtils.assertExpectException;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.integrity.AppInstallMetadata;
+import android.content.integrity.AtomicFormula;
+import android.content.integrity.CompoundFormula;
+import android.content.integrity.Formula;
+import android.content.integrity.Rule;
+
+import androidx.annotation.NonNull;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Arrays;
+
+/** Unit tests for {@link RuleIndexTypeIdentifier}. */
+@RunWith(JUnit4.class)
+public class RuleIndexTypeIdentifierTest {
+
+    @Test
+    public void getIndexType_nullRule() {
+        Rule rule = null;
+
+        assertExpectException(
+                IllegalArgumentException.class,
+                /* expectedExceptionMessageRegex= */
+                "Indexing type cannot be determined for null rule.",
+                () -> RuleIndexTypeIdentifier.getIndexType(rule));
+    }
+
+    @Test
+    public void getIndexType_invalidFormula() {
+        Rule rule = new Rule(getInvalidFormula(), Rule.DENY);
+
+        assertExpectException(
+                IllegalArgumentException.class,
+                /* expectedExceptionMessageRegex= */ "Invalid formula tag type.",
+                () -> RuleIndexTypeIdentifier.getIndexType(rule));
+    }
+
+    @Test
+    public void getIndexType_ruleContainingPackageNameFormula() {
+        String packageName = "com.test.app";
+        String installerName = "com.test.installer";
+        Rule rule =
+                new Rule(
+                        new CompoundFormula(
+                                CompoundFormula.AND,
+                                Arrays.asList(
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.PACKAGE_NAME,
+                                                packageName,
+                                                /* isHashedValue= */ false),
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.INSTALLER_NAME,
+                                                installerName,
+                                                /* isHashedValue= */ false))),
+                        Rule.DENY);
+
+        assertThat(RuleIndexTypeIdentifier.getIndexType(rule))
+                .isEqualTo(RuleIndexTypeIdentifier.PACKAGE_NAME_INDEXED);
+    }
+
+    @Test
+    public void getIndexType_ruleContainingAppCertificateFormula() {
+        String appCertificate = "cert1";
+        String installerName = "com.test.installer";
+        Rule rule =
+                new Rule(
+                        new CompoundFormula(
+                                CompoundFormula.AND,
+                                Arrays.asList(
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.APP_CERTIFICATE,
+                                                appCertificate,
+                                                /* isHashedValue= */ false),
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.INSTALLER_NAME,
+                                                installerName,
+                                                /* isHashedValue= */ false))),
+                        Rule.DENY);
+
+        assertThat(RuleIndexTypeIdentifier.getIndexType(rule))
+                .isEqualTo(RuleIndexTypeIdentifier.APP_CERTIFICATE_INDEXED);
+    }
+
+    @Test
+    public void getIndexType_ruleWithUnindexedCompoundFormula() {
+        String installerCertificate = "cert1";
+        String installerName = "com.test.installer";
+        Rule rule =
+                new Rule(
+                        new CompoundFormula(
+                                CompoundFormula.AND,
+                                Arrays.asList(
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.INSTALLER_CERTIFICATE,
+                                                installerCertificate,
+                                                /* isHashedValue= */ false),
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.INSTALLER_NAME,
+                                                installerName,
+                                                /* isHashedValue= */ false))),
+                        Rule.DENY);
+
+        assertThat(RuleIndexTypeIdentifier.getIndexType(rule))
+                .isEqualTo(RuleIndexTypeIdentifier.NOT_INDEXED);
+    }
+
+    @Test
+    public void getIndexType_rulContainingCompoundFormulaWithIntAndBoolean() {
+        int appVersion = 12;
+        Rule rule =
+                new Rule(
+                        new CompoundFormula(
+                                CompoundFormula.AND,
+                                Arrays.asList(
+                                        new AtomicFormula.BooleanAtomicFormula(
+                                                AtomicFormula.PRE_INSTALLED,
+                                                /* booleanValue= */ true),
+                                        new AtomicFormula.IntAtomicFormula(
+                                                AtomicFormula.VERSION_CODE,
+                                                AtomicFormula.EQ,
+                                                appVersion))),
+                        Rule.DENY);
+
+        assertThat(RuleIndexTypeIdentifier.getIndexType(rule))
+                .isEqualTo(RuleIndexTypeIdentifier.NOT_INDEXED);
+    }
+
+    @Test
+    public void getIndexType_negatedRuleContainingPackageNameFormula() {
+        String packageName = "com.test.app";
+        String installerName = "com.test.installer";
+        Rule rule =
+                new Rule(
+                        new CompoundFormula(
+                                CompoundFormula.NOT,
+                                Arrays.asList(
+                                        new CompoundFormula(
+                                                CompoundFormula.AND,
+                                                Arrays.asList(
+                                                        new AtomicFormula.StringAtomicFormula(
+                                                                AtomicFormula.PACKAGE_NAME,
+                                                                packageName,
+                                                                /* isHashedValue= */ false),
+                                                        new AtomicFormula.StringAtomicFormula(
+                                                                AtomicFormula.INSTALLER_NAME,
+                                                                installerName,
+                                                                /* isHashedValue= */ false))))),
+                        Rule.DENY);
+
+        assertThat(RuleIndexTypeIdentifier.getIndexType(rule))
+                .isEqualTo(RuleIndexTypeIdentifier.NOT_INDEXED);
+    }
+
+    private Formula getInvalidFormula() {
+        return new Formula() {
+            @Override
+            public boolean isSatisfied(AppInstallMetadata appInstallMetadata) {
+                return false;
+            }
+
+            @Override
+            public int getTag() {
+                return 4;
+            }
+
+            @Override
+            public int hashCode() {
+                return super.hashCode();
+            }
+
+            @Override
+            public boolean equals(Object obj) {
+                return super.equals(obj);
+            }
+
+            @NonNull
+            @Override
+            protected Object clone() throws CloneNotSupportedException {
+                return super.clone();
+            }
+
+            @Override
+            public String toString() {
+                return super.toString();
+            }
+
+            @Override
+            protected void finalize() throws Throwable {
+                super.finalize();
+            }
+        };
+    }
+}
+
diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java
index 40e89ba..ad74901 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java
@@ -34,10 +34,12 @@
 
 import java.io.ByteArrayOutputStream;
 import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.Optional;
 
 @RunWith(JUnit4.class)
 public class RuleXmlSerializerTest {
@@ -48,101 +50,145 @@
         RuleSerializer xmlSerializer = new RuleXmlSerializer();
         String expectedRules = "<RL />";
 
-        String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+        byte[] actualRules =
+                xmlSerializer.serialize(
+                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
 
-        assertEquals(expectedRules, actualRules);
+        assertEquals(expectedRules, new String(actualRules, StandardCharsets.UTF_8));
     }
 
     @Test
     public void testXmlString_serializeMultipleRules_oneEmpty() throws Exception {
         Rule rule1 = null;
-        Rule rule2 = new Rule(
-                new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test",
-                        /* isHashedValue= */ false),
-                Rule.DENY);
+        Rule rule2 =
+                new Rule(
+                        new AtomicFormula.StringAtomicFormula(
+                                AtomicFormula.PACKAGE_NAME,
+                                "com.app.test",
+                                /* isHashedValue= */ false),
+                        Rule.DENY);
         RuleSerializer xmlSerializer = new RuleXmlSerializer();
         Map<String, String> packageNameAttrs = new LinkedHashMap<>();
         packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
         packageNameAttrs.put("V", "com.app.test");
         packageNameAttrs.put("H", "false");
-        String expectedRules = "<RL>"
-                + generateTagWithAttribute(/* tag= */ "R",
-                    Collections.singletonMap("E", String.valueOf(Rule.DENY)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
-                + "</R>"
-                + "</RL>";
+        String expectedRules =
+                "<RL>"
+                        + generateTagWithAttribute(
+                                /* tag= */ "R",
+                                Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+                        + "</R>"
+                        + "</RL>";
 
-        String actualRules = xmlSerializer.serialize(Arrays.asList(rule1, rule2));
+        byte[] actualRules =
+                xmlSerializer.serialize(
+                        Arrays.asList(rule1, rule2), /* formatVersion= */ Optional.empty());
 
-        assertEquals(expectedRules, actualRules);
+        assertEquals(expectedRules, new String(actualRules, StandardCharsets.UTF_8));
     }
 
     @Test
-    public void testXmlStream_serializeValidOpenFormula() throws Exception {
-        Rule rule = new Rule(new CompoundFormula(CompoundFormula.NOT,
-                Collections.singletonList(
-                        new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
-                                "com.app.test", /* isHashedValue= */ false))), Rule.DENY);
+    public void testXmlStream_serializeValidCompoundFormula() throws Exception {
+        Rule rule =
+                new Rule(
+                        new CompoundFormula(
+                                CompoundFormula.NOT,
+                                Collections.singletonList(
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.PACKAGE_NAME,
+                                                "com.app.test",
+                                                /* isHashedValue= */ false))),
+                        Rule.DENY);
         RuleSerializer xmlSerializer = new RuleXmlSerializer();
         OutputStream outputStream = new ByteArrayOutputStream();
         Map<String, String> packageNameAttrs = new LinkedHashMap<>();
         packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
         packageNameAttrs.put("V", "com.app.test");
         packageNameAttrs.put("H", "false");
-        String expectedRules = "<RL>"
-                + generateTagWithAttribute(/* tag= */ "R",
-                    Collections.singletonMap("E", String.valueOf(Rule.DENY)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "OF",
-                    Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
-                + "</OF>"
-                + "</R>"
-                + "</RL>";
+        String expectedRules =
+                "<RL>"
+                        + generateTagWithAttribute(
+                                /* tag= */ "R",
+                                Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "OF",
+                                Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+                        + "</OF>"
+                        + "</R>"
+                        + "</RL>";
 
-        xmlSerializer.serialize(Collections.singletonList(rule), outputStream);
+        xmlSerializer.serialize(
+                Collections.singletonList(rule),
+                /* formatVersion= */ Optional.empty(),
+                outputStream);
 
-        String actualRules = outputStream.toString();
-        assertEquals(expectedRules, actualRules);
+        byte[] actualRules = outputStream.toString().getBytes(StandardCharsets.UTF_8);
+        assertEquals(expectedRules, new String(actualRules, StandardCharsets.UTF_8));
     }
 
     @Test
-    public void testXmlString_serializeValidOpenFormula_notConnector() throws Exception {
-        Rule rule = new Rule(new CompoundFormula(CompoundFormula.NOT,
-                Collections.singletonList(
-                        new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
-                                "com.app.test", /* isHashedValue= */ false))), Rule.DENY);
+    public void testXmlString_serializeValidCompoundFormula_notConnector() throws Exception {
+        Rule rule =
+                new Rule(
+                        new CompoundFormula(
+                                CompoundFormula.NOT,
+                                Collections.singletonList(
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.PACKAGE_NAME,
+                                                "com.app.test",
+                                                /* isHashedValue= */ false))),
+                        Rule.DENY);
         RuleSerializer xmlSerializer = new RuleXmlSerializer();
         Map<String, String> packageNameAttrs = new LinkedHashMap<>();
         packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
         packageNameAttrs.put("V", "com.app.test");
         packageNameAttrs.put("H", "false");
-        String expectedRules = "<RL>"
-                + generateTagWithAttribute(/* tag= */ "R",
-                    Collections.singletonMap("E", String.valueOf(Rule.DENY)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "OF",
-                    Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
-                + "</OF>"
-                + "</R>"
-                + "</RL>";
+        String expectedRules =
+                "<RL>"
+                        + generateTagWithAttribute(
+                                /* tag= */ "R",
+                                Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "OF",
+                                Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+                        + "</OF>"
+                        + "</R>"
+                        + "</RL>";
 
-        String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+        byte[] actualRules =
+                xmlSerializer.serialize(
+                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
 
-        assertEquals(expectedRules, actualRules);
+        assertEquals(expectedRules, new String(actualRules, StandardCharsets.UTF_8));
     }
 
     @Test
-    public void testXmlString_serializeValidOpenFormula_andConnector() throws Exception {
-        Rule rule = new Rule(new CompoundFormula(CompoundFormula.AND,
-                Arrays.asList(new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
-                                "com.app.test", /* isHashedValue= */ false),
-                        new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE,
-                                "test_cert", /* isHashedValue= */ false))), Rule.DENY);
+    public void testXmlString_serializeValidCompoundFormula_andConnector() throws Exception {
+        Rule rule =
+                new Rule(
+                        new CompoundFormula(
+                                CompoundFormula.AND,
+                                Arrays.asList(
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.PACKAGE_NAME,
+                                                "com.app.test",
+                                                /* isHashedValue= */ false),
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.APP_CERTIFICATE,
+                                                "test_cert",
+                                                /* isHashedValue= */ false))),
+                        Rule.DENY);
         RuleSerializer xmlSerializer = new RuleXmlSerializer();
         Map<String, String> packageNameAttrs = new LinkedHashMap<>();
         packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
@@ -152,31 +198,47 @@
         appCertificateAttrs.put("K", String.valueOf(AtomicFormula.APP_CERTIFICATE));
         appCertificateAttrs.put("V", "test_cert");
         appCertificateAttrs.put("H", "false");
-        String expectedRules = "<RL>"
-                + generateTagWithAttribute(/* tag= */ "R",
-                    Collections.singletonMap("E", String.valueOf(Rule.DENY)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "OF",
-                    Collections.singletonMap("C", String.valueOf(CompoundFormula.AND)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
-                + generateTagWithAttribute(/* tag= */ "AF", appCertificateAttrs, /* closed= */ true)
-                + "</OF>"
-                + "</R>"
-                + "</RL>";
+        String expectedRules =
+                "<RL>"
+                        + generateTagWithAttribute(
+                                /* tag= */ "R",
+                                Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "OF",
+                                Collections.singletonMap("C", String.valueOf(CompoundFormula.AND)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+                        + generateTagWithAttribute(
+                                /* tag= */ "AF", appCertificateAttrs, /* closed= */ true)
+                        + "</OF>"
+                        + "</R>"
+                        + "</RL>";
 
-        String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+        byte[] actualRules =
+                xmlSerializer.serialize(
+                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
 
-        assertEquals(expectedRules, actualRules);
+        assertEquals(expectedRules, new String(actualRules, StandardCharsets.UTF_8));
     }
 
     @Test
-    public void testXmlString_serializeValidOpenFormula_orConnector() throws Exception {
-        Rule rule = new Rule(new CompoundFormula(CompoundFormula.OR,
-                Arrays.asList(new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
-                                "com.app.test", /* isHashedValue= */ false),
-                        new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE,
-                                "test_cert", /* isHashedValue= */ false))), Rule.DENY);
+    public void testXmlString_serializeValidCompoundFormula_orConnector() throws Exception {
+        Rule rule =
+                new Rule(
+                        new CompoundFormula(
+                                CompoundFormula.OR,
+                                Arrays.asList(
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.PACKAGE_NAME,
+                                                "com.app.test",
+                                                /* isHashedValue= */ false),
+                                        new AtomicFormula.StringAtomicFormula(
+                                                AtomicFormula.APP_CERTIFICATE,
+                                                "test_cert",
+                                                /* isHashedValue= */ false))),
+                        Rule.DENY);
         RuleSerializer xmlSerializer = new RuleXmlSerializer();
         Map<String, String> packageNameAttrs = new LinkedHashMap<>();
         packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
@@ -186,91 +248,119 @@
         appCertificateAttrs.put("K", String.valueOf(AtomicFormula.APP_CERTIFICATE));
         appCertificateAttrs.put("V", "test_cert");
         appCertificateAttrs.put("H", "false");
-        String expectedRules = "<RL>"
-                + generateTagWithAttribute(/* tag= */ "R",
-                    Collections.singletonMap("E", String.valueOf(Rule.DENY)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "OF",
-                    Collections.singletonMap("C", String.valueOf(CompoundFormula.OR)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
-                + generateTagWithAttribute(/* tag= */ "AF", appCertificateAttrs, /* closed= */ true)
-                + "</OF>"
-                + "</R>"
-                + "</RL>";
+        String expectedRules =
+                "<RL>"
+                        + generateTagWithAttribute(
+                                /* tag= */ "R",
+                                Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "OF",
+                                Collections.singletonMap("C", String.valueOf(CompoundFormula.OR)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+                        + generateTagWithAttribute(
+                                /* tag= */ "AF", appCertificateAttrs, /* closed= */ true)
+                        + "</OF>"
+                        + "</R>"
+                        + "</RL>";
 
-        String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+        byte[] actualRules =
+                xmlSerializer.serialize(
+                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
 
-        assertEquals(expectedRules, actualRules);
+        assertEquals(expectedRules, new String(actualRules, StandardCharsets.UTF_8));
     }
 
     @Test
     public void testXmlString_serializeValidAtomicFormula_stringValue() throws Exception {
-        Rule rule = new Rule(
-                new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test",
-                        /* isHashedValue= */ false),
-                Rule.DENY);
+        Rule rule =
+                new Rule(
+                        new AtomicFormula.StringAtomicFormula(
+                                AtomicFormula.PACKAGE_NAME,
+                                "com.app.test",
+                                /* isHashedValue= */ false),
+                        Rule.DENY);
         RuleSerializer xmlSerializer = new RuleXmlSerializer();
         Map<String, String> packageNameAttrs = new LinkedHashMap<>();
         packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
         packageNameAttrs.put("V", "com.app.test");
         packageNameAttrs.put("H", "false");
-        String expectedRules = "<RL>"
-                + generateTagWithAttribute(/* tag= */ "R",
-                    Collections.singletonMap("E", String.valueOf(Rule.DENY)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
-                + "</R>"
-                + "</RL>";
+        String expectedRules =
+                "<RL>"
+                        + generateTagWithAttribute(
+                                /* tag= */ "R",
+                                Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+                        + "</R>"
+                        + "</RL>";
 
-        String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+        byte[] actualRules =
+                xmlSerializer.serialize(
+                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
 
-        assertEquals(expectedRules, actualRules);
+        assertEquals(expectedRules, new String(actualRules, StandardCharsets.UTF_8));
     }
 
     @Test
     public void testXmlString_serializeValidAtomicFormula_integerValue() throws Exception {
-        Rule rule = new Rule(
-                new AtomicFormula.IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1),
-                Rule.DENY);
+        Rule rule =
+                new Rule(
+                        new AtomicFormula.IntAtomicFormula(
+                                AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1),
+                        Rule.DENY);
         RuleSerializer xmlSerializer = new RuleXmlSerializer();
         Map<String, String> versionCodeAttrs = new LinkedHashMap<>();
         versionCodeAttrs.put("K", String.valueOf(AtomicFormula.VERSION_CODE));
         versionCodeAttrs.put("O", String.valueOf(AtomicFormula.EQ));
         versionCodeAttrs.put("V", "1");
-        String expectedRules = "<RL>"
-                + generateTagWithAttribute(/* tag= */ "R",
-                    Collections.singletonMap("E", String.valueOf(Rule.DENY)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "AF", versionCodeAttrs, /* closed= */ true)
-                + "</R>"
-                + "</RL>";
+        String expectedRules =
+                "<RL>"
+                        + generateTagWithAttribute(
+                                /* tag= */ "R",
+                                Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "AF", versionCodeAttrs, /* closed= */ true)
+                        + "</R>"
+                        + "</RL>";
 
-        String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+        byte[] actualRules =
+                xmlSerializer.serialize(
+                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
 
-        assertEquals(expectedRules, actualRules);
+        assertEquals(expectedRules, new String(actualRules, StandardCharsets.UTF_8));
     }
 
     @Test
     public void testXmlString_serializeValidAtomicFormula_booleanValue() throws Exception {
-        Rule rule = new Rule(
-                new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true),
-                Rule.DENY);
+        Rule rule =
+                new Rule(
+                        new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true),
+                        Rule.DENY);
         RuleSerializer xmlSerializer = new RuleXmlSerializer();
         Map<String, String> preInstalledAttrs = new LinkedHashMap<>();
         preInstalledAttrs.put("K", String.valueOf(AtomicFormula.PRE_INSTALLED));
         preInstalledAttrs.put("V", "true");
-        String expectedRules = "<RL>"
-                + generateTagWithAttribute(/* tag= */ "R",
-                    Collections.singletonMap("E", String.valueOf(Rule.DENY)),
-                        /* closed= */ false)
-                + generateTagWithAttribute(/* tag= */ "AF", preInstalledAttrs, /* closed= */ true)
-                + "</R>"
-                + "</RL>";
+        String expectedRules =
+                "<RL>"
+                        + generateTagWithAttribute(
+                                /* tag= */ "R",
+                                Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+                                /* closed= */ false)
+                        + generateTagWithAttribute(
+                                /* tag= */ "AF", preInstalledAttrs, /* closed= */ true)
+                        + "</R>"
+                        + "</RL>";
 
-        String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+        byte[] actualRules =
+                xmlSerializer.serialize(
+                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
 
-        assertEquals(expectedRules, actualRules);
+        assertEquals(expectedRules, new String(actualRules, StandardCharsets.UTF_8));
     }
 
     @Test
@@ -282,11 +372,14 @@
         assertExpectException(
                 RuleSerializeException.class,
                 /* expectedExceptionMessageRegex */ "Invalid formula type",
-                () -> xmlSerializer.serialize(Collections.singletonList(rule)));
+                () ->
+                        xmlSerializer.serialize(
+                                Collections.singletonList(rule),
+                                /* formatVersion= */ Optional.empty()));
     }
 
-    private String generateTagWithAttribute(String tag, Map<String, String> attributeValues,
-            boolean closed) {
+    private String generateTagWithAttribute(
+            String tag, Map<String, String> attributeValues, boolean closed) {
         StringBuilder res = new StringBuilder("<");
         res.append(tag);
         for (String attribute : attributeValues.keySet()) {
diff --git a/services/tests/servicestests/src/com/android/server/integrity/utils/TestUtils.java b/services/tests/servicestests/src/com/android/server/integrity/utils/TestUtils.java
new file mode 100644
index 0000000..e54410b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/integrity/utils/TestUtils.java
@@ -0,0 +1,48 @@
+/*
+ * 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.integrity.utils;
+
+public class TestUtils {
+
+    public static String getBits(int component, int numOfBits) {
+        return String.format("%" + numOfBits + "s", Integer.toBinaryString(component))
+                .replace(' ', '0');
+    }
+
+    public static String getValueBits(String value) {
+        StringBuilder stringBuilder = new StringBuilder();
+        for (byte valueByte : value.getBytes()) {
+            stringBuilder.append(getBits(valueByte, /* numOfBits= */ 8));
+        }
+        return stringBuilder.toString();
+    }
+
+    public static byte[] getBytes(String bits) {
+        int bitStringSize = bits.length();
+        int numOfBytes = bitStringSize / 8;
+        if (bitStringSize % 8 != 0) {
+            numOfBytes++;
+        }
+        byte[] bytes = new byte[numOfBytes];
+        for (int i = 0; i < bits.length(); i++) {
+            if (bits.charAt(i) == '1') {
+                bytes[i / 8] |= 1 << (7 - (i % 8));
+            }
+        }
+        return bytes;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java
deleted file mode 100644
index d1c2fd0..0000000
--- a/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java
+++ /dev/null
@@ -1,151 +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.server.locksettings;
-
-import static com.android.server.testutils.TestUtils.assertExpectException;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.os.RemoteException;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.widget.LockscreenCredential;
-import com.android.internal.widget.VerifyCredentialResponse;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-
-import java.util.ArrayList;
-
-/**
- * Run the synthetic password tests with caching enabled.
- *
- * By default, those tests run without caching. Untrusted credential reset depends on caching so
- * this class included those tests.
- */
-@SmallTest
-@Presubmit
-@RunWith(AndroidJUnit4.class)
-public class CachedSyntheticPasswordTests extends SyntheticPasswordTests {
-
-    @Before
-    public void enableSpCache() throws Exception {
-        enableSpCaching(true);
-    }
-
-    private void enableSpCaching(boolean enable) {
-        when(mDevicePolicyManagerInternal
-                .canUserHaveUntrustedCredentialReset(anyInt())).thenReturn(enable);
-    }
-
-    @Test
-    public void testSyntheticPasswordClearCredentialUntrusted() throws RemoteException {
-        final LockscreenCredential password = newPassword("password");
-        final LockscreenCredential newPassword = newPassword("newpassword");
-
-        initializeCredentialUnderSP(password, PRIMARY_USER_ID);
-        long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
-        // clear password
-        mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID, true);
-        assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
-
-        // set a new password
-        mService.setLockCredential(newPassword, nonePassword(), PRIMARY_USER_ID,
-                false);
-        assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
-                newPassword, 0, PRIMARY_USER_ID)
-                        .getResponseCode());
-        assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
-    }
-
-    @Test
-    public void testSyntheticPasswordChangeCredentialUntrusted() throws RemoteException {
-        final LockscreenCredential password = newPassword("password");
-        final LockscreenCredential newPassword = newPassword("newpassword");
-
-        initializeCredentialUnderSP(password, PRIMARY_USER_ID);
-        long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
-        // Untrusted change password
-        mService.setLockCredential(newPassword, nonePassword(), PRIMARY_USER_ID,
-                true);
-        assertNotEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
-        assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
-
-        // Verify the password
-        assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
-                newPassword, 0, PRIMARY_USER_ID).getResponseCode());
-    }
-
-    @Test
-    public void testUntrustedCredentialChangeMaintainsAuthSecret() throws RemoteException {
-        final LockscreenCredential password = newPassword("password");
-        final LockscreenCredential newPassword = newPassword("newpassword");
-
-        initializeCredentialUnderSP(password, PRIMARY_USER_ID);
-        // Untrusted change password
-        mService.setLockCredential(newPassword, nonePassword(), PRIMARY_USER_ID,
-                true);
-
-        // Verify the password
-        assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
-                newPassword, 0, PRIMARY_USER_ID)
-                        .getResponseCode());
-
-        // Ensure the same secret was passed each time
-        ArgumentCaptor<ArrayList<Byte>> secret = ArgumentCaptor.forClass(ArrayList.class);
-        verify(mAuthSecretService, atLeastOnce()).primaryUserCredential(secret.capture());
-        assertEquals(1, secret.getAllValues().stream().distinct().count());
-    }
-
-    @Test
-    public void testUntrustedCredentialChangeBlockedIfSpNotCached() throws RemoteException {
-        final LockscreenCredential password = newPassword("password");
-        final LockscreenCredential newPassword = newPassword("newpassword");
-
-        // Disable caching for this test
-        enableSpCaching(false);
-
-        initializeCredentialUnderSP(password, PRIMARY_USER_ID);
-        flushHandlerTasks();
-
-        long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
-        // Untrusted change password
-        assertExpectException(
-                IllegalStateException.class,
-                /* messageRegex= */ "Untrusted credential reset not possible without cached SP",
-                () -> mService.setLockCredential(newPassword, nonePassword(),
-                        PRIMARY_USER_ID, true));
-        assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
-
-        // Verify the new password doesn't work but the old one still does
-        assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, mService.verifyCredential(
-                newPassword, 0, PRIMARY_USER_ID)
-                        .getResponseCode());
-        assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
-                password, 0, PRIMARY_USER_ID)
-                        .getResponseCode());
-    }
-
-}
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 8c8edfa..abfda77 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
@@ -93,7 +93,7 @@
         initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("password"), sid);
 
         assertFalse(mService.setLockCredential(newPassword("newpwd"), newPassword("badpwd"),
-                    PRIMARY_USER_ID, false));
+                    PRIMARY_USER_ID));
         assertVerifyCredentials(PRIMARY_USER_ID, newPassword("password"), sid);
     }
 
@@ -101,7 +101,7 @@
     public void testClearPasswordPrimaryUser() throws RemoteException {
         initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("password"), 1234);
         assertTrue(mService.setLockCredential(nonePassword(), newPassword("password"),
-                PRIMARY_USER_ID, false));
+                PRIMARY_USER_ID));
         assertEquals(CREDENTIAL_TYPE_NONE, mService.getCredentialType(PRIMARY_USER_ID));
         assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
     }
@@ -111,7 +111,7 @@
         final LockscreenCredential firstUnifiedPassword = newPassword("pwd-1");
         final LockscreenCredential secondUnifiedPassword = newPassword("pwd-2");
         assertTrue(mService.setLockCredential(firstUnifiedPassword,
-                nonePassword(), PRIMARY_USER_ID, false));
+                nonePassword(), PRIMARY_USER_ID));
         mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
         final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
         final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
@@ -146,15 +146,14 @@
         mStorageManager.setIgnoreBadUnlock(true);
         // Change primary password and verify that profile SID remains
         assertTrue(mService.setLockCredential(
-                secondUnifiedPassword, firstUnifiedPassword, PRIMARY_USER_ID, false));
+                secondUnifiedPassword, firstUnifiedPassword, PRIMARY_USER_ID));
         mStorageManager.setIgnoreBadUnlock(false);
         assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
         assertNull(mGateKeeperService.getAuthToken(TURNED_OFF_PROFILE_USER_ID));
 
         // Clear unified challenge
         assertTrue(mService.setLockCredential(nonePassword(),
-                secondUnifiedPassword, PRIMARY_USER_ID,
-                false));
+                secondUnifiedPassword, PRIMARY_USER_ID));
         assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
         assertEquals(0, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
         assertEquals(0, mGateKeeperService.getSecureUserId(TURNED_OFF_PROFILE_USER_ID));
@@ -166,7 +165,7 @@
         final LockscreenCredential profilePassword = newPassword("profile");
         assertTrue(mService.setLockCredential(primaryPassword,
                 nonePassword(),
-                PRIMARY_USER_ID, false));
+                PRIMARY_USER_ID));
         /* Currently in LockSettingsService.setLockCredential, unlockUser() is called with the new
          * credential as part of verifyCredential() before the new credential is committed in
          * StorageManager. So we relax the check in our mock StorageManager to allow that.
@@ -174,7 +173,7 @@
         mStorageManager.setIgnoreBadUnlock(true);
         assertTrue(mService.setLockCredential(profilePassword,
                 nonePassword(),
-                MANAGED_PROFILE_USER_ID, false));
+                MANAGED_PROFILE_USER_ID));
         mStorageManager.setIgnoreBadUnlock(false);
 
         final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
@@ -201,7 +200,7 @@
         // Change primary credential and make sure we don't affect profile
         mStorageManager.setIgnoreBadUnlock(true);
         assertTrue(mService.setLockCredential(
-                newPassword("pwd"), primaryPassword, PRIMARY_USER_ID, false));
+                newPassword("pwd"), primaryPassword, PRIMARY_USER_ID));
         mStorageManager.setIgnoreBadUnlock(false);
         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
                 profilePassword, 0, MANAGED_PROFILE_USER_ID)
@@ -214,8 +213,7 @@
         assertTrue(mService.setLockCredential(
                 newPassword("password"),
                 nonePassword(),
-                PRIMARY_USER_ID,
-                false));
+                PRIMARY_USER_ID));
 
         verify(mRecoverableKeyStoreManager)
                 .lockScreenSecretChanged(CREDENTIAL_TYPE_PASSWORD, "password".getBytes(),
@@ -228,8 +226,7 @@
         assertTrue(mService.setLockCredential(
                 newPattern("12345"),
                 nonePassword(),
-                MANAGED_PROFILE_USER_ID,
-                false));
+                MANAGED_PROFILE_USER_ID));
 
         verify(mRecoverableKeyStoreManager)
                 .lockScreenSecretChanged(CREDENTIAL_TYPE_PATTERN, "12345".getBytes(),
@@ -247,8 +244,7 @@
         assertTrue(mService.setLockCredential(
                 newPassword("newPassword"),
                 newPattern("12345"),
-                MANAGED_PROFILE_USER_ID,
-                false));
+                MANAGED_PROFILE_USER_ID));
 
         verify(mRecoverableKeyStoreManager)
                 .lockScreenSecretChanged(CREDENTIAL_TYPE_PASSWORD, "newPassword".getBytes(),
@@ -263,8 +259,7 @@
         assertTrue(mService.setLockCredential(
                 newPattern("12345"),
                 nonePassword(),
-                PRIMARY_USER_ID,
-                false));
+                PRIMARY_USER_ID));
 
         verify(mRecoverableKeyStoreManager, never())
                 .lockScreenSecretChanged(
@@ -284,8 +279,7 @@
         assertTrue(mService.setLockCredential(
                 newCredential,
                 oldCredential,
-                PRIMARY_USER_ID,
-                false));
+                PRIMARY_USER_ID));
 
         verify(mRecoverableKeyStoreManager)
                 .lockScreenSecretChanged(CREDENTIAL_TYPE_PASSWORD, newCredential.getCredential(),
@@ -305,8 +299,7 @@
         assertTrue(mService.setLockCredential(
                 nonePassword(),
                 newPassword("oldPassword"),
-                PRIMARY_USER_ID,
-                false));
+                PRIMARY_USER_ID));
 
         verify(mRecoverableKeyStoreManager)
                 .lockScreenSecretChanged(CREDENTIAL_TYPE_NONE, null, PRIMARY_USER_ID);
@@ -322,7 +315,7 @@
                 1234);
         mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
 
-        mService.setLockCredential(nonePassword(), newPattern("123654"), PRIMARY_USER_ID, false);
+        mService.setLockCredential(nonePassword(), newPattern("123654"), PRIMARY_USER_ID);
 
         // Verify fingerprint is removed
         verify(mFingerprintManager).remove(any(), eq(PRIMARY_USER_ID), any());
@@ -343,8 +336,7 @@
         assertTrue(mService.setLockCredential(
                 profilePassword,
                 nonePassword(),
-                MANAGED_PROFILE_USER_ID,
-                false));
+                MANAGED_PROFILE_USER_ID));
 
         verify(mRecoverableKeyStoreManager)
                 .lockScreenSecretChanged(CREDENTIAL_TYPE_PASSWORD, profilePassword.getCredential(),
@@ -390,8 +382,7 @@
         assertTrue(mService.setLockCredential(
                 pattern,
                 nonePassword(),
-                MANAGED_PROFILE_USER_ID,
-                false));
+                MANAGED_PROFILE_USER_ID));
         reset(mRecoverableKeyStoreManager);
 
         mService.verifyCredential(pattern, 1, MANAGED_PROFILE_USER_ID);
@@ -426,7 +417,7 @@
 
     private void testCreateCredential(int userId, LockscreenCredential credential)
             throws RemoteException {
-        assertTrue(mService.setLockCredential(credential, nonePassword(), userId, false));
+        assertTrue(mService.setLockCredential(credential, nonePassword(), userId));
         assertVerifyCredentials(userId, credential, -1);
     }
 
@@ -435,7 +426,7 @@
         mHasSecureLockScreen = false;
 
         try {
-            mService.setLockCredential(credential, null, userId, false);
+            mService.setLockCredential(credential, null, userId);
             fail("An exception should have been thrown.");
         } catch (UnsupportedOperationException e) {
             // Success - the exception was expected.
@@ -448,7 +439,7 @@
             LockscreenCredential oldCredential) throws RemoteException {
         final long sid = 1234;
         initializeStorageWithCredential(userId, oldCredential, sid);
-        assertTrue(mService.setLockCredential(newCredential, oldCredential, userId, false));
+        assertTrue(mService.setLockCredential(newCredential, oldCredential, userId));
         assertVerifyCredentials(userId, newCredential, sid);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java
index 27af9e2..4b3f7b5 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java
@@ -48,7 +48,7 @@
 
     @Test
     public void testFrpCredential_setPin() {
-        mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID, false);
+        mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
 
         assertEquals(CREDENTIAL_TYPE_PIN, mService.getCredentialType(USER_FRP));
         assertEquals(VerifyCredentialResponse.RESPONSE_OK,
@@ -57,7 +57,7 @@
 
     @Test
     public void testFrpCredential_setPattern() {
-        mService.setLockCredential(newPattern("4321"), nonePassword(), PRIMARY_USER_ID, false);
+        mService.setLockCredential(newPattern("4321"), nonePassword(), PRIMARY_USER_ID);
 
         assertEquals(CREDENTIAL_TYPE_PATTERN, mService.getCredentialType(USER_FRP));
         assertEquals(VerifyCredentialResponse.RESPONSE_OK,
@@ -66,7 +66,7 @@
 
     @Test
     public void testFrpCredential_setPassword() {
-        mService.setLockCredential(newPassword("4321"), nonePassword(), PRIMARY_USER_ID, false);
+        mService.setLockCredential(newPassword("4321"), nonePassword(), PRIMARY_USER_ID);
 
         assertEquals(CREDENTIAL_TYPE_PASSWORD, mService.getCredentialType(USER_FRP));
         assertEquals(VerifyCredentialResponse.RESPONSE_OK,
@@ -75,8 +75,8 @@
 
     @Test
     public void testFrpCredential_changeCredential() {
-        mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID, false);
-        mService.setLockCredential(newPattern("5678"), newPassword("1234"), PRIMARY_USER_ID, false);
+        mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID);
+        mService.setLockCredential(newPattern("5678"), newPassword("1234"), PRIMARY_USER_ID);
 
         assertEquals(CREDENTIAL_TYPE_PATTERN, mService.getCredentialType(USER_FRP));
         assertEquals(VerifyCredentialResponse.RESPONSE_OK,
@@ -85,16 +85,16 @@
 
     @Test
     public void testFrpCredential_removeCredential() {
-        mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID, false);
+        mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID);
         assertEquals(CREDENTIAL_TYPE_PASSWORD, mService.getCredentialType(USER_FRP));
 
-        mService.setLockCredential(nonePassword(), newPassword("1234"), PRIMARY_USER_ID, false);
+        mService.setLockCredential(nonePassword(), newPassword("1234"), PRIMARY_USER_ID);
         assertEquals(CREDENTIAL_TYPE_NONE, mService.getCredentialType(USER_FRP));
     }
 
     @Test
     public void testFrpCredential_cannotVerifyAfterProvsioning() {
-        mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID, false);
+        mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
 
         mSettings.setDeviceProvisioned(true);
         assertEquals(VerifyCredentialResponse.RESPONSE_ERROR,
@@ -103,7 +103,7 @@
 
     @Test
     public void testFrpCredential_legacyPinTypePersistentData() {
-        mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID, false);
+        mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
         PersistentData data = mStorage.readPersistentDataBlock();
         // Tweak the existing persistent data to make it look like one with legacy credential type
         assertEquals(CREDENTIAL_TYPE_PIN, data.payload[3]);
@@ -119,7 +119,7 @@
 
     @Test
     public void testFrpCredential_legacyPasswordTypePersistentData() {
-        mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID, false);
+        mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID);
         PersistentData data = mStorage.readPersistentDataBlock();
         // Tweak the existing persistent data to make it look like one with legacy credential type
         assertEquals(CREDENTIAL_TYPE_PASSWORD, data.payload[3]);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index 4985848..d6ef2d4 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -106,7 +106,7 @@
         final LockscreenCredential password = newPassword("testPasswordMigration-password");
 
         disableSyntheticPassword();
-        assertTrue(mService.setLockCredential(password, nonePassword(), PRIMARY_USER_ID, false));
+        assertTrue(mService.setLockCredential(password, nonePassword(), PRIMARY_USER_ID));
         long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
         final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
         enableSyntheticPassword();
@@ -128,7 +128,7 @@
     protected void initializeCredentialUnderSP(LockscreenCredential password, int userId)
             throws RemoteException {
         enableSyntheticPassword();
-        mService.setLockCredential(password, nonePassword(), userId, false);
+        mService.setLockCredential(password, nonePassword(), userId);
         assertEquals(CREDENTIAL_TYPE_PASSWORD, mService.getCredentialType(userId));
         assertTrue(mService.isSyntheticPasswordBasedCredential(userId));
     }
@@ -140,7 +140,7 @@
 
         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
         long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
-        mService.setLockCredential(newPassword, password, PRIMARY_USER_ID, false);
+        mService.setLockCredential(newPassword, password, PRIMARY_USER_ID);
         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
                 newPassword, 0, PRIMARY_USER_ID)
                         .getResponseCode());
@@ -170,12 +170,11 @@
         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
         long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
         // clear password
-        mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID, false);
+        mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID);
         assertEquals(0 ,mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
 
         // set a new password
-        mService.setLockCredential(badPassword, nonePassword(),
-                PRIMARY_USER_ID, false);
+        mService.setLockCredential(badPassword, nonePassword(), PRIMARY_USER_ID);
         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
                 badPassword, 0, PRIMARY_USER_ID)
                         .getResponseCode());
@@ -188,7 +187,7 @@
         LockscreenCredential badPassword = newPassword("new");
 
         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
-        mService.setLockCredential(badPassword, password, PRIMARY_USER_ID, false);
+        mService.setLockCredential(badPassword, password, PRIMARY_USER_ID);
         assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
                 badPassword, 0, PRIMARY_USER_ID)
                         .getResponseCode());
@@ -245,7 +244,7 @@
     public void testSyntheticPasswordButNoCredentialPassesAuthSecret() throws RemoteException {
         LockscreenCredential password = newPassword("getASyntheticPassword");
         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
-        mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID, false);
+        mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID);
 
         reset(mAuthSecretService);
         mService.onUnlockUser(PRIMARY_USER_ID);
@@ -257,7 +256,7 @@
     public void testManagedProfileUnifiedChallengeMigration() throws RemoteException {
         LockscreenCredential UnifiedPassword = newPassword("unified-pwd");
         disableSyntheticPassword();
-        mService.setLockCredential(UnifiedPassword, nonePassword(), PRIMARY_USER_ID, false);
+        mService.setLockCredential(UnifiedPassword, nonePassword(), PRIMARY_USER_ID);
         mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
         final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
         final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
@@ -292,9 +291,8 @@
         LockscreenCredential primaryPassword = newPassword("primary");
         LockscreenCredential profilePassword = newPassword("profile");
         disableSyntheticPassword();
-        mService.setLockCredential(primaryPassword, nonePassword(), PRIMARY_USER_ID, false);
-        mService.setLockCredential(profilePassword, nonePassword(),
-                MANAGED_PROFILE_USER_ID, false);
+        mService.setLockCredential(primaryPassword, nonePassword(), PRIMARY_USER_ID);
+        mService.setLockCredential(profilePassword, nonePassword(), MANAGED_PROFILE_USER_ID);
         final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
         final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
         byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
@@ -404,7 +402,7 @@
         mService.verifyCredential(password, 0, PRIMARY_USER_ID).getResponseCode();
         assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
 
-        mService.setLockCredential(pattern, password, PRIMARY_USER_ID, false);
+        mService.setLockCredential(pattern, password, PRIMARY_USER_ID);
 
         mLocalService.setLockCredentialWithToken(newPassword, handle, token, PRIMARY_USER_ID);
 
@@ -433,7 +431,7 @@
         // initialized but the user currently has no password
         initializeCredentialUnderSP(newPassword("password"), PRIMARY_USER_ID);
         assertTrue(mService.setLockCredential(nonePassword(), newPassword("password"),
-                PRIMARY_USER_ID, false));
+                PRIMARY_USER_ID));
         assertTrue(mService.isSyntheticPasswordBasedCredential(PRIMARY_USER_ID));
 
         long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
@@ -449,7 +447,7 @@
         LockscreenCredential password = newPassword("password");
         // Set up pre-SP user password
         disableSyntheticPassword();
-        mService.setLockCredential(password, nonePassword(), PRIMARY_USER_ID, false);
+        mService.setLockCredential(password, nonePassword(), PRIMARY_USER_ID);
         enableSyntheticPassword();
 
         long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
@@ -507,11 +505,11 @@
     @Test
     public void testGetHashFactorPrimaryUser() throws RemoteException {
         LockscreenCredential password = newPassword("password");
-        mService.setLockCredential(password, nonePassword(), PRIMARY_USER_ID, false);
+        mService.setLockCredential(password, nonePassword(), PRIMARY_USER_ID);
         byte[] hashFactor = mService.getHashFactor(password, PRIMARY_USER_ID);
         assertNotNull(hashFactor);
 
-        mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID, false);
+        mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID);
         byte[] newHashFactor = mService.getHashFactor(nonePassword(), PRIMARY_USER_ID);
         assertNotNull(newHashFactor);
         // Hash factor should never change after password change/removal
@@ -521,7 +519,7 @@
     @Test
     public void testGetHashFactorManagedProfileUnifiedChallenge() throws RemoteException {
         LockscreenCredential pattern = newPattern("1236");
-        mService.setLockCredential(pattern, nonePassword(), PRIMARY_USER_ID, false);
+        mService.setLockCredential(pattern, nonePassword(), PRIMARY_USER_ID);
         mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
         assertNotNull(mService.getHashFactor(null, MANAGED_PROFILE_USER_ID));
     }
@@ -530,9 +528,8 @@
     public void testGetHashFactorManagedProfileSeparateChallenge() throws RemoteException {
         LockscreenCredential primaryPassword = newPassword("primary");
         LockscreenCredential profilePassword = newPassword("profile");
-        mService.setLockCredential(primaryPassword, nonePassword(), PRIMARY_USER_ID, false);
-        mService.setLockCredential(profilePassword, nonePassword(),
-                MANAGED_PROFILE_USER_ID, false);
+        mService.setLockCredential(primaryPassword, nonePassword(), PRIMARY_USER_ID);
+        mService.setLockCredential(profilePassword, nonePassword(), MANAGED_PROFILE_USER_ID);
         assertNotNull(
                 mService.getHashFactor(profilePassword, MANAGED_PROFILE_USER_ID));
     }
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 51bae16..545836e 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -138,7 +138,6 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.util.test.BroadcastInterceptingContext;
 import com.android.internal.util.test.BroadcastInterceptingContext.FutureIntent;
 import com.android.server.DeviceIdleInternal;
@@ -1484,7 +1483,7 @@
         // smoke test to make sure no errors are raised
         mServiceContext.sendBroadcast(
                 new Intent(ACTION_CARRIER_CONFIG_CHANGED)
-                        .putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
+                        .putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, FAKE_SUB_ID)
         );
         assertNetworkPolicyEquals(DEFAULT_CYCLE_DAY, mDefaultWarningBytes, mDefaultLimitBytes,
                 true);
@@ -1499,7 +1498,7 @@
         bundle.putLong(CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG, -100);
         mServiceContext.sendBroadcast(
                 new Intent(ACTION_CARRIER_CONFIG_CHANGED)
-                        .putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
+                        .putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, FAKE_SUB_ID)
         );
 
         assertNetworkPolicyEquals(DEFAULT_CYCLE_DAY, mDefaultWarningBytes, mDefaultLimitBytes,
@@ -1518,7 +1517,7 @@
                 DATA_CYCLE_USE_PLATFORM_DEFAULT);
         mServiceContext.sendBroadcast(
                 new Intent(ACTION_CARRIER_CONFIG_CHANGED)
-                        .putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
+                        .putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, FAKE_SUB_ID)
         );
 
         assertNetworkPolicyEquals(DEFAULT_CYCLE_DAY, mDefaultWarningBytes, mDefaultLimitBytes,
@@ -1540,7 +1539,7 @@
                 DATA_CYCLE_THRESHOLD_DISABLED);
         mServiceContext.sendBroadcast(
                 new Intent(ACTION_CARRIER_CONFIG_CHANGED)
-                        .putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
+                        .putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, FAKE_SUB_ID)
         );
 
         // The policy still shouldn't change, because we don't want to overwrite user settings.
@@ -1557,7 +1556,7 @@
         bundle.putLong(CarrierConfigManager.KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG, 9999);
         mServiceContext.sendBroadcast(
                 new Intent(ACTION_CARRIER_CONFIG_CHANGED)
-                        .putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
+                        .putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, FAKE_SUB_ID)
         );
 
         assertNetworkPolicyEquals(31, 9999, 9999, true);
@@ -1574,7 +1573,7 @@
                 DATA_CYCLE_THRESHOLD_DISABLED);
         mServiceContext.sendBroadcast(
                 new Intent(ACTION_CARRIER_CONFIG_CHANGED)
-                        .putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
+                        .putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, FAKE_SUB_ID)
         );
 
         assertNetworkPolicyEquals(31, WARNING_DISABLED, LIMIT_DISABLED, true);
@@ -1591,7 +1590,7 @@
                 DATA_CYCLE_THRESHOLD_DISABLED);
         mServiceContext.sendBroadcast(
                 new Intent(ACTION_CARRIER_CONFIG_CHANGED)
-                        .putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
+                        .putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, FAKE_SUB_ID)
         );
         assertNetworkPolicyEquals(31, WARNING_DISABLED, LIMIT_DISABLED, true);
 
@@ -1606,7 +1605,7 @@
                 DATA_CYCLE_USE_PLATFORM_DEFAULT);
         mServiceContext.sendBroadcast(
                 new Intent(ACTION_CARRIER_CONFIG_CHANGED)
-                        .putExtra(PhoneConstants.SUBSCRIPTION_KEY, FAKE_SUB_ID)
+                        .putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, FAKE_SUB_ID)
         );
 
         assertNetworkPolicyEquals(31, mDefaultWarningBytes, mDefaultLimitBytes,
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt b/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
new file mode 100644
index 0000000..f45316f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
@@ -0,0 +1,208 @@
+/*
+ * 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.om
+
+import android.content.pm.parsing.AndroidPackage
+import android.net.Uri
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.testng.Assert.assertThrows
+import test.util.mockThrowOnUnmocked
+import test.util.whenever
+
+@RunWith(Parameterized::class)
+class OverlayReferenceMapperTests {
+
+    companion object {
+        private const val TARGET_PACKAGE_NAME = "com.test.target"
+        private const val OVERLAY_PACKAGE_NAME = "com.test.overlay"
+        private const val ACTOR_PACKAGE_NAME = "com.test.actor"
+        private const val ACTOR_NAME = "overlay://test/actorName"
+
+        @JvmStatic
+        @Parameterized.Parameters(name = "deferRebuild {0}")
+        fun parameters() = arrayOf(true, false)
+    }
+
+    private lateinit var mapper: OverlayReferenceMapper
+
+    @JvmField
+    @Parameterized.Parameter(0)
+    var deferRebuild = false
+
+    @Before
+    fun initMapper() {
+        mapper = mapper()
+    }
+
+    @Test
+    fun targetWithOverlay() {
+        val target = mockTarget()
+        val overlay = mockOverlay()
+        val existing = mapper.addInOrder(overlay)
+        assertEmpty()
+        mapper.addInOrder(target, existing = existing)
+        assertMapping(ACTOR_PACKAGE_NAME to setOf(target, overlay))
+        mapper.remove(target)
+        assertEmpty()
+    }
+
+    @Test
+    fun targetWithMultipleOverlays() {
+        val target = mockTarget()
+        val overlay0 = mockOverlay(0)
+        val overlay1 = mockOverlay(1)
+        mapper = mapper(
+                overlayToTargetToOverlayables = mapOf(
+                        overlay0.packageName to mapOf(
+                                target.packageName to target.overlayables.keys
+                        ),
+                        overlay1.packageName to mapOf(
+                                target.packageName to target.overlayables.keys
+                        )
+                )
+        )
+        val existing = mapper.addInOrder(overlay0, overlay1)
+        assertEmpty()
+        mapper.addInOrder(target, existing = existing)
+        assertMapping(ACTOR_PACKAGE_NAME to setOf(target, overlay0, overlay1))
+        mapper.remove(overlay0)
+        assertMapping(ACTOR_PACKAGE_NAME to setOf(target, overlay1))
+        mapper.remove(target)
+        assertEmpty()
+    }
+
+    @Test
+    fun targetWithoutOverlay() {
+        val target = mockTarget()
+        mapper.addInOrder(target)
+        assertMapping(ACTOR_PACKAGE_NAME to setOf(target))
+        mapper.remove(target)
+        assertEmpty()
+    }
+
+    @Test
+    fun overlayWithTarget() {
+        val target = mockTarget()
+        val overlay = mockOverlay()
+        val existing = mapper.addInOrder(target)
+        assertMapping(ACTOR_PACKAGE_NAME to setOf(target))
+        mapper.addInOrder(overlay, existing = existing)
+        assertMapping(ACTOR_PACKAGE_NAME to setOf(target, overlay))
+        mapper.remove(overlay)
+        assertMapping(ACTOR_PACKAGE_NAME to setOf(target))
+    }
+
+    @Test
+    fun overlayWithMultipleTargets() {
+        val target0 = mockTarget(0)
+        val target1 = mockTarget(1)
+        val overlay = mockOverlay()
+        mapper = mapper(
+                overlayToTargetToOverlayables = mapOf(
+                        overlay.packageName to mapOf(
+                                target0.packageName to target0.overlayables.keys,
+                                target1.packageName to target1.overlayables.keys
+                        )
+                )
+        )
+        mapper.addInOrder(target0, target1, overlay)
+        assertMapping(ACTOR_PACKAGE_NAME to setOf(target0, target1, overlay))
+        mapper.remove(target0)
+        assertMapping(ACTOR_PACKAGE_NAME to setOf(target1, overlay))
+        mapper.remove(target1)
+        assertEmpty()
+    }
+
+    @Test
+    fun overlayWithoutTarget() {
+        val overlay = mockOverlay()
+        mapper.addInOrder(overlay)
+        // An overlay can only have visibility exposed through its target
+        assertEmpty()
+        mapper.remove(overlay)
+        assertEmpty()
+    }
+
+    private fun OverlayReferenceMapper.addInOrder(
+        vararg pkgs: AndroidPackage,
+        existing: MutableMap<String, AndroidPackage> = mutableMapOf()
+    ) = pkgs.fold(existing) { map, pkg ->
+        addPkg(pkg, map)
+        map[pkg.packageName] = pkg
+        return@fold map
+    }
+
+    private fun OverlayReferenceMapper.remove(pkg: AndroidPackage) = removePkg(pkg.packageName)
+
+    private fun assertMapping(vararg pairs: Pair<String, Set<AndroidPackage>>) {
+        val expected = pairs.associate { it }
+                .mapValues { pair -> pair.value.map { it.packageName }.toSet() }
+
+        // This validates the API exposed for querying the relationships
+        expected.forEach { (actorPkgName, expectedPkgNames) ->
+            expectedPkgNames.forEach { expectedPkgName ->
+                if (deferRebuild) {
+                    assertThrows(IllegalStateException::class.java) {
+                        mapper.isValidActor(expectedPkgName, actorPkgName)
+                    }
+                    mapper.rebuildIfDeferred()
+                    deferRebuild = false
+                }
+
+                assertThat(mapper.isValidActor(expectedPkgName, actorPkgName)).isTrue()
+            }
+        }
+
+        // This asserts no other relationships are defined besides those tested above
+        assertThat(mapper.actorPkgToPkgs).containsExactlyEntriesIn(expected)
+    }
+
+    private fun assertEmpty() = assertMapping()
+
+    private fun mapper(
+        namedActors: Map<String, Map<String, String>> = Uri.parse(ACTOR_NAME).run {
+            mapOf(authority!! to mapOf(pathSegments.first() to ACTOR_PACKAGE_NAME))
+        },
+        overlayToTargetToOverlayables: Map<String, Map<String, Set<String>>> = mapOf(
+                mockOverlay().packageName to mapOf(
+                        mockTarget().run { packageName to overlayables.keys }
+                )
+        )
+    ) = OverlayReferenceMapper(deferRebuild, object : OverlayReferenceMapper.Provider {
+        override fun getActorPkg(actor: String?) =
+                OverlayActorEnforcer.getPackageNameForActor(actor, namedActors).first
+
+        override fun getTargetToOverlayables(pkg: AndroidPackage) =
+                overlayToTargetToOverlayables[pkg.packageName] ?: emptyMap()
+    })
+
+    private fun mockTarget(increment: Int = 0) = mockThrowOnUnmocked<AndroidPackage> {
+        whenever(packageName) { "$TARGET_PACKAGE_NAME$increment" }
+        whenever(overlayables) { mapOf("overlayableName$increment" to ACTOR_NAME) }
+        whenever(toString()) { "Package{$packageName}" }
+    }
+
+    private fun mockOverlay(increment: Int = 0) = mockThrowOnUnmocked<AndroidPackage> {
+        whenever(packageName) { "$OVERLAY_PACKAGE_NAME$increment" }
+        whenever(overlayables) { emptyMap<String, String>() }
+        whenever(toString()) { "Package{$packageName}" }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
index 178f38a..fb9c68a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -68,7 +68,7 @@
     @Before
     public void setUp() throws RemoteException {
         mContext = InstrumentationRegistry.getInstrumentation().getContext();
-        mApexManager = new ApexManager.ApexManagerImpl(mContext, mApexService);
+        mApexManager = new ApexManager.ApexManagerImpl(mApexService);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index f6fb6e2..82bbdcb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -26,12 +26,20 @@
 import android.annotation.Nullable;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsingPackage;
 import android.os.Build;
 import android.os.Process;
 import android.util.ArrayMap;
+import android.util.ArraySet;
+
+import androidx.annotation.NonNull;
+
+import com.android.server.om.OverlayReferenceMapper;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -40,56 +48,72 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
 @RunWith(JUnit4.class)
 public class AppsFilterTest {
 
     private static final int DUMMY_CALLING_UID = 10345;
     private static final int DUMMY_TARGET_UID = 10556;
+    private static final int DUMMY_ACTOR_UID = 10656;
+    private static final int DUMMY_OVERLAY_UID = 10756;
+    private static final int DUMMY_ACTOR_TWO_UID = 10856;
 
     @Mock
     AppsFilter.FeatureConfig mFeatureConfigMock;
 
     private ArrayMap<String, PackageSetting> mExisting = new ArrayMap<>();
 
-    private static PackageBuilder pkg(String packageName) {
-        return new PackageBuilder(packageName)
-                .setApplicationInfoTargetSdkVersion(Build.VERSION_CODES.R);
+    private static ParsingPackage pkg(String packageName) {
+        return PackageImpl.forParsing(packageName)
+                .setTargetSdkVersion(Build.VERSION_CODES.R);
     }
 
-    private static PackageBuilder pkg(String packageName, Intent... queries) {
-        return pkg(packageName).setQueriesIntents(queries);
-    }
-
-    private static PackageBuilder pkg(String packageName, String... queriesPackages) {
-        return pkg(packageName).setQueriesPackages(queriesPackages);
-    }
-
-    private static PackageBuilder pkg(String packageName, IntentFilter... filters) {
-        final ActivityInfo activityInfo = new ActivityInfo();
-        final PackageBuilder packageBuilder = pkg(packageName).addActivity(
-                pkg -> new PackageParser.ParseComponentArgs(pkg, new String[1], 0, 0, 0, 0, 0, 0,
-                        new String[]{packageName}, 0, 0, 0), activityInfo);
-        for (IntentFilter filter : filters) {
-            packageBuilder.addActivityIntentInfo(0 /* index */, activity -> {
-                final PackageParser.ActivityIntentInfo info =
-                        new PackageParser.ActivityIntentInfo(activity);
-                if (filter.countActions() > 0) {
-                    filter.actionsIterator().forEachRemaining(info::addAction);
-                }
-                if (filter.countCategories() > 0) {
-                    filter.actionsIterator().forEachRemaining(info::addCategory);
-                }
-                if (filter.countDataAuthorities() > 0) {
-                    filter.authoritiesIterator().forEachRemaining(info::addDataAuthority);
-                }
-                if (filter.countDataSchemes() > 0) {
-                    filter.schemesIterator().forEachRemaining(info::addDataScheme);
-                }
-                activityInfo.exported = true;
-                return info;
-            });
+    private static ParsingPackage pkg(String packageName, Intent... queries) {
+        ParsingPackage pkg = pkg(packageName);
+        if (queries != null) {
+            for (Intent intent : queries) {
+                pkg.addQueriesIntent(intent);
+            }
         }
-        return packageBuilder;
+        return pkg;
+    }
+
+    private static ParsingPackage pkg(String packageName, String... queriesPackages) {
+        ParsingPackage pkg = pkg(packageName);
+        if (queriesPackages != null) {
+            for (String queryPackageName : queriesPackages) {
+                pkg.addQueriesPackage(queryPackageName);
+            }
+        }
+        return pkg;
+    }
+
+    private static ParsingPackage pkg(String packageName, IntentFilter... filters) {
+        ParsedActivity activity = new ParsedActivity();
+        activity.setPackageName(packageName);
+        for (IntentFilter filter : filters) {
+            final ParsedActivityIntentInfo info = new ParsedActivityIntentInfo(packageName, null);
+            if (filter.countActions() > 0) {
+                filter.actionsIterator().forEachRemaining(info::addAction);
+            }
+            if (filter.countCategories() > 0) {
+                filter.actionsIterator().forEachRemaining(info::addAction);
+            }
+            if (filter.countDataAuthorities() > 0) {
+                filter.authoritiesIterator().forEachRemaining(info::addDataAuthority);
+            }
+            if (filter.countDataSchemes() > 0) {
+                filter.schemesIterator().forEachRemaining(info::addDataScheme);
+            }
+            activity.addIntent(info);
+            activity.exported = true;
+        }
+
+        return pkg(packageName)
+                .addActivity(activity);
     }
 
     @Before
@@ -98,14 +122,14 @@
 
         MockitoAnnotations.initMocks(this);
         when(mFeatureConfigMock.isGloballyEnabled()).thenReturn(true);
-        when(mFeatureConfigMock.packageIsEnabled(any(PackageParser.Package.class)))
+        when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class)))
                 .thenReturn(true);
     }
 
     @Test
     public void testSystemReadyPropogates() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
         appsFilter.onSystemReady();
         verify(mFeatureConfigMock).onSystemReady();
     }
@@ -113,7 +137,8 @@
     @Test
     public void testQueriesAction_FilterMatches() {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkg("com.some.package", new IntentFilter("TEST_ACTION")), DUMMY_TARGET_UID);
@@ -126,7 +151,8 @@
     @Test
     public void testQueriesAction_NoMatchingAction_Filters() {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkg("com.some.package"), DUMMY_TARGET_UID);
@@ -139,14 +165,15 @@
     @Test
     public void testQueriesAction_NoMatchingActionFilterLowSdk_DoesntFilter() {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkg("com.some.package"), DUMMY_TARGET_UID);
         PackageSetting calling = simulateAddPackage(appsFilter,
                 pkg("com.some.other.package",
                         new Intent("TEST_ACTION"))
-                        .setApplicationInfoTargetSdkVersion(Build.VERSION_CODES.P),
+                        .setTargetSdkVersion(Build.VERSION_CODES.P),
                 DUMMY_CALLING_UID);
 
         when(mFeatureConfigMock.packageIsEnabled(calling.pkg)).thenReturn(false);
@@ -157,7 +184,8 @@
     @Test
     public void testNoQueries_Filters() {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkg("com.some.package"), DUMMY_TARGET_UID);
@@ -170,7 +198,8 @@
     @Test
     public void testForceQueryable_DoesntFilter() {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                         pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_UID);
@@ -183,7 +212,8 @@
     @Test
     public void testForceQueryableByDevice_SystemCaller_DoesntFilter() {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkg("com.some.package"), DUMMY_TARGET_UID,
@@ -197,7 +227,8 @@
     @Test
     public void testForceQueryableByDevice_NonSystemCaller_Filters() {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkg("com.some.package"), DUMMY_TARGET_UID);
@@ -212,7 +243,8 @@
     public void testSystemQueryable_DoesntFilter() {
         final AppsFilter appsFilter =
                 new AppsFilter(mFeatureConfigMock, new String[]{},
-                        true /* system force queryable */);
+                        true /* system force queryable */, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkg("com.some.package"), DUMMY_TARGET_UID,
@@ -226,7 +258,8 @@
     @Test
     public void testQueriesPackage_DoesntFilter() {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkg("com.some.package"), DUMMY_TARGET_UID);
@@ -238,10 +271,11 @@
 
     @Test
     public void testNoQueries_FeatureOff_DoesntFilter() {
-        when(mFeatureConfigMock.packageIsEnabled(any(PackageParser.Package.class)))
+        when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class)))
                 .thenReturn(false);
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(
                 appsFilter, pkg("com.some.package"), DUMMY_TARGET_UID);
@@ -254,20 +288,22 @@
     @Test
     public void testSystemUid_DoesntFilter() {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkg("com.some.package"), DUMMY_TARGET_UID);
 
         assertFalse(appsFilter.shouldFilterApplication(0, null, target, 0));
-        assertFalse(appsFilter.shouldFilterApplication(
-                Process.FIRST_APPLICATION_UID - 1, null, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(Process.FIRST_APPLICATION_UID - 1,
+                null, target, 0));
     }
 
     @Test
     public void testNonSystemUid_NoCallingSetting_Filters() {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkg("com.some.package"), DUMMY_TARGET_UID);
@@ -278,7 +314,8 @@
     @Test
     public void testNoTargetPackage_filters() {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false);
+                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+        appsFilter.onSystemReady();
 
         PackageSetting target = new PackageSettingBuilder()
                 .setName("com.some.package")
@@ -292,30 +329,151 @@
         assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
     }
 
+    @Test
+    public void testActsOnTargetOfOverlay() {
+        final String actorName = "overlay://test/actorName";
+
+        ParsingPackage target = pkg("com.some.package.target")
+                .addOverlayable("overlayableName", actorName);
+        ParsingPackage overlay = pkg("com.some.package.overlay")
+                .setIsOverlay(true)
+                .setOverlayTarget(target.getPackageName())
+                .setOverlayTargetName("overlayableName");
+        ParsingPackage actor = pkg("com.some.package.actor");
+
+        final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false,
+                new OverlayReferenceMapper.Provider() {
+                    @Nullable
+                    @Override
+                    public String getActorPkg(String actorString) {
+                        if (actorName.equals(actorString)) {
+                            return actor.getPackageName();
+                        }
+                        return null;
+                    }
+
+                    @NonNull
+                    @Override
+                    public Map<String, Set<String>> getTargetToOverlayables(
+                            @NonNull AndroidPackage pkg) {
+                        if (overlay.getPackageName().equals(pkg.getPackageName())) {
+                            Map<String, Set<String>> map = new ArrayMap<>();
+                            Set<String> set = new ArraySet<>();
+                            set.add(overlay.getOverlayTargetName());
+                            map.put(overlay.getOverlayTarget(), set);
+                            return map;
+                        }
+                        return Collections.emptyMap();
+                    }
+                });
+        appsFilter.onSystemReady();
+
+        PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_UID);
+        PackageSetting overlaySetting = simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_UID);
+        PackageSetting actorSetting = simulateAddPackage(appsFilter, actor, DUMMY_ACTOR_UID);
+
+        // Actor can see both target and overlay
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_UID, actorSetting,
+                targetSetting, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_UID, actorSetting,
+                overlaySetting, 0));
+
+        // But target/overlay can't see each other
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_TARGET_UID, targetSetting,
+                overlaySetting, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_UID, overlaySetting,
+                targetSetting, 0));
+
+        // And can't see the actor
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_TARGET_UID, targetSetting,
+                actorSetting, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_UID, overlaySetting,
+                actorSetting, 0));
+    }
+
+    @Test
+    public void testActsOnTargetOfOverlayThroughSharedUser() {
+        final String actorName = "overlay://test/actorName";
+
+        ParsingPackage target = pkg("com.some.package.target")
+                .addOverlayable("overlayableName", actorName);
+        ParsingPackage overlay = pkg("com.some.package.overlay")
+                .setIsOverlay(true)
+                .setOverlayTarget(target.getPackageName())
+                .setOverlayTargetName("overlayableName");
+        ParsingPackage actorOne = pkg("com.some.package.actor.one");
+        ParsingPackage actorTwo = pkg("com.some.package.actor.two");
+
+        final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false,
+                new OverlayReferenceMapper.Provider() {
+                    @Nullable
+                    @Override
+                    public String getActorPkg(String actorString) {
+                        // Only actorOne is mapped as a valid actor
+                        if (actorName.equals(actorString)) {
+                            return actorOne.getPackageName();
+                        }
+                        return null;
+                    }
+
+                    @NonNull
+                    @Override
+                    public Map<String, Set<String>> getTargetToOverlayables(
+                            @NonNull AndroidPackage pkg) {
+                        if (overlay.getPackageName().equals(pkg.getPackageName())) {
+                            Map<String, Set<String>> map = new ArrayMap<>();
+                            Set<String> set = new ArraySet<>();
+                            set.add(overlay.getOverlayTargetName());
+                            map.put(overlay.getOverlayTarget(), set);
+                            return map;
+                        }
+                        return Collections.emptyMap();
+                    }
+                });
+        appsFilter.onSystemReady();
+
+        PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_UID);
+        PackageSetting overlaySetting = simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_UID);
+        PackageSetting actorOneSetting = simulateAddPackage(appsFilter, actorOne, DUMMY_ACTOR_UID);
+        PackageSetting actorTwoSetting = simulateAddPackage(appsFilter, actorTwo,
+                DUMMY_ACTOR_TWO_UID);
+
+        SharedUserSetting actorSharedSetting = new SharedUserSetting("actorSharedUser",
+                actorOneSetting.pkgFlags, actorOneSetting.pkgPrivateFlags);
+        actorSharedSetting.addPackage(actorOneSetting);
+        actorSharedSetting.addPackage(actorTwoSetting);
+
+        // actorTwo can see both target and overlay
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_TWO_UID, actorSharedSetting,
+                targetSetting, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_TWO_UID, actorSharedSetting,
+                overlaySetting, 0));
+    }
+
     private interface WithSettingBuilder {
         PackageSettingBuilder withBuilder(PackageSettingBuilder builder);
     }
 
     private PackageSetting simulateAddPackage(AppsFilter filter,
-            PackageBuilder newPkgBuilder, int appId) {
+            ParsingPackage newPkgBuilder, int appId) {
         return simulateAddPackage(filter, newPkgBuilder, appId, null);
     }
 
     private PackageSetting simulateAddPackage(AppsFilter filter,
-            PackageBuilder newPkgBuilder, int appId, @Nullable WithSettingBuilder action) {
-        PackageParser.Package newPkg = newPkgBuilder.build();
+            ParsingPackage newPkgBuilder, int appId, @Nullable WithSettingBuilder action) {
+        AndroidPackage newPkg = newPkgBuilder.hideAsParsed().hideAsFinal();
 
         final PackageSettingBuilder settingBuilder = new PackageSettingBuilder()
                 .setPackage(newPkg)
                 .setAppId(appId)
-                .setName(newPkg.packageName)
+                .setName(newPkg.getPackageName())
                 .setCodePath("/")
                 .setResourcePath("/")
                 .setPVersionCode(1L);
         final PackageSetting setting =
                 (action == null ? settingBuilder : action.withBuilder(settingBuilder)).build();
         filter.addPackage(setting, mExisting);
-        mExisting.put(newPkg.packageName, setting);
+        mExisting.put(newPkg.getPackageName(), setting);
         return setting;
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
index fec3267..0273a1c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
@@ -19,17 +19,17 @@
 
 import android.content.pm.PackageParser;
 import android.content.pm.Signature;
+import android.test.AndroidTestCase;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.LongSparseArray;
+
 import com.android.internal.util.ArrayUtils;
 
 import java.io.File;
 import java.io.IOException;
-import java.security.cert.CertificateException;
 import java.security.PublicKey;
-
-import android.test.AndroidTestCase;
+import java.security.cert.CertificateException;
 
 public class KeySetManagerServiceTest extends AndroidTestCase {
 
@@ -39,7 +39,7 @@
     public PackageSetting generateFakePackageSetting(String name) {
         return new PackageSetting(name, name, new File(mContext.getCacheDir(), "fakeCodePath"),
                 new File(mContext.getCacheDir(), "fakeResPath"), "", "", "",
-                "", 1, 0, 0, null, null, 0 /*sharedUserId*/, null /*usesStaticLibraries*/,
+                "", 1, 0, 0, 0 /*sharedUserId*/, null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java
deleted file mode 100644
index c38672c..0000000
--- a/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java
+++ /dev/null
@@ -1,176 +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.pm;
-
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageParser;
-
-import com.android.internal.util.ArrayUtils;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-
-class PackageBuilder {
-    final PackageParser.Package mPkg;
-
-    PackageBuilder(String packageName) {
-        mPkg = new PackageParser.Package(packageName);
-    }
-
-    PackageBuilder setApplicationInfoCodePath(String codePath) {
-        mPkg.applicationInfo.setCodePath(codePath);
-        return this;
-    }
-
-    PackageBuilder setApplicationInfoResourcePath(String resourcePath) {
-        mPkg.applicationInfo.setResourcePath(resourcePath);
-        return this;
-    }
-
-    PackageBuilder setCodePath(String codePath) {
-        mPkg.codePath = codePath;
-        return this;
-    }
-
-    PackageBuilder setBaseCodePath(String baseCodePath) {
-        mPkg.baseCodePath = baseCodePath;
-        return this;
-    }
-
-    PackageBuilder addUsesStaticLibrary(String name, long version) {
-        mPkg.usesStaticLibraries = ArrayUtils.add(mPkg.usesStaticLibraries, name);
-        mPkg.usesStaticLibrariesVersions =
-                ArrayUtils.appendLong(mPkg.usesStaticLibrariesVersions, version);
-        return this;
-    }
-
-    PackageBuilder setApplicationInfoNativeLibraryRootDir(String dir) {
-        mPkg.applicationInfo.nativeLibraryRootDir = dir;
-        return this;
-    }
-
-    PackageBuilder setStaticSharedLib(String staticSharedLibName, long staticSharedLibVersion) {
-        mPkg.staticSharedLibVersion = staticSharedLibVersion;
-        mPkg.staticSharedLibName = staticSharedLibName;
-        return this;
-    }
-
-    PackageBuilder setManifestPackageName(String manifestPackageName) {
-        mPkg.manifestPackageName = manifestPackageName;
-        return this;
-    }
-
-    PackageBuilder setVersionCodeMajor(int versionCodeMajor) {
-        mPkg.mVersionCodeMajor = versionCodeMajor;
-        return this;
-    }
-
-    PackageBuilder setVersionCode(int versionCode) {
-        mPkg.mVersionCode = versionCode;
-        return this;
-    }
-
-    PackageBuilder addSplitCodePath(String splitCodePath) {
-        mPkg.splitCodePaths =
-                ArrayUtils.appendElement(String.class, mPkg.splitCodePaths, splitCodePath);
-        return this;
-    }
-
-    PackageBuilder setApplicationInfoVolumeUuid(String volumeUuid) {
-        mPkg.applicationInfo.volumeUuid = volumeUuid;
-        return this;
-    }
-
-    PackageBuilder addLibraryName(String libraryName) {
-        mPkg.libraryNames = ArrayUtils.add(mPkg.libraryNames, libraryName);
-        return this;
-    }
-
-    PackageBuilder setRealPackageName(String realPackageName) {
-        mPkg.mRealPackage = realPackageName;
-        return this;
-    }
-
-    PackageBuilder setCpuAbiOVerride(String cpuAbiOverride) {
-        mPkg.cpuAbiOverride = cpuAbiOverride;
-        return this;
-    }
-
-    PackageBuilder addPermissionRequest(String permissionName) {
-        mPkg.requestedPermissions.add(permissionName);
-        return this;
-    }
-
-    PackageParser.Package build() {
-        return mPkg;
-    }
-
-    public PackageBuilder addApplicationInfoFlag(int flag) {
-        mPkg.applicationInfo.flags |= flag;
-        return this;
-    }
-
-    public PackageBuilder setApplicationInfoTargetSdkVersion(int versionCode) {
-        mPkg.applicationInfo.targetSdkVersion = versionCode;
-        return this;
-    }
-
-    public PackageBuilder setQueriesIntents(Collection<Intent> queriesIntents) {
-        mPkg.mQueriesIntents = new ArrayList<>(queriesIntents);
-        return this;
-    }
-
-    public PackageBuilder setQueriesIntents(Intent... intents) {
-        return setQueriesIntents(Arrays.asList(intents));
-    }
-
-    public PackageBuilder setQueriesPackages(Collection<String> queriesPackages) {
-        mPkg.mQueriesPackages = new ArrayList<>(queriesPackages);
-        return this;
-    }
-
-    public PackageBuilder setQueriesPackages(String... queriesPackages) {
-        return setQueriesPackages(Arrays.asList(queriesPackages));
-    }
-
-    public PackageBuilder setForceQueryable(boolean forceQueryable) {
-        mPkg.mForceQueryable = forceQueryable;
-        return this;
-    }
-
-    public interface ParseComponentArgsCreator {
-        PackageParser.ParseComponentArgs create(PackageParser.Package pkg);
-    }
-
-    public PackageBuilder addActivity(ParseComponentArgsCreator argsCreator, ActivityInfo info) {
-        mPkg.activities.add(new PackageParser.Activity(argsCreator.create(mPkg), info));
-        return this;
-    }
-
-    public interface ActivityIntentInfoCreator {
-        PackageParser.ActivityIntentInfo create(PackageParser.Activity activity);
-    }
-
-    public PackageBuilder addActivityIntentInfo(
-            int activityIndex, ActivityIntentInfoCreator creator) {
-        final PackageParser.Activity activity = mPkg.activities.get(activityIndex);
-        activity.intents.add(creator.create(activity));
-        return this;
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index 0a310d1..85840e1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -87,7 +87,7 @@
         setting = new PackageSetting("name", "realName", new File("codePath"),
                 new File("resourcePath"), "legacyNativeLibraryPathString",
                 "primaryCpuAbiString", "secondaryCpuAbiString",
-                "cpuAbiOverrideString", 0, 0, 0, "parentPackageName", null, 0,
+                "cpuAbiOverrideString", 0, 0, 0, 0,
                 null, null);
         pri.populateUsers(new int[] {
                 1, 2, 3, 4, 5
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 1106be2..8329227 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -403,10 +403,6 @@
 
     private static final String PACKAGE_NAME = "com.android.bar";
     private static final String REAL_PACKAGE_NAME = "com.android.foo";
-    private static final String PARENT_PACKAGE_NAME = "com.android.bar.parent";
-    private static final String CHILD_PACKAGE_NAME_01 = "com.android.bar.child01";
-    private static final String CHILD_PACKAGE_NAME_02 = "com.android.bar.child02";
-    private static final String CHILD_PACKAGE_NAME_03 = "com.android.bar.child03";
     private static final File INITIAL_CODE_PATH =
             new File(InstrumentationRegistry.getContext().getFilesDir(), "com.android.bar-1");
     private static final File UPDATED_CODE_PATH =
@@ -416,10 +412,6 @@
 
     @Test
     public void testPackageStateCopy01() {
-        final List<String> childPackageNames = new ArrayList<>();
-        childPackageNames.add(CHILD_PACKAGE_NAME_01);
-        childPackageNames.add(CHILD_PACKAGE_NAME_02);
-        childPackageNames.add(CHILD_PACKAGE_NAME_03);
         final PackageSetting origPkgSetting01 = new PackageSetting(
                 PACKAGE_NAME,
                 REAL_PACKAGE_NAME,
@@ -432,8 +424,6 @@
                 INITIAL_VERSION_CODE,
                 ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_HAS_CODE,
                 ApplicationInfo.PRIVATE_FLAG_PRIVILEGED|ApplicationInfo.PRIVATE_FLAG_HIDDEN,
-                PARENT_PACKAGE_NAME,
-                childPackageNames,
                 0,
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -443,10 +433,6 @@
 
     @Test
     public void testPackageStateCopy02() {
-        final List<String> childPackageNames = new ArrayList<>();
-        childPackageNames.add(CHILD_PACKAGE_NAME_01);
-        childPackageNames.add(CHILD_PACKAGE_NAME_02);
-        childPackageNames.add(CHILD_PACKAGE_NAME_03);
         final PackageSetting origPkgSetting01 = new PackageSetting(
                 PACKAGE_NAME /*pkgName*/,
                 REAL_PACKAGE_NAME /*realPkgName*/,
@@ -459,8 +445,6 @@
                 INITIAL_VERSION_CODE,
                 ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_HAS_CODE,
                 ApplicationInfo.PRIVATE_FLAG_PRIVILEGED|ApplicationInfo.PRIVATE_FLAG_HIDDEN,
-                PARENT_PACKAGE_NAME,
-                childPackageNames,
                 0,
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -476,8 +460,6 @@
                 UPDATED_VERSION_CODE,
                 0 /*pkgFlags*/,
                 0 /*pkgPrivateFlags*/,
-                null /*parentPkgName*/,
-                null /*childPkgNames*/,
                 0,
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -505,7 +487,6 @@
                 "armeabi" /*secondaryCpuAbi*/,
                 0 /*pkgFlags*/,
                 0 /*pkgPrivateFlags*/,
-                null /*childPkgNames*/,
                 UserManagerService.getInstance(),
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -539,7 +520,6 @@
                 "armeabi" /*secondaryCpuAbi*/,
                 ApplicationInfo.FLAG_SYSTEM /*pkgFlags*/,
                 ApplicationInfo.PRIVATE_FLAG_PRIVILEGED /*pkgPrivateFlags*/,
-                null /*childPkgNames*/,
                 UserManagerService.getInstance(),
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -579,7 +559,6 @@
                     "armeabi" /*secondaryCpuAbi*/,
                     0 /*pkgFlags*/,
                     0 /*pkgPrivateFlags*/,
-                    null /*childPkgNames*/,
                     UserManagerService.getInstance(),
                     null /*usesStaticLibraries*/,
                     null /*usesStaticLibrariesVersions*/);
@@ -612,8 +591,6 @@
                 false /*allowInstall*/,
                 false /*instantApp*/,
                 false /*virtualPreload*/,
-                null /*parentPkgName*/,
-                null /*childPkgNames*/,
                 UserManagerService.getInstance(),
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -653,8 +630,6 @@
                 true /*allowInstall*/,
                 false /*instantApp*/,
                 false /*virtualPreload*/,
-                null /*parentPkgName*/,
-                null /*childPkgNames*/,
                 UserManagerService.getInstance(),
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -700,8 +675,6 @@
                 false /*allowInstall*/,
                 false /*instantApp*/,
                 false /*virtualPreload*/,
-                null /*parentPkgName*/,
-                null /*childPkgNames*/,
                 UserManagerService.getInstance(),
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -744,8 +717,6 @@
                 false /*allowInstall*/,
                 false /*instantApp*/,
                 false /*virtualPreload*/,
-                null /*parentPkgName*/,
-                null /*childPkgNames*/,
                 UserManagerService.getInstance(),
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -802,9 +773,6 @@
     private void verifySettingCopy(PackageSetting origPkgSetting, PackageSetting testPkgSetting) {
         assertThat(origPkgSetting, is(not(testPkgSetting)));
         assertThat(origPkgSetting.appId, is(testPkgSetting.appId));
-        // different but equal objects
-        assertNotSame(origPkgSetting.childPackageNames, testPkgSetting.childPackageNames);
-        assertThat(origPkgSetting.childPackageNames, is(testPkgSetting.childPackageNames));
         assertSame(origPkgSetting.codePath, testPkgSetting.codePath);
         assertThat(origPkgSetting.codePath, is(testPkgSetting.codePath));
         assertSame(origPkgSetting.codePathString, testPkgSetting.codePathString);
@@ -828,8 +796,6 @@
         // mOldCodePaths is _not_ copied
         // assertNotSame(origPkgSetting.mOldCodePaths, testPkgSetting.mOldCodePaths);
         // assertThat(origPkgSetting.mOldCodePaths, is(not(testPkgSetting.mOldCodePaths)));
-        assertSame(origPkgSetting.parentPackageName, testPkgSetting.parentPackageName);
-        assertThat(origPkgSetting.parentPackageName, is(testPkgSetting.parentPackageName));
         assertSame(origPkgSetting.pkg, testPkgSetting.pkg);
         // No equals() method for this object
         // assertThat(origPkgSetting.pkg, is(testPkgSetting.pkg));
@@ -881,8 +847,6 @@
                 INITIAL_VERSION_CODE,
                 pkgFlags,
                 0 /*privateFlags*/,
-                null /*parentPackageName*/,
-                null /*childPackageNames*/,
                 sharedUserId,
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
@@ -901,8 +865,6 @@
                 INITIAL_VERSION_CODE,
                 0,
                 0 /*privateFlags*/,
-                null /*parentPackageName*/,
-                null /*childPackageNames*/,
                 0,
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index e33d8ca..56ac7c5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -15,35 +15,49 @@
  */
 package com.android.server.pm;
 
-import static android.content.res.Resources.ID_NULL;
-
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
-import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ConfigurationInfo;
 import android.content.pm.FeatureGroupInfo;
 import android.content.pm.FeatureInfo;
-import android.content.pm.InstrumentationInfo;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageParser;
+import android.content.pm.PackageUserState;
 import android.content.pm.ProviderInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.Signature;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
+import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
+import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
+import android.content.pm.parsing.ComponentParseUtils.ParsedService;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.PackageInfoUtils;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.ParsingPackage;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.platform.test.annotations.Presubmit;
-import android.util.ArrayMap;
 import android.util.ArraySet;
 
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.util.ArrayUtils;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -57,6 +71,7 @@
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -64,6 +79,9 @@
 @RunWith(AndroidJUnit4.class)
 @MediumTest
 public class PackageParserTest {
+    // TODO(b/135203078): Update this test with all fields and validate equality. Initial change
+    //  was just migrating to new interfaces. Consider adding actual equals() methods.
+
     @Rule
     public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
 
@@ -79,12 +97,12 @@
     @Test
     public void testParse_noCache() throws Exception {
         PackageParser pp = new CachePackageNameParser();
-        PackageParser.Package pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
+        ParsedPackage pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */,
                 false /* useCaches */);
         assertNotNull(pkg);
 
         pp.setCacheDir(mTmpDir);
-        pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
+        pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */,
                 false /* useCaches */);
         assertNotNull(pkg);
 
@@ -99,27 +117,27 @@
 
         pp.setCacheDir(mTmpDir);
         // The first parse will write this package to the cache.
-        pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
+        pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
 
         // Now attempt to parse the package again, should return the
         // cached result.
-        PackageParser.Package pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
+        ParsedPackage pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */,
                 true /* useCaches */);
-        assertEquals("cache_android", pkg.packageName);
+        assertEquals("cache_android", pkg.getPackageName());
 
         // Try again, with useCaches == false, shouldn't return the parsed
         // result.
-        pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */);
-        assertEquals("android", pkg.packageName);
+        pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */);
+        assertEquals("android", pkg.getPackageName());
 
         // We haven't set a cache directory here : the parse should still succeed,
         // just not using the cached results.
         pp = new CachePackageNameParser();
-        pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
-        assertEquals("android", pkg.packageName);
+        pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
+        assertEquals("android", pkg.getPackageName());
 
-        pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */);
-        assertEquals("android", pkg.packageName);
+        pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */);
+        assertEquals("android", pkg.getPackageName());
     }
 
     @Test
@@ -127,14 +145,14 @@
         PackageParser pp = new PackageParser();
         pp.setCacheDir(mTmpDir);
 
-        PackageParser.Package pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
-            true /* useCaches */);
+        ParsedPackage pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */,
+                true /* useCaches */);
 
         Parcel p = Parcel.obtain();
         pkg.writeToParcel(p, 0 /* flags */);
 
         p.setDataPosition(0);
-        PackageParser.Package deserialized = new PackageParser.Package(p);
+        ParsedPackage deserialized = new PackageImpl(p);
 
         assertPackagesEqual(pkg, deserialized);
     }
@@ -143,154 +161,164 @@
     @SmallTest
     @Presubmit
     public void test_roundTripKnownFields() throws Exception {
-        PackageParser.Package pkg = new PackageParser.Package("foo");
+        ParsingPackage pkg = PackageImpl.forParsing("foo");
         setKnownFields(pkg);
 
         Parcel p = Parcel.obtain();
         pkg.writeToParcel(p, 0 /* flags */);
 
         p.setDataPosition(0);
-        PackageParser.Package deserialized = new PackageParser.Package(p);
+        ParsedPackage deserialized = new PackageImpl(p);
         assertAllFieldsExist(deserialized);
     }
 
     @Test
     public void test_stringInterning() throws Exception {
-        PackageParser.Package pkg = new PackageParser.Package("foo");
+        ParsingPackage pkg = PackageImpl.forParsing("foo");
         setKnownFields(pkg);
 
         Parcel p = Parcel.obtain();
         pkg.writeToParcel(p, 0 /* flags */);
 
         p.setDataPosition(0);
-        PackageParser.Package deserialized = new PackageParser.Package(p);
+        ParsingPackage deserialized = new PackageImpl(p);
 
         p.setDataPosition(0);
-        PackageParser.Package deserialized2 = new PackageParser.Package(p);
+        ParsingPackage deserialized2 = new PackageImpl(p);
 
-        assertSame(deserialized.packageName, deserialized2.packageName);
-        assertSame(deserialized.applicationInfo.permission,
-                deserialized2.applicationInfo.permission);
-        assertSame(deserialized.requestedPermissions.get(0),
-                deserialized2.requestedPermissions.get(0));
-        assertSame(deserialized.protectedBroadcasts.get(0),
-                deserialized2.protectedBroadcasts.get(0));
-        assertSame(deserialized.usesLibraries.get(0),
-                deserialized2.usesLibraries.get(0));
-        assertSame(deserialized.usesOptionalLibraries.get(0),
-                deserialized2.usesOptionalLibraries.get(0));
-        assertSame(deserialized.mVersionName, deserialized2.mVersionName);
-        assertSame(deserialized.mSharedUserId, deserialized2.mSharedUserId);
+        assertSame(deserialized.getPackageName(), deserialized2.getPackageName());
+        assertSame(deserialized.getPermission(),
+                deserialized2.getPermission());
+        assertSame(deserialized.getRequestedPermissions().get(0),
+                deserialized2.getRequestedPermissions().get(0));
+
+        List<String> protectedBroadcastsOne = new ArrayList<>(1);
+        protectedBroadcastsOne.addAll(deserialized.getProtectedBroadcasts());
+
+        List<String> protectedBroadcastsTwo = new ArrayList<>(1);
+        protectedBroadcastsTwo.addAll(deserialized2.getProtectedBroadcasts());
+
+        assertSame(protectedBroadcastsOne.get(0), protectedBroadcastsTwo.get(0));
+
+        assertSame(deserialized.getUsesLibraries().get(0),
+                deserialized2.getUsesLibraries().get(0));
+        assertSame(deserialized.getUsesOptionalLibraries().get(0),
+                deserialized2.getUsesOptionalLibraries().get(0));
+        assertSame(deserialized.getVersionName(), deserialized2.getVersionName());
+        assertSame(deserialized.getSharedUserId(), deserialized2.getSharedUserId());
     }
 
-
     /**
      * A trivial subclass of package parser that only caches the package name, and throws away
      * all other information.
      */
     public static class CachePackageNameParser extends PackageParser {
         @Override
-        public byte[] toCacheEntry(Package pkg) {
-            return ("cache_" + pkg.packageName).getBytes(StandardCharsets.UTF_8);
+        public byte[] toCacheEntry(ParsedPackage pkg) {
+            return ("cache_" + pkg.getPackageName()).getBytes(StandardCharsets.UTF_8);
         }
 
         @Override
-        public Package fromCacheEntry(byte[] cacheEntry) {
-            return new Package(new String(cacheEntry, StandardCharsets.UTF_8));
+        public ParsedPackage fromCacheEntry(byte[] cacheEntry) {
+            return PackageImpl.forParsing(new String(cacheEntry, StandardCharsets.UTF_8))
+                    .hideAsParsed();
         }
     }
 
     // NOTE: The equality assertions below are based on code autogenerated by IntelliJ.
 
-    public static void assertPackagesEqual(PackageParser.Package a, PackageParser.Package b) {
-        assertEquals(a.baseRevisionCode, b.baseRevisionCode);
-        assertEquals(a.baseHardwareAccelerated, b.baseHardwareAccelerated);
-        assertEquals(a.mVersionCode, b.mVersionCode);
-        assertEquals(a.mSharedUserLabel, b.mSharedUserLabel);
-        assertEquals(a.mPreferredOrder, b.mPreferredOrder);
-        assertEquals(a.installLocation, b.installLocation);
-        assertEquals(a.coreApp, b.coreApp);
-        assertEquals(a.mRequiredForAllUsers, b.mRequiredForAllUsers);
-        assertEquals(a.mCompileSdkVersion, b.mCompileSdkVersion);
-        assertEquals(a.mCompileSdkVersionCodename, b.mCompileSdkVersionCodename);
-        assertEquals(a.use32bitAbi, b.use32bitAbi);
-        assertEquals(a.packageName, b.packageName);
-        assertTrue(Arrays.equals(a.splitNames, b.splitNames));
-        assertEquals(a.volumeUuid, b.volumeUuid);
-        assertEquals(a.codePath, b.codePath);
-        assertEquals(a.baseCodePath, b.baseCodePath);
-        assertTrue(Arrays.equals(a.splitCodePaths, b.splitCodePaths));
-        assertTrue(Arrays.equals(a.splitRevisionCodes, b.splitRevisionCodes));
-        assertTrue(Arrays.equals(a.splitFlags, b.splitFlags));
-        assertTrue(Arrays.equals(a.splitPrivateFlags, b.splitPrivateFlags));
-        assertApplicationInfoEqual(a.applicationInfo, b.applicationInfo);
+    public static void assertPackagesEqual(AndroidPackage a, AndroidPackage b) {
+        assertEquals(a.getBaseRevisionCode(), b.getBaseRevisionCode());
+        assertEquals(a.isBaseHardwareAccelerated(), b.isBaseHardwareAccelerated());
+        assertEquals(a.getVersionCode(), b.getVersionCode());
+        assertEquals(a.getSharedUserLabel(), b.getSharedUserLabel());
+        assertEquals(a.getPreferredOrder(), b.getPreferredOrder());
+        assertEquals(a.getInstallLocation(), b.getInstallLocation());
+        assertEquals(a.isCoreApp(), b.isCoreApp());
+        assertEquals(a.isRequiredForAllUsers(), b.isRequiredForAllUsers());
+        assertEquals(a.getCompileSdkVersion(), b.getCompileSdkVersion());
+        assertEquals(a.getCompileSdkVersionCodeName(), b.getCompileSdkVersionCodeName());
+        assertEquals(a.isUse32BitAbi(), b.isUse32BitAbi());
+        assertEquals(a.getPackageName(), b.getPackageName());
+        assertArrayEquals(a.getSplitNames(), b.getSplitNames());
+        assertEquals(a.getVolumeUuid(), b.getVolumeUuid());
+        assertEquals(a.getCodePath(), b.getCodePath());
+        assertEquals(a.getBaseCodePath(), b.getBaseCodePath());
+        assertArrayEquals(a.getSplitCodePaths(), b.getSplitCodePaths());
+        assertArrayEquals(a.getSplitRevisionCodes(), b.getSplitRevisionCodes());
+        assertArrayEquals(a.getSplitFlags(), b.getSplitFlags());
 
-        assertEquals(a.permissions.size(), b.permissions.size());
-        for (int i = 0; i < a.permissions.size(); ++i) {
-            assertPermissionsEqual(a.permissions.get(i), b.permissions.get(i));
-            assertSame(a.permissions.get(i).owner, a);
-            assertSame(b.permissions.get(i).owner, b);
+        PackageInfo aInfo = PackageInfoUtils.generate(a, new int[]{}, 0, 0, 0,
+                Collections.emptySet(), new PackageUserState(), 0);
+        PackageInfo bInfo = PackageInfoUtils.generate(b, new int[]{}, 0, 0, 0,
+                Collections.emptySet(), new PackageUserState(), 0);
+        assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo);
+
+        assertEquals(ArrayUtils.size(a.getPermissions()), ArrayUtils.size(b.getPermissions()));
+        for (int i = 0; i < ArrayUtils.size(a.getPermissions()); ++i) {
+            assertPermissionsEqual(a.getPermissions().get(i), b.getPermissions().get(i));
         }
 
-        assertEquals(a.permissionGroups.size(), b.permissionGroups.size());
-        for (int i = 0; i < a.permissionGroups.size(); ++i) {
-            assertPermissionGroupsEqual(a.permissionGroups.get(i), b.permissionGroups.get(i));
+        assertEquals(ArrayUtils.size(a.getPermissionGroups()),
+                ArrayUtils.size(b.getPermissionGroups()));
+        for (int i = 0; i < a.getPermissionGroups().size(); ++i) {
+            assertPermissionGroupsEqual(a.getPermissionGroups().get(i),
+                    b.getPermissionGroups().get(i));
         }
 
-        assertEquals(a.activities.size(), b.activities.size());
-        for (int i = 0; i < a.activities.size(); ++i) {
-            assertActivitiesEqual(a.activities.get(i), b.activities.get(i));
+        assertEquals(ArrayUtils.size(a.getActivities()), ArrayUtils.size(b.getActivities()));
+        for (int i = 0; i < ArrayUtils.size(a.getActivities()); ++i) {
+            assertActivitiesEqual(a, a.getActivities().get(i), b, b.getActivities().get(i));
         }
 
-        assertEquals(a.receivers.size(), b.receivers.size());
-        for (int i = 0; i < a.receivers.size(); ++i) {
-            assertActivitiesEqual(a.receivers.get(i), b.receivers.get(i));
+        assertEquals(ArrayUtils.size(a.getReceivers()), ArrayUtils.size(b.getReceivers()));
+        for (int i = 0; i < ArrayUtils.size(a.getReceivers()); ++i) {
+            assertActivitiesEqual(a, a.getReceivers().get(i), b, b.getReceivers().get(i));
         }
 
-        assertEquals(a.providers.size(), b.providers.size());
-        for (int i = 0; i < a.providers.size(); ++i) {
-            assertProvidersEqual(a.providers.get(i), b.providers.get(i));
+        assertEquals(ArrayUtils.size(a.getProviders()), ArrayUtils.size(b.getProviders()));
+        for (int i = 0; i < ArrayUtils.size(a.getProviders()); ++i) {
+            assertProvidersEqual(a, a.getProviders().get(i), b, b.getProviders().get(i));
         }
 
-        assertEquals(a.services.size(), b.services.size());
-        for (int i = 0; i < a.services.size(); ++i) {
-            assertServicesEqual(a.services.get(i), b.services.get(i));
+        assertEquals(ArrayUtils.size(a.getServices()), ArrayUtils.size(b.getServices()));
+        for (int i = 0; i < ArrayUtils.size(a.getServices()); ++i) {
+            assertServicesEqual(a, a.getServices().get(i), b, b.getServices().get(i));
         }
 
-        assertEquals(a.instrumentation.size(), b.instrumentation.size());
-        for (int i = 0; i < a.instrumentation.size(); ++i) {
-            assertInstrumentationEqual(a.instrumentation.get(i), b.instrumentation.get(i));
+        assertEquals(ArrayUtils.size(a.getInstrumentations()),
+                ArrayUtils.size(b.getInstrumentations()));
+        for (int i = 0; i < ArrayUtils.size(a.getInstrumentations()); ++i) {
+            assertInstrumentationEqual(a.getInstrumentations().get(i),
+                    b.getInstrumentations().get(i));
         }
 
-        assertEquals(a.requestedPermissions, b.requestedPermissions);
-        assertEquals(a.protectedBroadcasts, b.protectedBroadcasts);
-        assertEquals(a.parentPackage, b.parentPackage);
-        assertEquals(a.childPackages, b.childPackages);
-        assertEquals(a.libraryNames, b.libraryNames);
-        assertEquals(a.usesLibraries, b.usesLibraries);
-        assertEquals(a.usesOptionalLibraries, b.usesOptionalLibraries);
-        assertTrue(Arrays.equals(a.usesLibraryFiles, b.usesLibraryFiles));
-        assertEquals(a.mOriginalPackages, b.mOriginalPackages);
-        assertEquals(a.mRealPackage, b.mRealPackage);
-        assertEquals(a.mAdoptPermissions, b.mAdoptPermissions);
-        assertBundleApproximateEquals(a.mAppMetaData, b.mAppMetaData);
-        assertEquals(a.mVersionName, b.mVersionName);
-        assertEquals(a.mSharedUserId, b.mSharedUserId);
-        assertTrue(Arrays.equals(a.mSigningDetails.signatures, b.mSigningDetails.signatures));
-        assertTrue(Arrays.equals(a.mLastPackageUsageTimeInMills, b.mLastPackageUsageTimeInMills));
-        assertEquals(a.mExtras, b.mExtras);
-        assertEquals(a.mRestrictedAccountType, b.mRestrictedAccountType);
-        assertEquals(a.mRequiredAccountType, b.mRequiredAccountType);
-        assertEquals(a.mOverlayTarget, b.mOverlayTarget);
-        assertEquals(a.mOverlayTargetName, b.mOverlayTargetName);
-        assertEquals(a.mOverlayCategory, b.mOverlayCategory);
-        assertEquals(a.mOverlayPriority, b.mOverlayPriority);
-        assertEquals(a.mOverlayIsStatic, b.mOverlayIsStatic);
-        assertEquals(a.mSigningDetails.publicKeys, b.mSigningDetails.publicKeys);
-        assertEquals(a.mUpgradeKeySets, b.mUpgradeKeySets);
-        assertEquals(a.mKeySetMapping, b.mKeySetMapping);
-        assertEquals(a.cpuAbiOverride, b.cpuAbiOverride);
-        assertTrue(Arrays.equals(a.restrictUpdateHash, b.restrictUpdateHash));
+        assertEquals(a.getRequestedPermissions(), b.getRequestedPermissions());
+        assertEquals(a.getProtectedBroadcasts(), b.getProtectedBroadcasts());
+        assertEquals(a.getLibraryNames(), b.getLibraryNames());
+        assertEquals(a.getUsesLibraries(), b.getUsesLibraries());
+        assertEquals(a.getUsesOptionalLibraries(), b.getUsesOptionalLibraries());
+        assertArrayEquals(a.getUsesLibraryFiles(), b.getUsesLibraryFiles());
+        assertEquals(a.getOriginalPackages(), b.getOriginalPackages());
+        assertEquals(a.getRealPackage(), b.getRealPackage());
+        assertEquals(a.getAdoptPermissions(), b.getAdoptPermissions());
+        assertBundleApproximateEquals(a.getAppMetaData(), b.getAppMetaData());
+        assertEquals(a.getVersionName(), b.getVersionName());
+        assertEquals(a.getSharedUserId(), b.getSharedUserId());
+        assertArrayEquals(a.getSigningDetails().signatures, b.getSigningDetails().signatures);
+        assertArrayEquals(a.getLastPackageUsageTimeInMills(), b.getLastPackageUsageTimeInMills());
+        assertEquals(a.getRestrictedAccountType(), b.getRestrictedAccountType());
+        assertEquals(a.getRequiredAccountType(), b.getRequiredAccountType());
+        assertEquals(a.getOverlayTarget(), b.getOverlayTarget());
+        assertEquals(a.getOverlayTargetName(), b.getOverlayTargetName());
+        assertEquals(a.getOverlayCategory(), b.getOverlayCategory());
+        assertEquals(a.getOverlayPriority(), b.getOverlayPriority());
+        assertEquals(a.isOverlayIsStatic(), b.isOverlayIsStatic());
+        assertEquals(a.getSigningDetails().publicKeys, b.getSigningDetails().publicKeys);
+        assertEquals(a.getUpgradeKeySets(), b.getUpgradeKeySets());
+        assertEquals(a.getKeySetMapping(), b.getKeySetMapping());
+        assertEquals(a.getCpuAbiOverride(), b.getCpuAbiOverride());
+        assertArrayEquals(a.getRestrictUpdateHash(), b.getRestrictUpdateHash());
     }
 
     private static void assertBundleApproximateEquals(Bundle a, Bundle b) {
@@ -305,10 +333,10 @@
         assertEquals(a.toString(), b.toString());
     }
 
-    private static void assertComponentsEqual(PackageParser.Component<?> a,
-                                              PackageParser.Component<?> b) {
+    private static void assertComponentsEqual(ParsedComponent<?> a,
+            ParsedComponent<?> b) {
         assertEquals(a.className, b.className);
-        assertBundleApproximateEquals(a.metaData, b.metaData);
+        assertBundleApproximateEquals(a.getMetaData(), b.getMetaData());
         assertEquals(a.getComponentName(), b.getComponentName());
 
         if (a.intents != null && b.intents != null) {
@@ -318,80 +346,102 @@
         }
 
         for (int i = 0; i < a.intents.size(); ++i) {
-            PackageParser.IntentInfo aIntent = a.intents.get(i);
-            PackageParser.IntentInfo bIntent = b.intents.get(i);
+            ParsedIntentInfo aIntent = a.intents.get(i);
+            ParsedIntentInfo bIntent = b.intents.get(i);
 
             assertEquals(aIntent.hasDefault, bIntent.hasDefault);
             assertEquals(aIntent.labelRes, bIntent.labelRes);
             assertEquals(aIntent.nonLocalizedLabel, bIntent.nonLocalizedLabel);
             assertEquals(aIntent.icon, bIntent.icon);
-            assertEquals(aIntent.logo, bIntent.logo);
-            assertEquals(aIntent.banner, bIntent.banner);
-            assertEquals(aIntent.preferred, bIntent.preferred);
         }
     }
 
-    private static void assertPermissionsEqual(PackageParser.Permission a,
-                                               PackageParser.Permission b) {
+    private static void assertPermissionsEqual(ParsedPermission a,
+            ParsedPermission b) {
         assertComponentsEqual(a, b);
         assertEquals(a.tree, b.tree);
 
         // Verify basic flags in PermissionInfo to make sure they're consistent. We don't perform
         // a full structural equality here because the code that serializes them isn't parser
         // specific and is tested elsewhere.
-        assertEquals(a.info.protectionLevel, b.info.protectionLevel);
-        assertEquals(a.info.group, b.info.group);
-        assertEquals(a.info.flags, b.info.flags);
+        assertEquals(a.getProtection(), b.getProtection());
+        assertEquals(a.getGroup(), b.getGroup());
+        assertEquals(a.flags, b.flags);
 
-        if (a.group != null && b.group != null) {
-            assertPermissionGroupsEqual(a.group, b.group);
-        } else if (a.group != null || b.group != null) {
+        if (a.parsedPermissionGroup != null && b.parsedPermissionGroup != null) {
+            assertPermissionGroupsEqual(a.parsedPermissionGroup, b.parsedPermissionGroup);
+        } else if (a.parsedPermissionGroup != null || b.parsedPermissionGroup != null) {
             throw new AssertionError();
         }
     }
 
-    private static void assertInstrumentationEqual(PackageParser.Instrumentation a,
-                                                   PackageParser.Instrumentation b) {
+    private static void assertInstrumentationEqual(ParsedInstrumentation a,
+            ParsedInstrumentation b) {
         assertComponentsEqual(a, b);
 
         // Sanity check for InstrumentationInfo.
-        assertEquals(a.info.targetPackage, b.info.targetPackage);
-        assertEquals(a.info.targetProcesses, b.info.targetProcesses);
-        assertEquals(a.info.sourceDir, b.info.sourceDir);
-        assertEquals(a.info.publicSourceDir, b.info.publicSourceDir);
+        assertEquals(a.getTargetPackage(), b.getTargetPackage());
+        assertEquals(a.getTargetProcesses(), b.getTargetProcesses());
     }
 
-    private static void assertServicesEqual(PackageParser.Service a, PackageParser.Service b) {
+    private static void assertServicesEqual(
+            AndroidPackage aPkg,
+            ParsedService a,
+            AndroidPackage bPkg,
+            ParsedService b
+    ) {
         assertComponentsEqual(a, b);
 
         // Sanity check for ServiceInfo.
-        assertApplicationInfoEqual(a.info.applicationInfo, b.info.applicationInfo);
-        assertEquals(a.info.name, b.info.name);
+        ServiceInfo aInfo = PackageInfoUtils.generateServiceInfo(aPkg, a, 0, new PackageUserState(),
+                0);
+        ServiceInfo bInfo = PackageInfoUtils.generateServiceInfo(bPkg, b, 0, new PackageUserState(),
+                0);
+        assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo);
+        assertEquals(a.getName(), b.getName());
     }
 
-    private static void assertProvidersEqual(PackageParser.Provider a, PackageParser.Provider b) {
+    private static void assertProvidersEqual(
+            AndroidPackage aPkg,
+            ParsedProvider a,
+            AndroidPackage bPkg,
+            ParsedProvider b
+    ) {
         assertComponentsEqual(a, b);
 
         // Sanity check for ProviderInfo
-        assertApplicationInfoEqual(a.info.applicationInfo, b.info.applicationInfo);
-        assertEquals(a.info.name, b.info.name);
+        ProviderInfo aInfo = PackageInfoUtils.generateProviderInfo(aPkg, a, 0,
+                new PackageUserState(), 0);
+        ProviderInfo bInfo = PackageInfoUtils.generateProviderInfo(bPkg, b, 0,
+                new PackageUserState(), 0);
+        assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo);
+        assertEquals(a.getName(), b.getName());
     }
 
-    private static void assertActivitiesEqual(PackageParser.Activity a, PackageParser.Activity b) {
+    private static void assertActivitiesEqual(
+            AndroidPackage aPkg,
+            ParsedActivity a,
+            AndroidPackage bPkg,
+            ParsedActivity b
+    ) {
         assertComponentsEqual(a, b);
 
         // Sanity check for ActivityInfo.
-        assertApplicationInfoEqual(a.info.applicationInfo, b.info.applicationInfo);
-        assertEquals(a.info.name, b.info.name);
+        ActivityInfo aInfo = PackageInfoUtils.generateActivityInfo(aPkg, a, 0,
+                new PackageUserState(), 0);
+        ActivityInfo bInfo = PackageInfoUtils.generateActivityInfo(bPkg, b, 0,
+                new PackageUserState(), 0);
+        assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo);
+        assertEquals(a.getName(), b.getName());
     }
 
-    private static void assertPermissionGroupsEqual(PackageParser.PermissionGroup a,
-                                                    PackageParser.PermissionGroup b) {
+    private static void assertPermissionGroupsEqual(ParsedPermissionGroup a,
+            ParsedPermissionGroup b) {
         assertComponentsEqual(a, b);
 
         // Sanity check for PermissionGroupInfo.
-        assertEquals(a.info.name, b.info.name);
-        assertEquals(a.info.descriptionRes, b.info.descriptionRes);
+        assertEquals(a.getName(), b.getName());
+        assertEquals(a.descriptionRes, b.descriptionRes);
     }
 
     private static void assertApplicationInfoEqual(ApplicationInfo a, ApplicationInfo that) {
@@ -424,11 +474,11 @@
         assertEquals(a.scanPublicSourceDir, that.scanPublicSourceDir);
         assertEquals(a.sourceDir, that.sourceDir);
         assertEquals(a.publicSourceDir, that.publicSourceDir);
-        assertTrue(Arrays.equals(a.splitSourceDirs, that.splitSourceDirs));
-        assertTrue(Arrays.equals(a.splitPublicSourceDirs, that.splitPublicSourceDirs));
-        assertTrue(Arrays.equals(a.resourceDirs, that.resourceDirs));
+        assertArrayEquals(a.splitSourceDirs, that.splitSourceDirs);
+        assertArrayEquals(a.splitPublicSourceDirs, that.splitPublicSourceDirs);
+        assertArrayEquals(a.resourceDirs, that.resourceDirs);
         assertEquals(a.seInfo, that.seInfo);
-        assertTrue(Arrays.equals(a.sharedLibraryFiles, that.sharedLibraryFiles));
+        assertArrayEquals(a.sharedLibraryFiles, that.sharedLibraryFiles);
         assertEquals(a.dataDir, that.dataDir);
         assertEquals(a.deviceProtectedDataDir, that.deviceProtectedDataDir);
         assertEquals(a.credentialProtectedDataDir, that.credentialProtectedDataDir);
@@ -439,132 +489,93 @@
         assertEquals(a.secondaryCpuAbi, that.secondaryCpuAbi);
     }
 
-    public static void setKnownFields(PackageParser.Package pkg) {
-        pkg.baseRevisionCode = 100;
-        pkg.baseHardwareAccelerated = true;
-        pkg.mVersionCode = 100;
-        pkg.mSharedUserLabel = 100;
-        pkg.mPreferredOrder = 100;
-        pkg.installLocation = 100;
-        pkg.coreApp = true;
-        pkg.mRequiredForAllUsers = true;
-        pkg.use32bitAbi = true;
-        pkg.packageName = "foo";
-        pkg.splitNames = new String[] { "foo2" };
-        pkg.volumeUuid = "foo3";
-        pkg.codePath = "foo4";
-        pkg.baseCodePath = "foo5";
-        pkg.splitCodePaths = new String[] { "foo6" };
-        pkg.splitRevisionCodes = new int[] { 100 };
-        pkg.splitFlags = new int[] { 100 };
-        pkg.splitPrivateFlags = new int[] { 100 };
-        pkg.applicationInfo = new ApplicationInfo();
+    public static void setKnownFields(ParsingPackage pkg) {
+        Bundle bundle = new Bundle();
+        bundle.putString("key", "value");
 
-        pkg.permissions.add(new PackageParser.Permission(pkg, (String) null));
-        pkg.permissionGroups.add(new PackageParser.PermissionGroup(pkg, ID_NULL, ID_NULL, ID_NULL));
+        ParsedPermission permission = new ParsedPermission();
+        permission.parsedPermissionGroup = new ParsedPermissionGroup();
 
-        final PackageParser.ParseComponentArgs dummy = new PackageParser.ParseComponentArgs(
-                pkg, new String[1], 0, 0, 0, 0, 0, 0, null, 0, 0, 0);
-
-        pkg.activities.add(new PackageParser.Activity(dummy, new ActivityInfo()));
-        pkg.receivers.add(new PackageParser.Activity(dummy, new ActivityInfo()));
-        pkg.providers.add(new PackageParser.Provider(dummy, new ProviderInfo()));
-        pkg.services.add(new PackageParser.Service(dummy, new ServiceInfo()));
-        pkg.instrumentation.add(new PackageParser.Instrumentation(dummy, new InstrumentationInfo()));
-        pkg.requestedPermissions.add("foo7");
-        pkg.implicitPermissions.add("foo25");
-
-        pkg.protectedBroadcasts = new ArrayList<>();
-        pkg.protectedBroadcasts.add("foo8");
-
-        pkg.parentPackage = new PackageParser.Package("foo9");
-
-        pkg.childPackages = new ArrayList<>();
-        pkg.childPackages.add(new PackageParser.Package("bar"));
-
-        pkg.staticSharedLibName = "foo23";
-        pkg.staticSharedLibVersion = 100;
-        pkg.usesStaticLibraries = new ArrayList<>();
-        pkg.usesStaticLibraries.add("foo23");
-        pkg.usesStaticLibrariesCertDigests = new String[1][];
-        pkg.usesStaticLibrariesCertDigests[0] = new String[] { "digest" };
-        pkg.usesStaticLibrariesVersions = new long[] { 100 };
-
-        pkg.libraryNames = new ArrayList<>();
-        pkg.libraryNames.add("foo10");
-
-        pkg.usesLibraries = new ArrayList<>();
-        pkg.usesLibraries.add("foo11");
-
-        pkg.usesOptionalLibraries = new ArrayList<>();
-        pkg.usesOptionalLibraries.add("foo12");
-
-        pkg.usesLibraryFiles = new String[] { "foo13"};
-
-        pkg.usesLibraryInfos = new ArrayList<>();
-        pkg.usesLibraryInfos.add(
-                new SharedLibraryInfo(null, null, null, null, 0L, 0, null, null, null));
-
-        pkg.mOriginalPackages = new ArrayList<>();
-        pkg.mOriginalPackages.add("foo14");
-
-        pkg.mRealPackage = "foo15";
-
-        pkg.mAdoptPermissions = new ArrayList<>();
-        pkg.mAdoptPermissions.add("foo16");
-
-        pkg.mAppMetaData = new Bundle();
-        pkg.mVersionName = "foo17";
-        pkg.mSharedUserId = "foo18";
-        pkg.mSigningDetails =
-                new PackageParser.SigningDetails(
-                        new Signature[] { new Signature(new byte[16]) },
-                        2,
-                        new ArraySet<>(),
-                        null);
-        pkg.mExtras = new Bundle();
-        pkg.mRestrictedAccountType = "foo19";
-        pkg.mRequiredAccountType = "foo20";
-        pkg.mOverlayTarget = "foo21";
-        pkg.mOverlayPriority = 100;
-        pkg.mUpgradeKeySets = new ArraySet<>();
-        pkg.mKeySetMapping = new ArrayMap<>();
-        pkg.cpuAbiOverride = "foo22";
-        pkg.restrictUpdateHash = new byte[16];
-
-        pkg.preferredActivityFilters = new ArrayList<>();
-        pkg.preferredActivityFilters.add(new PackageParser.ActivityIntentInfo(
-                new PackageParser.Activity(dummy, new ActivityInfo())));
-
-        pkg.configPreferences = new ArrayList<>();
-        pkg.configPreferences.add(new ConfigurationInfo());
-
-        pkg.reqFeatures = new ArrayList<>();
-        pkg.reqFeatures.add(new FeatureInfo());
-
-        pkg.featureGroups = new ArrayList<>();
-        pkg.featureGroups.add(new FeatureGroupInfo());
-
-        pkg.mCompileSdkVersionCodename = "foo23";
-        pkg.mCompileSdkVersion = 100;
-        pkg.mVersionCodeMajor = 100;
-
-        pkg.mOverlayCategory = "foo24";
-        pkg.mOverlayIsStatic = true;
-        pkg.mOverlayTargetName = "foo26";
-
-        pkg.baseHardwareAccelerated = true;
-        pkg.coreApp = true;
-        pkg.mRequiredForAllUsers = true;
-        pkg.visibleToInstantApps = true;
-        pkg.use32bitAbi = true;
-        pkg.mForceQueryable = true;
-        pkg.mQueriesPackages = new ArrayList<>(Arrays.asList("foo27"));
-        pkg.mQueriesIntents = new ArrayList<>(Arrays.asList(new Intent("foo28")));
+        pkg.setBaseRevisionCode(100)
+                .setBaseHardwareAccelerated(true)
+                .setSharedUserLabel(100)
+                .setPreferredOrder(100)
+                .setInstallLocation(100)
+                .setRequiredForAllUsers(true)
+                .asSplit(
+                        new String[]{"foo2"},
+                        new String[]{"foo6"},
+                        new int[]{100},
+                        null
+                )
+                .setUse32BitAbi(true)
+                .setVolumeUuid("foo3")
+                .setCodePath("foo4")
+                .addPermission(permission)
+                .addPermissionGroup(new ParsedPermissionGroup())
+                .addActivity(new ParsedActivity())
+                .addReceiver(new ParsedActivity())
+                .addProvider(new ParsedProvider())
+                .addService(new ParsedService())
+                .addInstrumentation(new ParsedInstrumentation())
+                .addRequestedPermission("foo7")
+                .addImplicitPermission("foo25")
+                .addProtectedBroadcast("foo8")
+                .setStaticSharedLibName("foo23")
+                .setStaticSharedLibVersion(100)
+                .addUsesStaticLibrary("foo23")
+                .addUsesStaticLibraryCertDigests(new String[]{"digest"})
+                .addUsesStaticLibraryVersion(100)
+                .addLibraryName("foo10")
+                .addUsesLibrary("foo11")
+                .addUsesOptionalLibrary("foo12")
+                .addOriginalPackage("foo14")
+                .setRealPackage("foo15")
+                .addAdoptPermission("foo16")
+                .setAppMetaData(bundle)
+                .setVersionName("foo17")
+                .setSharedUserId("foo18")
+                .setSigningDetails(
+                        new PackageParser.SigningDetails(
+                                new Signature[]{new Signature(new byte[16])},
+                                2,
+                                new ArraySet<>(),
+                                null)
+                )
+                .setRestrictedAccountType("foo19")
+                .setRequiredAccountType("foo20")
+                .setOverlayTarget("foo21")
+                .setOverlayPriority(100)
+                .setUpgradeKeySets(new ArraySet<>())
+                .addPreferredActivityFilter(
+                        new ComponentParseUtils.ParsedActivityIntentInfo("foo", "className"))
+                .addConfigPreference(new ConfigurationInfo())
+                .addReqFeature(new FeatureInfo())
+                .addFeatureGroup(new FeatureGroupInfo())
+                .setCompileSdkVersionCodename("foo23")
+                .setCompileSdkVersion(100)
+                .setOverlayCategory("foo24")
+                .setOverlayIsStatic(true)
+                .setOverlayTargetName("foo26")
+                .setVisibleToInstantApps(true)
+                .setSplitHasCode(0, true)
+                .hideAsParsed()
+                .setBaseCodePath("foo5")
+                .setVersionCode(100)
+                .setCpuAbiOverride("foo22")
+                .setRestrictUpdateHash(new byte[16])
+                .setVersionCodeMajor(100)
+                .setCoreApp(true)
+                .hideAsFinal()
+                .mutate()
+                .setUsesLibraryInfos(Arrays.asList(
+                        new SharedLibraryInfo(null, null, null, null, 0L, 0, null, null, null)
+                ))
+                .setUsesLibraryFiles(new String[]{"foo13"});
     }
 
-    private static void assertAllFieldsExist(PackageParser.Package pkg) throws Exception {
-        Field[] fields = PackageParser.Package.class.getDeclaredFields();
+    private static void assertAllFieldsExist(ParsedPackage pkg) throws Exception {
+        Field[] fields = ParsedPackage.class.getDeclaredFields();
 
         Set<String> nonSerializedFields = new HashSet<>();
         nonSerializedFields.add("mExtras");
@@ -601,7 +612,7 @@
             } else if (fieldType == boolean.class) {
                 // boolean fields: Check that they're set to true.
                 boolean value = (boolean) f.get(pkg);
-                assertEquals("Bad value for field: " + f, true, value);
+                assertTrue("Bad value for field: " + f, value);
             } else {
                 // All other fields: Check that they're set.
                 Object o = f.get(pkg);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
index 8d476f6..2473997 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
@@ -16,14 +16,13 @@
 
 package com.android.server.pm;
 
-import android.content.pm.PackageParser;
 import android.content.pm.PackageUserState;
+import android.content.pm.parsing.AndroidPackage;
 import android.util.SparseArray;
 
 import java.io.File;
-import java.util.List;
 
-class PackageSettingBuilder {
+public class PackageSettingBuilder {
     private String mName;
     private String mRealName;
     private String mCodePath;
@@ -35,17 +34,15 @@
     private long mPVersionCode;
     private int mPkgFlags;
     private int mPrivateFlags;
-    private String mParentPackageName;
-    private List<String> mChildPackageNames;
     private int mSharedUserId;
     private String[] mUsesStaticLibraries;
     private long[] mUsesStaticLibrariesVersions;
     private String mVolumeUuid;
     private SparseArray<PackageUserState> mUserStates = new SparseArray<>();
-    private PackageParser.Package mPkg;
+    private AndroidPackage mPkg;
     private int mAppId;
 
-    public PackageSettingBuilder setPackage(PackageParser.Package pkg) {
+    public PackageSettingBuilder setPackage(AndroidPackage pkg) {
         this.mPkg = pkg;
         return this;
     }
@@ -111,16 +108,6 @@
         return this;
     }
 
-    public PackageSettingBuilder setParentPackageName(String parentPackageName) {
-        this.mParentPackageName = parentPackageName;
-        return this;
-    }
-
-    public PackageSettingBuilder setChildPackageNames(List<String> childPackageNames) {
-        this.mChildPackageNames = childPackageNames;
-        return this;
-    }
-
     public PackageSettingBuilder setSharedUserId(int sharedUserId) {
         this.mSharedUserId = sharedUserId;
         return this;
@@ -154,9 +141,8 @@
         final PackageSetting packageSetting = new PackageSetting(mName, mRealName,
                 new File(mCodePath), new File(mResourcePath),
                 mLegacyNativeLibraryPathString, mPrimaryCpuAbiString, mSecondaryCpuAbiString,
-                mCpuAbiOverrideString, mPVersionCode, mPkgFlags, mPrivateFlags, mParentPackageName,
-                mChildPackageNames, mSharedUserId, mUsesStaticLibraries,
-                mUsesStaticLibrariesVersions);
+                mCpuAbiOverrideString, mPVersionCode, mPkgFlags, mPrivateFlags, mSharedUserId,
+                mUsesStaticLibraries, mUsesStaticLibrariesVersions);
         packageSetting.pkg = mPkg;
         packageSetting.appId = mAppId;
         packageSetting.volumeUuid = this.mVolumeUuid;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
index d3a77d3..04e769d 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
@@ -16,8 +16,8 @@
 package com.android.server.pm;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -467,8 +467,7 @@
         File appPath = new File("/data/app/app");
         PackageSetting result = new PackageSetting("test.app", null, appPath, appPath,
                 "/data/app/app", null, null, null,
-                1, 940097092, 0, null,
-                null, 0 /*userId*/, null, null);
+                1, 940097092, 0, 0 /*userId*/, null, null);
         return result;
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
index 41489dc..a0efc8a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
@@ -17,6 +17,7 @@
 package com.android.server.pm;
 
 import android.content.pm.PackageParser;
+import android.content.pm.parsing.ParsedPackage;
 import android.util.Log;
 
 import androidx.test.runner.AndroidJUnit4;
@@ -74,7 +75,7 @@
         }
 
         @Override
-        protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile,
+        protected ParsedPackage parsePackage(PackageParser packageParser, File scanFile,
                 int parseFlags) throws PackageParser.PackageParserException {
             // Do not actually parse the package for testing
             return null;
diff --git a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
new file mode 100644
index 0000000..30108c6
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.pm;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.os.Build;
+import android.platform.test.annotations.Presubmit;
+
+import com.android.server.compat.PlatformCompat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+
+/**
+ * {@link SELinuxMMAC} tests.
+ */
+@RunWith(MockitoJUnitRunner.class)
+@Presubmit
+public class SELinuxMMACTest {
+
+    private static final String PACKAGE_NAME = "my.package";
+    private static final int OPT_IN_VERSION = Build.VERSION_CODES.R;
+
+    @Mock
+    PlatformCompat mMockCompatibility;
+
+    @Test
+    public void getSeInfoOptInToLatest() {
+        AndroidPackage pkg = makePackage(Build.VERSION_CODES.P);
+        when(mMockCompatibility.isChangeEnabled(eq(SELinuxMMAC.SELINUX_LATEST_CHANGES),
+                argThat(argument -> argument.packageName.equals(pkg.getPackageName()))))
+                .thenReturn(true);
+        assertThat(SELinuxMMAC.getSeInfo(pkg, null, mMockCompatibility),
+                is("default:targetSdkVersion=" + OPT_IN_VERSION));
+    }
+
+    @Test
+    public void getSeInfoNoOptIn() {
+        AndroidPackage pkg = makePackage(Build.VERSION_CODES.P);
+        when(mMockCompatibility.isChangeEnabled(eq(SELinuxMMAC.SELINUX_LATEST_CHANGES),
+                argThat(argument -> argument.packageName.equals(pkg.getPackageName()))))
+                .thenReturn(false);
+        assertThat(SELinuxMMAC.getSeInfo(pkg, null, mMockCompatibility),
+                is("default:targetSdkVersion=28"));
+    }
+
+    @Test
+    public void getSeInfoNoOptInButAlreadyR() {
+        AndroidPackage pkg = makePackage(OPT_IN_VERSION);
+        when(mMockCompatibility.isChangeEnabled(eq(SELinuxMMAC.SELINUX_LATEST_CHANGES),
+                argThat(argument -> argument.packageName.equals(pkg.getPackageName()))))
+                .thenReturn(false);
+        assertThat(SELinuxMMAC.getSeInfo(pkg, null, mMockCompatibility),
+                is("default:targetSdkVersion=" + OPT_IN_VERSION));
+    }
+
+    private AndroidPackage makePackage(int targetSdkVersion) {
+        return PackageImpl.forParsing(PACKAGE_NAME)
+                .setTargetSdkVersion(targetSdkVersion)
+                .hideAsParsed()
+                .hideAsFinal();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
index 34a3f86..11f154b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java
@@ -16,12 +16,13 @@
 
 package com.android.server.pm;
 
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ParsedPackage;
 import android.os.UserHandle;
 
 class ScanRequestBuilder {
-    private final PackageParser.Package mPkg;
-    private PackageParser.Package mOldPkg;
+    private final ParsedPackage mPkg;
+    private AndroidPackage mOldPkg;
     private SharedUserSetting mSharedUserSetting;
     private PackageSetting mPkgSetting;
     private PackageSetting mDisabledPkgSetting;
@@ -32,11 +33,11 @@
     private UserHandle mUser;
     private boolean mIsPlatformPackage;
 
-    ScanRequestBuilder(PackageParser.Package pkg) {
+    ScanRequestBuilder(ParsedPackage pkg) {
         this.mPkg = pkg;
     }
 
-    public ScanRequestBuilder setOldPkg(PackageParser.Package oldPkg) {
+    public ScanRequestBuilder setOldPkg(AndroidPackage oldPkg) {
         this.mOldPkg = oldPkg;
         return this;
     }
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
index 3ea3b3c..583cf58 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -35,19 +35,26 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import android.Manifest;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
-import android.content.pm.PackageParser;
 import android.content.pm.SharedLibraryInfo;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.PackageInfoUtils;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.res.TypedArray;
 import android.os.Environment;
 import android.os.UserHandle;
 import android.os.UserManagerInternal;
 import android.platform.test.annotations.Presubmit;
 import android.util.Pair;
 
+import com.android.server.compat.PlatformCompat;
+
 import org.hamcrest.BaseMatcher;
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
@@ -58,6 +65,7 @@
 import org.mockito.junit.MockitoJUnitRunner;
 
 import java.io.File;
+import java.util.UUID;
 
 @RunWith(MockitoJUnitRunner.class)
 @Presubmit
@@ -66,17 +74,23 @@
 
     private static final String DUMMY_PACKAGE_NAME = "some.app.to.test";
 
+    private static final UUID UUID_ONE = UUID.randomUUID();
+    private static final UUID UUID_TWO = UUID.randomUUID();
+
     @Mock
     PackageAbiHelper mMockPackageAbiHelper;
     @Mock
     UserManagerInternal mMockUserManager;
     @Mock
+    PlatformCompat mMockCompatibility;
+    @Mock
     PackageManagerService.Injector mMockInjector;
 
     @Before
     public void setupInjector() {
         when(mMockInjector.getAbiHelper()).thenReturn(mMockPackageAbiHelper);
         when(mMockInjector.getUserManagerInternal()).thenReturn(mMockUserManager);
+        when(mMockInjector.getCompatibility()).thenReturn(mMockCompatibility);
     }
 
     @Before
@@ -87,25 +101,25 @@
     @Before
     public void setupDefaultAbiBehavior() throws Exception {
         when(mMockPackageAbiHelper.derivePackageAbi(
-                any(PackageParser.Package.class), nullable(String.class), anyBoolean()))
+                any(ParsedPackage.class), nullable(String.class), anyBoolean()))
                 .thenReturn(new Pair<>(
                         new PackageAbiHelper.Abis("derivedPrimary", "derivedSecondary"),
                         new PackageAbiHelper.NativeLibraryPaths(
                                 "derivedRootDir", true, "derivedNativeDir", "derivedNativeDir2")));
         when(mMockPackageAbiHelper.getNativeLibraryPaths(
-                any(PackageParser.Package.class), any(File.class)))
+                any(ParsedPackage.class), any(File.class)))
                 .thenReturn(new PackageAbiHelper.NativeLibraryPaths(
                         "getRootDir", true, "getNativeDir", "getNativeDir2"
                 ));
         when(mMockPackageAbiHelper.getBundledAppAbis(
-                any(PackageParser.Package.class)))
+                any(ParsedPackage.class)))
                 .thenReturn(new PackageAbiHelper.Abis("bundledPrimary", "bundledSecondary"));
     }
 
     @Test
     public void newInstallSimpleAllNominal() throws Exception {
         final PackageManagerService.ScanRequest scanRequest =
-                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
                         .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
                         .build();
@@ -123,7 +137,7 @@
         when(mMockUserManager.getUserIds()).thenReturn(userIds);
 
         final PackageManagerService.ScanRequest scanRequest =
-                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .setRealPkgName(null)
                         .addScanFlag(PackageManagerService.SCAN_NEW_INSTALL)
                         .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
@@ -138,7 +152,7 @@
     @Test
     public void installRealPackageName() throws Exception {
         final PackageManagerService.ScanRequest scanRequest =
-                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .setRealPkgName("com.package.real")
                         .build();
 
@@ -149,7 +163,7 @@
         final PackageManagerService.ScanRequest scanRequestNoRealPkg =
                 createBasicScanRequestBuilder(
                         createBasicPackage(DUMMY_PACKAGE_NAME)
-                                .setRealPackageName("com.package.real").build())
+                                .setRealPackage("com.package.real"))
                         .build();
 
         final PackageManagerService.ScanResult scanResultNoReal = executeScan(scanRequestNoRealPkg);
@@ -165,7 +179,7 @@
                 .setSecondaryCpuAbiString("secondaryCpuAbi")
                 .build();
         final PackageManagerService.ScanRequest scanRequest =
-                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
                         .setPkgSetting(pkgSetting)
                         .build();
@@ -197,7 +211,7 @@
                         .build();
 
         final PackageManagerService.ScanRequest scanRequest =
-                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .setPkgSetting(existingPkgSetting)
                         .build();
 
@@ -209,17 +223,18 @@
 
     @Test
     public void installStaticSharedLibrary() throws Exception {
-        final PackageParser.Package pkg = createBasicPackage("static.lib.pkg.123")
-                .setStaticSharedLib("static.lib", 123L)
-                .setManifestPackageName("static.lib.pkg")
+        final ParsedPackage pkg = createBasicPackage("static.lib.pkg")
+                .setStaticSharedLibName("static.lib")
+                .setStaticSharedLibVersion(123L)
+                .hideAsParsed()
+                .setPackageName("static.lib.pkg.123")
                 .setVersionCodeMajor(1)
                 .setVersionCode(234)
                 .setBaseCodePath("/some/path.apk")
-                .addSplitCodePath("/some/other/path.apk")
-                .build();
+                .setSplitCodePaths(new String[] {"/some/other/path.apk"});
 
-        final PackageManagerService.ScanRequest scanRequest = new ScanRequestBuilder(
-                pkg).setUser(UserHandle.of(0)).build();
+        final PackageManagerService.ScanRequest scanRequest = new ScanRequestBuilder(pkg)
+                .setUser(UserHandle.of(0)).build();
 
 
         final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
@@ -240,15 +255,14 @@
 
     @Test
     public void installDynamicLibraries() throws Exception {
-        final PackageParser.Package pkg = createBasicPackage("dynamic.lib.pkg")
-                .setManifestPackageName("dynamic.lib.pkg")
+        final ParsedPackage pkg = createBasicPackage("dynamic.lib.pkg")
                 .addLibraryName("liba")
                 .addLibraryName("libb")
+                .hideAsParsed()
                 .setVersionCodeMajor(1)
                 .setVersionCode(234)
                 .setBaseCodePath("/some/path.apk")
-                .addSplitCodePath("/some/other/path.apk")
-                .build();
+                .setSplitCodePaths(new String[] {"/some/other/path.apk"});
 
         final PackageManagerService.ScanRequest scanRequest =
                 new ScanRequestBuilder(pkg).setUser(UserHandle.of(0)).build();
@@ -290,15 +304,15 @@
                         .setVolumeUuid("someUuid")
                         .build();
 
-        final PackageParser.Package basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
-                .setApplicationInfoVolumeUuid("someNewUuid")
-                .build();
+        final ParsedPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
+                .hideAsParsed()
+                .setApplicationVolumeUuid(UUID_TWO.toString());
 
 
         final PackageManagerService.ScanResult scanResult = executeScan(
                 new ScanRequestBuilder(basicPackage).setPkgSetting(pkgSetting).build());
 
-        assertThat(scanResult.pkgSetting.volumeUuid, is("someNewUuid"));
+        assertThat(scanResult.pkgSetting.volumeUuid, is(UUID_TWO.toString()));
     }
 
     @Test
@@ -306,10 +320,10 @@
         final PackageSetting pkgSetting =
                 createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME).build();
 
-        final PackageParser.Package basicPackage =
+        final ParsedPackage basicPackage =
                 createBasicPackage(DUMMY_PACKAGE_NAME)
-                        .setCpuAbiOVerride("testOverride")
-                        .build();
+                        .hideAsParsed()
+                        .setCpuAbiOverride("testOverride");
 
 
         final PackageManagerService.ScanResult scanResult = executeScan(new ScanRequestBuilder(
@@ -326,9 +340,9 @@
         final PackageSetting originalPkgSetting =
                 createBasicPackageSettingBuilder("original.package").build();
 
-        final PackageParser.Package basicPackage =
+        final ParsedPackage basicPackage =
                 createBasicPackage(DUMMY_PACKAGE_NAME)
-                        .build();
+                        .hideAsParsed();
 
 
         final PackageManagerService.ScanResult result =
@@ -336,7 +350,7 @@
                         .setOriginalPkgSetting(originalPkgSetting)
                         .build());
 
-        assertThat(result.request.pkg.packageName, is("original.package"));
+        assertThat(result.request.parsedPackage.getPackageName(), is("original.package"));
     }
 
     @Test
@@ -349,7 +363,7 @@
                         .build();
 
         final PackageManagerService.ScanRequest scanRequest =
-                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .setPkgSetting(existingPkgSetting)
                         .addScanFlag(SCAN_AS_FULL_APP)
                         .build();
@@ -370,7 +384,7 @@
                         .build();
 
         final PackageManagerService.ScanRequest scanRequest =
-                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .setPkgSetting(existingPkgSetting)
                         .addScanFlag(SCAN_AS_INSTANT_APP)
                         .build();
@@ -389,7 +403,7 @@
                         .build();
 
         final PackageManagerService.ScanRequest scanRequest =
-                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build())
+                createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME))
                         .setPkgSetting(existingPkgSetting)
                         .setDisabledPkgSetting(existingPkgSetting)
                         .addScanFlag(SCAN_NEW_INSTALL)
@@ -397,15 +411,14 @@
 
         final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);
 
-        assertThat(scanResult.request.pkg.applicationInfo.flags,
+        assertThat(scanResult.request.parsedPackage.getFlags(),
                 hasFlag(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP));
     }
 
     @Test
     public void factoryTestFlagSet() throws Exception {
-        final PackageParser.Package basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
-                .addPermissionRequest(Manifest.permission.FACTORY_TEST)
-                .build();
+        final ParsingPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME)
+                .addRequestedPermission(Manifest.permission.FACTORY_TEST);
 
         final PackageManagerService.ScanResult scanResult = PackageManagerService.scanPackageOnlyLI(
                 createBasicScanRequestBuilder(basicPackage).build(),
@@ -413,15 +426,15 @@
                 true /*isUnderFactoryTest*/,
                 System.currentTimeMillis());
 
-        assertThat(scanResult.request.pkg.applicationInfo.flags,
+        assertThat(scanResult.request.parsedPackage.getFlags(),
                 hasFlag(ApplicationInfo.FLAG_FACTORY_TEST));
     }
 
     @Test
     public void scanSystemApp_isOrphanedTrue() throws Exception {
-        final PackageParser.Package pkg = createBasicPackage(DUMMY_PACKAGE_NAME)
-                .addApplicationInfoFlag(ApplicationInfo.FLAG_SYSTEM)
-                .build();
+        final ParsedPackage pkg = createBasicPackage(DUMMY_PACKAGE_NAME)
+                .hideAsParsed()
+                .setSystem(true);
 
         final PackageManagerService.ScanRequest scanRequest =
                 createBasicScanRequestBuilder(pkg)
@@ -476,22 +489,29 @@
                 .setResourcePath(createResourcePath(packageName));
     }
 
-    private static ScanRequestBuilder createBasicScanRequestBuilder(PackageParser.Package pkg) {
+    private static ScanRequestBuilder createBasicScanRequestBuilder(ParsingPackage pkg) {
+        return new ScanRequestBuilder(pkg.hideAsParsed())
+                .setUser(UserHandle.of(0));
+    }
+
+    private static ScanRequestBuilder createBasicScanRequestBuilder(ParsedPackage pkg) {
         return new ScanRequestBuilder(pkg)
                 .setUser(UserHandle.of(0));
     }
 
-
-    private static PackageBuilder createBasicPackage(String packageName) {
-        return new PackageBuilder(packageName)
+    private static ParsingPackage createBasicPackage(String packageName) {
+        // TODO(b/135203078): Make this use PackageImpl.forParsing and separate the steps
+        return new PackageImpl(packageName, null, mock(TypedArray.class), false)
                 .setCodePath("/data/tmp/randompath")
                 .setApplicationInfoCodePath(createCodePath(packageName))
                 .setApplicationInfoResourcePath(createResourcePath(packageName))
-                .setApplicationInfoVolumeUuid("volumeUuid")
+                .setApplicationVolumeUuid(UUID_ONE.toString())
                 .setBaseCodePath("/data/tmp/randompath/base.apk")
-                .addUsesStaticLibrary("some.static.library", 234L)
-                .addUsesStaticLibrary("some.other.static.library", 456L)
-                .setApplicationInfoNativeLibraryRootDir("/data/tmp/randompath/base.apk:/lib")
+                .addUsesStaticLibrary("some.static.library")
+                .addUsesStaticLibraryVersion(234L)
+                .addUsesStaticLibrary("some.other.static.library")
+                .addUsesStaticLibraryVersion(456L)
+                .setNativeLibraryRootDir("/data/tmp/randompath/base.apk:/lib")
                 .setVersionCodeMajor(1)
                 .setVersionCode(2345);
     }
@@ -503,20 +523,19 @@
         final PackageSetting pkgSetting = scanResult.pkgSetting;
         assertBasicPackageSetting(scanResult, packageName, isInstant, pkgSetting);
 
-        final ApplicationInfo applicationInfo = pkgSetting.pkg.applicationInfo;
+        final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo(
+                pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0);
         assertBasicApplicationInfo(scanResult, applicationInfo);
-
     }
 
     private static void assertBasicPackageSetting(PackageManagerService.ScanResult scanResult,
             String packageName, boolean isInstant, PackageSetting pkgSetting) {
-        assertThat(pkgSetting.pkg.packageName, is(packageName));
+        assertThat(pkgSetting.pkg.getPackageName(), is(packageName));
         assertThat(pkgSetting.getInstantApp(0), is(isInstant));
         assertThat(pkgSetting.usesStaticLibraries,
                 arrayContaining("some.static.library", "some.other.static.library"));
         assertThat(pkgSetting.usesStaticLibrariesVersions, is(new long[]{234L, 456L}));
-        assertThat(pkgSetting.pkg, is(scanResult.request.pkg));
-        assertThat(pkgSetting.pkg.mExtras, is(pkgSetting));
+        assertThat(pkgSetting.pkg, is(scanResult.request.parsedPackage));
         assertThat(pkgSetting.codePath, is(new File(createCodePath(packageName))));
         assertThat(pkgSetting.resourcePath, is(new File(createResourcePath(packageName))));
         assertThat(pkgSetting.versionCode, is(PackageInfo.composeLongVersionCode(1, 2345)));
@@ -524,34 +543,39 @@
 
     private static void assertBasicApplicationInfo(PackageManagerService.ScanResult scanResult,
             ApplicationInfo applicationInfo) {
-        assertThat(applicationInfo.processName, is(scanResult.request.pkg.packageName));
+        assertThat(applicationInfo.processName,
+                is(scanResult.request.parsedPackage.getPackageName()));
 
         final int uid = applicationInfo.uid;
         assertThat(UserHandle.getUserId(uid), is(UserHandle.USER_SYSTEM));
 
         final String calculatedCredentialId = Environment.getDataUserCePackageDirectory(
                 applicationInfo.volumeUuid, UserHandle.USER_SYSTEM,
-                scanResult.request.pkg.packageName).getAbsolutePath();
+                scanResult.request.parsedPackage.getPackageName()).getAbsolutePath();
         assertThat(applicationInfo.credentialProtectedDataDir, is(calculatedCredentialId));
         assertThat(applicationInfo.dataDir, is(applicationInfo.credentialProtectedDataDir));
     }
 
     private static void assertAbiAndPathssDerived(PackageManagerService.ScanResult scanResult) {
-        final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.applicationInfo;
+        PackageSetting pkgSetting = scanResult.pkgSetting;
+        final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo(
+                pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0);
         assertThat(applicationInfo.primaryCpuAbi, is("derivedPrimary"));
         assertThat(applicationInfo.secondaryCpuAbi, is("derivedSecondary"));
 
         assertThat(applicationInfo.nativeLibraryRootDir, is("derivedRootDir"));
-        assertThat(scanResult.pkgSetting.legacyNativeLibraryPathString, is("derivedRootDir"));
+        assertThat(pkgSetting.legacyNativeLibraryPathString, is("derivedRootDir"));
         assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true));
         assertThat(applicationInfo.nativeLibraryDir, is("derivedNativeDir"));
         assertThat(applicationInfo.secondaryNativeLibraryDir, is("derivedNativeDir2"));
     }
 
     private static void assertPathsNotDerived(PackageManagerService.ScanResult scanResult) {
-        final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.applicationInfo;
+        PackageSetting pkgSetting = scanResult.pkgSetting;
+        final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo(
+                pkgSetting.pkg, 0, pkgSetting.readUserState(0), 0);
         assertThat(applicationInfo.nativeLibraryRootDir, is("getRootDir"));
-        assertThat(scanResult.pkgSetting.legacyNativeLibraryPathString, is("getRootDir"));
+        assertThat(pkgSetting.legacyNativeLibraryPathString, is("getRootDir"));
         assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true));
         assertThat(applicationInfo.nativeLibraryDir, is("getNativeDir"));
         assertThat(applicationInfo.secondaryNativeLibraryDir, is("getNativeDir2"));
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index d071927..dee79bb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -263,6 +263,19 @@
     }
 
     @MediumTest
+    public void testFindExistingGuest_guestExists() throws Exception {
+        UserInfo userInfo1 = createUser("Guest", UserInfo.FLAG_GUEST);
+        UserInfo foundGuest = mUserManager.findCurrentGuestUser();
+        assertNotNull(foundGuest);
+    }
+
+    @SmallTest
+    public void testFindExistingGuest_guestDoesNotExist() throws Exception {
+        UserInfo foundGuest = mUserManager.findCurrentGuestUser();
+        assertNull(foundGuest);
+    }
+
+    @MediumTest
     public void testSetUserAdmin() throws Exception {
         UserInfo userInfo = createUser("SecondaryUser", /*flags=*/ 0);
 
@@ -703,6 +716,21 @@
         assertEquals(canBeCreatedCount, created.get());
     }
 
+    @MediumTest
+    public void testGetUserHandles_createNewUser_shouldFindNewUser() {
+        UserInfo user = createUser("Guest 1", UserManager.USER_TYPE_FULL_GUEST, /*flags*/ 0);
+
+        boolean found = false;
+        List<UserHandle> userHandles = mUserManager.getUserHandles(/* excludeDying= */ true);
+        for (UserHandle userHandle: userHandles) {
+            if (userHandle.getIdentifier() == user.id) {
+                found = true;
+            }
+        }
+
+        assertTrue(found);
+    }
+
     private boolean isPackageInstalledForUser(String packageName, int userId) {
         try {
             return mPackageManager.getPackageInfoAsUser(packageName, 0, userId) != null;
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
index 2cc5323..1a630ff 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
@@ -122,13 +122,15 @@
         final Bundle local = new Bundle();
         final Bundle global = new Bundle();
 
-        UserRestrictionsUtils.sortToGlobalAndLocal(null, false /* isDeviceOwner */,
-                UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
+        UserRestrictionsUtils.sortToGlobalAndLocal(null,
+                UserManagerInternal.OWNER_TYPE_PROFILE_OWNER,
+                global, local);
         assertEquals(0, global.size());
         assertEquals(0, local.size());
 
-        UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, false /* isDeviceOwner */,
-                UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
+        UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY,
+                UserManagerInternal.OWNER_TYPE_PROFILE_OWNER,
+                global, local);
         assertEquals(0, global.size());
         assertEquals(0, local.size());
 
@@ -140,8 +142,10 @@
                 UserManager.DISALLOW_CONFIG_TETHERING,
                 UserManager.DISALLOW_OUTGOING_BEAM,
                 UserManager.DISALLOW_APPS_CONTROL,
-                UserManager.ENSURE_VERIFY_APPS
-        ), true /* isDeviceOwner */, UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
+                UserManager.ENSURE_VERIFY_APPS,
+                UserManager.DISALLOW_CAMERA
+                ), UserManagerInternal.OWNER_TYPE_DEVICE_OWNER,
+                global, local);
 
 
         assertRestrictions(newRestrictions(
@@ -154,7 +158,10 @@
 
                 // These can only be set by DO.
                 UserManager.DISALLOW_USB_FILE_TRANSFER,
-                UserManager.DISALLOW_CONFIG_TETHERING
+                UserManager.DISALLOW_CONFIG_TETHERING,
+
+                // This can be set by DO or PO of organisation owned device
+                UserManager.DISALLOW_CAMERA
         ), global);
 
         assertRestrictions(newRestrictions(
@@ -174,8 +181,10 @@
                 UserManager.DISALLOW_CONFIG_TETHERING,
                 UserManager.DISALLOW_OUTGOING_BEAM,
                 UserManager.DISALLOW_APPS_CONTROL,
-                UserManager.ENSURE_VERIFY_APPS
-        ), false /* isDeviceOwner */, UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
+                UserManager.ENSURE_VERIFY_APPS,
+                UserManager.DISALLOW_CAMERA
+                ), UserManagerInternal.OWNER_TYPE_PROFILE_OWNER,
+                global, local);
 
         assertRestrictions(newRestrictions(
                 // This one is global no matter who sets it.
@@ -193,23 +202,47 @@
 
                 // These can only be set by DO.
                 UserManager.DISALLOW_USB_FILE_TRANSFER,
-                UserManager.DISALLOW_CONFIG_TETHERING
+                UserManager.DISALLOW_CONFIG_TETHERING,
+
+                // This can be set by DO or PO of organisation owned device
+                UserManager.DISALLOW_CAMERA
         ), local);
 
+        local.clear();
+        global.clear();
+
+        // Restrictions set by PO of organisation owned device
+        UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(
+                UserManager.DISALLOW_CONFIG_DATE_TIME
+                ), UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE,
+                global, local);
+
+        assertRestrictions(newRestrictions(
+                // This user restriction is global when set by PO of org owned device
+                UserManager.DISALLOW_CONFIG_DATE_TIME
+        ), global);
+        assertEquals(0, local.size());
     }
 
     public void testSortToLocalAndGlobalWithCameraDisabled() {
         final Bundle local = new Bundle();
         final Bundle global = new Bundle();
 
-        UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, false,
-                UserManagerInternal.CAMERA_DISABLED_GLOBALLY, global, local);
+        UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(UserManager.DISALLOW_CAMERA),
+                UserManagerInternal.OWNER_TYPE_DEVICE_OWNER, global, local);
         assertRestrictions(newRestrictions(UserManager.DISALLOW_CAMERA), global);
         assertEquals(0, local.size());
         global.clear();
 
-        UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, false,
-                UserManagerInternal.CAMERA_DISABLED_LOCALLY, global, local);
+        UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(UserManager.DISALLOW_CAMERA),
+                UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE, global,
+                local);
+        assertRestrictions(newRestrictions(UserManager.DISALLOW_CAMERA), global);
+        assertEquals(0, local.size());
+        global.clear();
+
+        UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(UserManager.DISALLOW_CAMERA),
+                UserManagerInternal.OWNER_TYPE_PROFILE_OWNER, global, local);
         assertEquals(0, global.size());
         assertRestrictions(newRestrictions(UserManager.DISALLOW_CAMERA), local);
     }
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
index 601e2e9..683278b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
@@ -24,6 +24,7 @@
 import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT;
 import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE;
 import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE;
+import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA;
 import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST;
 import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_LOG;
 
@@ -36,8 +37,9 @@
 import android.content.Context;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
 import android.content.pm.UserInfo;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
 import android.os.Looper;
 import android.os.SystemProperties;
 import android.os.UserManager;
@@ -249,10 +251,14 @@
         final Set<String> userWhitelist = new ArraySet<>();
         userWhitelist.add(packageName1);
 
-        final PackageParser.Package pkg1 = new PackageParser.Package(packageName1);
-        final PackageParser.Package pkg2 = new PackageParser.Package(packageName2);
-        final PackageParser.Package pkg3 = new PackageParser.Package(packageName3);
-        final PackageParser.Package pkg4 = new PackageParser.Package(packageName4);
+        final AndroidPackage pkg1 = PackageImpl.forParsing(packageName1)
+                .hideAsParsed().hideAsFinal();
+        final AndroidPackage pkg2 = PackageImpl.forParsing(packageName2)
+                .hideAsParsed().hideAsFinal();
+        final AndroidPackage pkg3 = PackageImpl.forParsing(packageName3)
+                .hideAsParsed().hideAsFinal();
+        final AndroidPackage pkg4 = PackageImpl.forParsing(packageName4)
+                .hideAsParsed().hideAsFinal();
 
         // No implicit whitelist, so only install pkg1.
         boolean implicit = false;
@@ -394,33 +400,45 @@
         assertFalse(mUserSystemPackageInstaller.isLogMode());
         assertFalse(mUserSystemPackageInstaller.isEnforceMode());
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+        assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
 
         setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_LOG);
         assertTrue(mUserSystemPackageInstaller.isLogMode());
         assertFalse(mUserSystemPackageInstaller.isEnforceMode());
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+        assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
 
         setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
         assertFalse(mUserSystemPackageInstaller.isLogMode());
         assertTrue(mUserSystemPackageInstaller.isEnforceMode());
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+        assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
 
         setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST);
         assertFalse(mUserSystemPackageInstaller.isLogMode());
         assertFalse(mUserSystemPackageInstaller.isEnforceMode());
         assertTrue(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+        assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
+
+        setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA);
+        assertFalse(mUserSystemPackageInstaller.isLogMode());
+        assertFalse(mUserSystemPackageInstaller.isEnforceMode());
+        assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+        assertTrue(mUserSystemPackageInstaller.isIgnoreOtaMode());
 
         setUserTypePackageWhitelistMode(
                 USER_TYPE_PACKAGE_WHITELIST_MODE_LOG | USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
         assertTrue(mUserSystemPackageInstaller.isLogMode());
         assertTrue(mUserSystemPackageInstaller.isEnforceMode());
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+        assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
 
         setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST
                 | USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
         assertFalse(mUserSystemPackageInstaller.isLogMode());
         assertTrue(mUserSystemPackageInstaller.isEnforceMode());
         assertTrue(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+        assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
     }
 
     /** Sets the whitelist mode to the desired value via adb's setprop. */
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
index 3a55c22..66a4946 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
@@ -22,8 +22,11 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import android.content.pm.ApplicationInfo;
 import android.content.pm.SharedLibraryInfo;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.PackageImpl;
+import android.content.pm.parsing.ParsedPackage;
+import android.content.pm.parsing.ParsingPackage;
 import android.util.SparseArray;
 
 import androidx.test.filters.SmallTest;
@@ -51,17 +54,18 @@
             DelegateLastClassLoader.class.getName();
 
     private static class TestData {
-        ApplicationInfo info;
+        AndroidPackage pkg;
         boolean[] pathsWithCode;
     }
 
     private TestData createMockApplicationInfo(String baseClassLoader, boolean addSplits,
-            boolean addSplitDependencies) {
-        ApplicationInfo ai = new ApplicationInfo();
+            boolean addSplitDependencies, boolean isolatedSplitLoading) {
         String codeDir = "/data/app/mock.android.com";
-        ai.setBaseCodePath(codeDir + "/base.dex");
-        ai.classLoaderName = baseClassLoader;
-        ai.privateFlags = ai.privateFlags | ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING;
+        ParsingPackage parsingPackage = PackageImpl.forParsing("mock.android.com")
+                .setClassLoaderName(baseClassLoader);
+
+        parsingPackage.setIsolatedSplitLoading(isolatedSplitLoading);
+
         boolean[] pathsWithCode;
         if (!addSplits) {
             pathsWithCode = new boolean[] {true};
@@ -70,7 +74,7 @@
             Arrays.fill(pathsWithCode, true);
             pathsWithCode[7] = false;  // config split
 
-            ai.setSplitCodePaths(new String[]{
+            String[] splitCodePaths = new String[]{
                     codeDir + "/base-1.dex",
                     codeDir + "/base-2.dex",
                     codeDir + "/base-3.dex",
@@ -78,32 +82,51 @@
                     codeDir + "/base-5.dex",
                     codeDir + "/base-6.dex",
                     codeDir + "/config-split-7.dex",
-                    codeDir + "/feature-no-deps.dex"});
+                    codeDir + "/feature-no-deps.dex"
+            };
 
-            ai.splitClassLoaderNames = new String[]{
-                    DELEGATE_LAST_CLASS_LOADER_NAME,
-                    DELEGATE_LAST_CLASS_LOADER_NAME,
-                    PATH_CLASS_LOADER_NAME,
-                    DEX_CLASS_LOADER_NAME,
-                    PATH_CLASS_LOADER_NAME,
-                    null,   // A null class loader name should default to PathClassLoader.
-                    null,   // The config split gets a null class loader.
-                    null};  // The feature split with no dependency and no specified class loader.
+            String[] splitNames = new String[splitCodePaths.length];
+            int[] splitRevisionCodes = new int[splitCodePaths.length];
+            SparseArray<int[]> splitDependencies = null;
+
             if (addSplitDependencies) {
-                ai.splitDependencies = new SparseArray<>(ai.splitClassLoaderNames.length + 1);
-                ai.splitDependencies.put(0, new int[] {-1}); // base has no dependency
-                ai.splitDependencies.put(1, new int[] {2}); // split 1 depends on 2
-                ai.splitDependencies.put(2, new int[] {4}); // split 2 depends on 4
-                ai.splitDependencies.put(3, new int[] {4}); // split 3 depends on 4
-                ai.splitDependencies.put(4, new int[] {0}); // split 4 depends on base
-                ai.splitDependencies.put(5, new int[] {0}); // split 5 depends on base
-                ai.splitDependencies.put(6, new int[] {5}); // split 6 depends on 5
+                splitDependencies = new SparseArray<>(splitCodePaths.length);
+                splitDependencies.put(0, new int[] {-1}); // base has no dependency
+                splitDependencies.put(1, new int[] {2}); // split 1 depends on 2
+                splitDependencies.put(2, new int[] {4}); // split 2 depends on 4
+                splitDependencies.put(3, new int[] {4}); // split 3 depends on 4
+                splitDependencies.put(4, new int[] {0}); // split 4 depends on base
+                splitDependencies.put(5, new int[] {0}); // split 5 depends on base
+                splitDependencies.put(6, new int[] {5}); // split 6 depends on 5
                 // Do not add the config split to the dependency list.
                 // Do not add the feature split with no dependency to the dependency list.
             }
+
+            parsingPackage
+                    .asSplit(
+                            splitNames,
+                            splitCodePaths,
+                            splitRevisionCodes,
+                            splitDependencies
+                    )
+                    .setSplitClassLoaderName(0, DELEGATE_LAST_CLASS_LOADER_NAME)
+                    .setSplitClassLoaderName(1, DELEGATE_LAST_CLASS_LOADER_NAME)
+                    .setSplitClassLoaderName(2, PATH_CLASS_LOADER_NAME)
+                    .setSplitClassLoaderName(3, DEX_CLASS_LOADER_NAME)
+                    .setSplitClassLoaderName(4, PATH_CLASS_LOADER_NAME)
+                    // A null class loader name should default to PathClassLoader
+                    .setSplitClassLoaderName(5, null)
+                    // The config split gets a null class loader
+                    .setSplitClassLoaderName(6, null)
+                    // The feature split with no dependency and no specified class loader.
+                    .setSplitClassLoaderName(7, null);
         }
+
+        ParsedPackage parsedPackage = parsingPackage.hideAsParsed()
+                .setBaseCodePath(codeDir + "/base.dex");
+
         TestData data = new TestData();
-        data.info = ai;
+        data.pkg = parsedPackage.hideAsFinal();
         data.pathsWithCode = pathsWithCode;
         return data;
     }
@@ -118,11 +141,11 @@
 
     @Test
     public void testSplitChain() {
-        TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true);
+        TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true, true);
         List<SharedLibraryInfo> sharedLibrary =
                 createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, sharedLibrary, data.pathsWithCode);
+                data.pkg, sharedLibrary, data.pathsWithCode);
 
         assertEquals(9, contexts.length);
         assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
@@ -139,11 +162,11 @@
 
     @Test
     public void testSplitChainNoSplitDependencies() {
-        TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, false);
+        TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, false, true);
         List<SharedLibraryInfo> sharedLibrary =
                 createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, sharedLibrary, data.pathsWithCode);
+                data.pkg, sharedLibrary, data.pathsWithCode);
 
         assertEquals(9, contexts.length);
         assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
@@ -167,11 +190,9 @@
 
     @Test
     public void testSplitChainNoIsolationNoSharedLibrary() {
-        TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true);
-        data.info.privateFlags = data.info.privateFlags
-                & (~ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING);
+        TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true, false);
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, null, data.pathsWithCode);
+                data.pkg, null, data.pathsWithCode);
 
         assertEquals(9, contexts.length);
         assertEquals("PCL[]", contexts[0]);
@@ -192,9 +213,9 @@
     @Test
     public void testSplitChainNoSharedLibraries() {
         TestData data = createMockApplicationInfo(
-                DELEGATE_LAST_CLASS_LOADER_NAME, true, true);
+                DELEGATE_LAST_CLASS_LOADER_NAME, true, true, true);
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, null, data.pathsWithCode);
+                data.pkg, null, data.pathsWithCode);
 
         assertEquals(9, contexts.length);
         assertEquals("DLC[]", contexts[0]);
@@ -211,11 +232,11 @@
     @Test
     public void testSplitChainWithNullPrimaryClassLoader() {
         // A null classLoaderName should mean PathClassLoader.
-        TestData data = createMockApplicationInfo(null, true, true);
+        TestData data = createMockApplicationInfo(null, true, true, true);
         List<SharedLibraryInfo> sharedLibrary =
                 createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, sharedLibrary, data.pathsWithCode);
+                data.pkg, sharedLibrary, data.pathsWithCode);
 
         assertEquals(9, contexts.length);
         assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
@@ -233,11 +254,11 @@
 
     @Test
     public void tesNoSplits() {
-        TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false);
+        TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false, true);
         List<SharedLibraryInfo> sharedLibrary =
                 createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, sharedLibrary, data.pathsWithCode);
+                data.pkg, sharedLibrary, data.pathsWithCode);
 
         assertEquals(1, contexts.length);
         assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
@@ -245,11 +266,11 @@
 
     @Test
     public void tesNoSplitsNullClassLoaderName() {
-        TestData data = createMockApplicationInfo(null, false, false);
+        TestData data = createMockApplicationInfo(null, false, false, true);
         List<SharedLibraryInfo> sharedLibrary =
                 createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, sharedLibrary, data.pathsWithCode);
+                data.pkg, sharedLibrary, data.pathsWithCode);
 
         assertEquals(1, contexts.length);
         assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
@@ -258,11 +279,11 @@
     @Test
     public void tesNoSplitDelegateLast() {
         TestData data = createMockApplicationInfo(
-                DELEGATE_LAST_CLASS_LOADER_NAME, false, false);
+                DELEGATE_LAST_CLASS_LOADER_NAME, false, false, true);
         List<SharedLibraryInfo> sharedLibrary =
                 createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, sharedLibrary, data.pathsWithCode);
+                data.pkg, sharedLibrary, data.pathsWithCode);
 
         assertEquals(1, contexts.length);
         assertEquals("DLC[]{PCL[a.dex:b.dex]}", contexts[0]);
@@ -270,9 +291,9 @@
 
     @Test
     public void tesNoSplitsNoSharedLibraries() {
-        TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false);
+        TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false, true);
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, null, data.pathsWithCode);
+                data.pkg, null, data.pathsWithCode);
 
         assertEquals(1, contexts.length);
         assertEquals("PCL[]", contexts[0]);
@@ -281,9 +302,9 @@
     @Test
     public void tesNoSplitDelegateLastNoSharedLibraries() {
         TestData data = createMockApplicationInfo(
-                DELEGATE_LAST_CLASS_LOADER_NAME, false, false);
+                DELEGATE_LAST_CLASS_LOADER_NAME, false, false, true);
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, null, data.pathsWithCode);
+                data.pkg, null, data.pathsWithCode);
 
         assertEquals(1, contexts.length);
         assertEquals("DLC[]", contexts[0]);
@@ -291,13 +312,13 @@
 
     @Test
     public void testContextWithNoCode() {
-        TestData data = createMockApplicationInfo(null, true, false);
+        TestData data = createMockApplicationInfo(null, true, false, true);
         Arrays.fill(data.pathsWithCode, false);
 
         List<SharedLibraryInfo> sharedLibrary =
                 createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, sharedLibrary, data.pathsWithCode);
+                data.pkg, sharedLibrary, data.pathsWithCode);
 
         assertEquals(9, contexts.length);
         assertEquals(null, contexts[0]);
@@ -312,12 +333,12 @@
 
     @Test
     public void testContextBaseNoCode() {
-        TestData data = createMockApplicationInfo(null, true, true);
+        TestData data = createMockApplicationInfo(null, true, true, true);
         data.pathsWithCode[0] = false;
         List<SharedLibraryInfo> sharedLibrary =
                 createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
-                data.info, sharedLibrary, data.pathsWithCode);
+                data.pkg, sharedLibrary, data.pathsWithCode);
 
         assertEquals(9, contexts.length);
         assertEquals(null, contexts[0]);
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
new file mode 100644
index 0000000..27d02e1
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
@@ -0,0 +1,132 @@
+/*
+ * 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.pm.parsing
+
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageInfo
+import android.content.pm.PackageManager
+import android.content.pm.PackageParser
+import android.content.pm.parsing.AndroidPackage
+import com.android.server.pm.parsing.AndroidPackageInfoFlagBehaviorTest.Companion.Param.Companion.appInfo
+import com.android.server.pm.parsing.AndroidPackageInfoFlagBehaviorTest.Companion.Param.Companion.pkgInfo
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * Verifies that missing/adding [PackageManager] flags adds/remove the appropriate fields from the
+ * [PackageInfo] or [ApplicationInfo] results.
+ *
+ * This test has to be updated manually whenever the info generation behavior changes, since
+ * there's no single place where flag -> field is defined besides this test.
+ */
+@RunWith(Parameterized::class)
+class AndroidPackageInfoFlagBehaviorTest : AndroidPackageParsingTestBase() {
+
+    companion object {
+
+        data class Param<T> constructor(
+            val flag: Int,
+            val logTag: String,
+            val oldPkgFunction: (pkg: PackageParser.Package, flags: Int) -> T?,
+            val newPkgFunction: (pkg: AndroidPackage, flags: Int) -> T?,
+            val fieldFunction: (T) -> List<Any?>
+        ) {
+            companion object {
+                fun pkgInfo(flag: Int, fieldFunction: (PackageInfo) -> List<Any?>) = Param(
+                        flag, PackageInfo::class.java.simpleName,
+                        ::oldPackageInfo, ::newPackageInfo, fieldFunction
+                )
+
+                fun appInfo(flag: Int, fieldFunction: (ApplicationInfo) -> List<Any?>) = Param(
+                        flag, ApplicationInfo::class.java.simpleName,
+                        ::oldAppInfo, ::newAppInfo, fieldFunction
+                )
+            }
+
+            override fun toString(): String {
+                val hex = Integer.toHexString(flag)
+                val fromRight = Integer.toBinaryString(flag).reversed().indexOf('1')
+                return "$logTag $hex | 1 shl $fromRight"
+            }
+        }
+
+        @JvmStatic
+        @Parameterized.Parameters(name = "{0}")
+        fun parameters() = arrayOf(
+                pkgInfo(PackageManager.GET_ACTIVITIES) { listOf(it.activities) },
+                pkgInfo(PackageManager.GET_GIDS) { listOf(it.gids) },
+                pkgInfo(PackageManager.GET_INSTRUMENTATION) { listOf(it.instrumentation) },
+                pkgInfo(PackageManager.GET_META_DATA) { listOf(it.applicationInfo.metaData) },
+                pkgInfo(PackageManager.GET_PROVIDERS) { listOf(it.providers) },
+                pkgInfo(PackageManager.GET_RECEIVERS) { listOf(it.receivers) },
+                pkgInfo(PackageManager.GET_SERVICES) { listOf(it.services) },
+                pkgInfo(PackageManager.GET_SIGNATURES) { listOf(it.signatures) },
+                pkgInfo(PackageManager.GET_SIGNING_CERTIFICATES) { listOf(it.signingInfo) },
+                pkgInfo(PackageManager.GET_SHARED_LIBRARY_FILES) {
+                    it.applicationInfo.run { listOf(sharedLibraryFiles, sharedLibraryFiles) }
+                },
+                pkgInfo(PackageManager.GET_CONFIGURATIONS) {
+                    listOf(it.configPreferences, it.reqFeatures, it.featureGroups)
+                },
+                pkgInfo(PackageManager.GET_PERMISSIONS) {
+                    listOf(it.permissions, it.requestedPermissions, it.requestedPermissionsFlags)
+                },
+
+                appInfo(PackageManager.GET_META_DATA) { listOf(it.metaData) },
+                appInfo(PackageManager.GET_SHARED_LIBRARY_FILES) {
+                    listOf(it.sharedLibraryFiles, it.sharedLibraryFiles)
+                }
+        )
+    }
+
+    @Parameterized.Parameter(0)
+    lateinit var param: Param<Any>
+
+    @Test
+    fun fieldPresence() {
+        oldPackages.asSequence().zip(newPackages.asSequence())
+                .forEach { (old, new) ->
+                    val oldWithFlag = param.oldPkgFunction(old, param.flag)
+                    val newWithFlag = param.newPkgFunction(new, param.flag)
+                    val oldFieldList = oldWithFlag?.let(param.fieldFunction).orEmpty()
+                    val newFieldList = newWithFlag?.let(param.fieldFunction).orEmpty()
+
+                    oldFieldList.zip(newFieldList).forEach {
+                        assertWithMessage(new.packageName).that(it.second).apply {
+                            // Assert same null-ness as old logic
+                            if (it.first == null) {
+                                isNull()
+                            } else {
+                                isNotNull()
+                            }
+                        }
+                    }
+                }
+    }
+
+    @Test
+    fun fieldAbsence() {
+        newPackages.forEach {
+            val newWithoutFlag = param.newPkgFunction(it, 0)
+            val newFieldListWithoutFlag = newWithoutFlag?.let(param.fieldFunction).orEmpty()
+            assertThat(newFieldListWithoutFlag.filterNotNull()).isEmpty()
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
new file mode 100644
index 0000000..925af7f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
@@ -0,0 +1,78 @@
+/*
+ * 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.pm.parsing
+
+import android.content.pm.PackageManager
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Test
+
+/**
+ * Collects APKs from the device and verifies that the new parsing behavior outputs
+ * the same exposed Info object as the old parsing logic.
+ */
+class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() {
+
+    @Test
+    fun applicationInfoEquality() {
+        val flags = PackageManager.GET_META_DATA or PackageManager.GET_SHARED_LIBRARY_FILES
+        val oldAppInfo = oldPackages.asSequence().map { oldAppInfo(it, flags) }
+        val newAppInfo = newPackages.asSequence().map { newAppInfo(it, flags) }
+        oldAppInfo.zip(newAppInfo).forEach {
+            val firstName = it.first?.packageName
+            val secondName = it.second?.packageName
+            val packageName = if (firstName == secondName) {
+                "$firstName"
+            } else {
+                "$firstName | $secondName"
+            }
+            assertWithMessage(packageName).that(it.first?.dumpToString())
+                    .isEqualTo(it.second?.dumpToString())
+        }
+    }
+
+    @Test
+    fun packageInfoEquality() {
+        val flags = PackageManager.GET_ACTIVITIES or
+                PackageManager.GET_CONFIGURATIONS or
+                PackageManager.GET_GIDS or
+                PackageManager.GET_INSTRUMENTATION or
+                PackageManager.GET_META_DATA or
+                PackageManager.GET_PERMISSIONS or
+                PackageManager.GET_PROVIDERS or
+                PackageManager.GET_RECEIVERS or
+                PackageManager.GET_SERVICES or
+                PackageManager.GET_SHARED_LIBRARY_FILES or
+                PackageManager.GET_SIGNATURES or
+                PackageManager.GET_SIGNING_CERTIFICATES
+        val oldPackageInfo = oldPackages.asSequence().map { oldPackageInfo(it, flags) }
+        val newPackageInfo = newPackages.asSequence().map { newPackageInfo(it, flags) }
+
+        oldPackageInfo.zip(newPackageInfo).forEach {
+            val firstName = it.first?.packageName
+            val secondName = it.second?.packageName
+            val packageName = if (firstName == secondName) {
+                "$firstName"
+            } else {
+                "$firstName | $secondName"
+            }
+            assertWithMessage(packageName).that(it.first?.dumpToString())
+                    .isEqualTo(it.second?.dumpToString())
+        }
+    }
+}
+
+
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
new file mode 100644
index 0000000..afd6e18
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
@@ -0,0 +1,361 @@
+/*
+ * 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.pm.parsing
+
+import android.content.Context
+import android.content.pm.ActivityInfo
+import android.content.pm.ApplicationInfo
+import android.content.pm.ConfigurationInfo
+import android.content.pm.FeatureInfo
+import android.content.pm.InstrumentationInfo
+import android.content.pm.PackageInfo
+import android.content.pm.PackageParser
+import android.content.pm.PackageUserState
+import android.content.pm.PermissionInfo
+import android.content.pm.ProviderInfo
+import android.content.pm.parsing.AndroidPackage
+import android.content.pm.parsing.PackageImpl
+import android.content.pm.parsing.PackageInfoUtils
+import android.os.Debug
+import android.os.Environment
+import android.util.SparseArray
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.pm.PackageManagerService
+import org.junit.BeforeClass
+import org.mockito.Mockito
+import java.io.File
+
+open class AndroidPackageParsingTestBase {
+
+    companion object {
+
+        /**
+         * By default, don't parse all APKs on device, only the framework one.
+         * Toggle this manually if working on package parsing.
+         */
+        private const val VERIFY_ALL_APKS = false
+
+        /** For auditing memory usage differences */
+        private const val DUMP_HPROF_TO_EXTERNAL = false
+
+        val context: Context = InstrumentationRegistry.getInstrumentation().getContext()
+        protected val packageParser = PackageParser().apply {
+            setOnlyCoreApps(false)
+            setDisplayMetrics(context.resources.displayMetrics)
+            setCallback { true }
+        }
+
+        /**
+         * It would be difficult to mock all possibilities, so just use the APKs on device.
+         * Unfortunately, this means the device must be bootable to verify potentially
+         * boot-breaking behavior.
+         */
+        private val apks = mutableListOf(File(Environment.getRootDirectory(), "framework"))
+                .apply {
+                    @Suppress("ConstantConditionIf")
+                    if (VERIFY_ALL_APKS) {
+                        this += (PackageManagerService.SYSTEM_PARTITIONS)
+                                .flatMap {
+                                    listOfNotNull(it.privAppFolder, it.appFolder, it.overlayFolder)
+                                }
+                    }
+                }
+                .flatMap {
+                    it.walkTopDown()
+                            .filter { file -> file.name.endsWith(".apk") }
+                            .toList()
+                }
+
+        private val dummyState = Mockito.mock(PackageUserState::class.java).apply {
+            installed = true
+            Mockito.`when`(isAvailable(Mockito.anyInt())).thenReturn(true)
+        }
+
+        lateinit var oldPackages: List<PackageParser.Package>
+
+        lateinit var newPackages: List<AndroidPackage>
+
+        @Suppress("ConstantConditionIf")
+        @JvmStatic
+        @BeforeClass
+        fun setUpPackages() {
+            this.oldPackages = apks.map {
+                packageParser.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false)
+            }
+
+            this.newPackages = apks.map {
+                packageParser.parseParsedPackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false)
+            }
+
+            if (DUMP_HPROF_TO_EXTERNAL) {
+                System.gc()
+                Environment.getExternalStorageDirectory()
+                        .resolve("${AndroidPackageParsingTestBase::class.java.simpleName}.hprof")
+                        .absolutePath
+                        .run(Debug::dumpHprofData)
+            }
+        }
+
+        fun oldAppInfo(pkg: PackageParser.Package, flags: Int = 0): ApplicationInfo? {
+            return PackageParser.generateApplicationInfo(pkg, flags, dummyState, 0)
+        }
+
+        fun newAppInfo(pkg: AndroidPackage, flags: Int = 0): ApplicationInfo? {
+            return PackageInfoUtils.generateApplicationInfo(pkg, flags, dummyState, 0)
+        }
+
+        fun oldPackageInfo(pkg: PackageParser.Package, flags: Int = 0): PackageInfo? {
+            return PackageParser.generatePackageInfo(pkg, intArrayOf(), flags, 5, 6, emptySet(), dummyState)
+        }
+
+        fun newPackageInfo(pkg: AndroidPackage, flags: Int = 0): PackageInfo? {
+            return PackageInfoUtils.generate(pkg, intArrayOf(), flags, 5, 6, emptySet(), dummyState, 0)
+        }
+    }
+
+    // The following methods dump an exact set of fields from the object to compare, because
+    // 1. comprehensive equals/toStrings do not exist on all of the Info objects, and
+    // 2. the test must only verify fields that [PackageParser.Package] can actually fill, as
+    // no new functionality will be added to it.
+
+    // The following methods prepend "this." because @hide APIs can cause an IDE to auto-import
+    // the R.attr constant instead of referencing the field in an attempt to fix the error.
+
+    /**
+     * Known exclusions:
+     *   - [ApplicationInfo.credentialProtectedDataDir]
+     *   - [ApplicationInfo.dataDir]
+     *   - [ApplicationInfo.deviceProtectedDataDir]
+     *   - [ApplicationInfo.processName]
+     *   - [ApplicationInfo.publicSourceDir]
+     *   - [ApplicationInfo.scanPublicSourceDir]
+     *   - [ApplicationInfo.scanSourceDir]
+     *   - [ApplicationInfo.sourceDir]
+     * These attributes used to be assigned post-package-parsing as part of another component,
+     * but are now adjusted directly inside [PackageImpl].
+     */
+    protected fun ApplicationInfo.dumpToString() = """
+            appComponentFactory=${this.appComponentFactory}
+            backupAgentName=${this.backupAgentName}
+            banner=${this.banner}
+            category=${this.category}
+            classLoaderName=${this.classLoaderName}
+            className=${this.className}
+            compatibleWidthLimitDp=${this.compatibleWidthLimitDp}
+            compileSdkVersion=${this.compileSdkVersion}
+            compileSdkVersionCodename=${this.compileSdkVersionCodename}
+            descriptionRes=${this.descriptionRes}
+            enabled=${this.enabled}
+            enabledSetting=${this.enabledSetting}
+            flags=${Integer.toBinaryString(this.flags)}
+            fullBackupContent=${this.fullBackupContent}
+            hiddenUntilInstalled=${this.hiddenUntilInstalled}
+            icon=${this.icon}
+            iconRes=${this.iconRes}
+            installLocation=${this.installLocation}
+            largestWidthLimitDp=${this.largestWidthLimitDp}
+            logo=${this.logo}
+            longVersionCode=${this.longVersionCode}
+            manageSpaceActivityName=${this.manageSpaceActivityName}
+            maxAspectRatio.compareTo(that.maxAspectRatio)=${this.maxAspectRatio}
+            metaData=${this.metaData}
+            minAspectRatio.compareTo(that.minAspectRatio)=${this.minAspectRatio}
+            minSdkVersion=${this.minSdkVersion}
+            name=${this.name}
+            nativeLibraryDir=${this.nativeLibraryDir}
+            nativeLibraryRootDir=${this.nativeLibraryRootDir}
+            nativeLibraryRootRequiresIsa=${this.nativeLibraryRootRequiresIsa}
+            networkSecurityConfigRes=${this.networkSecurityConfigRes}
+            nonLocalizedLabel=${this.nonLocalizedLabel}
+            packageName=${this.packageName}
+            permission=${this.permission}
+            primaryCpuAbi=${this.primaryCpuAbi}
+            privateFlags=${Integer.toBinaryString(this.privateFlags)}
+            requiresSmallestWidthDp=${this.requiresSmallestWidthDp}
+            resourceDirs=${this.resourceDirs?.contentToString()}
+            roundIconRes=${this.roundIconRes}
+            secondaryCpuAbi=${this.secondaryCpuAbi}
+            secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir}
+            seInfo=${this.seInfo}
+            seInfoUser=${this.seInfoUser}
+            sharedLibraryFiles=${this.sharedLibraryFiles?.contentToString()}
+            sharedLibraryInfos=${this.sharedLibraryInfos}
+            showUserIcon=${this.showUserIcon}
+            splitClassLoaderNames=${this.splitClassLoaderNames?.contentToString()}
+            splitDependencies=${this.splitDependencies}
+            splitNames=${this.splitNames?.contentToString()}
+            splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()}
+            splitSourceDirs=${this.splitSourceDirs?.contentToString()}
+            storageUuid=${this.storageUuid}
+            targetSandboxVersion=${this.targetSandboxVersion}
+            targetSdkVersion=${this.targetSdkVersion}
+            taskAffinity=${this.taskAffinity}
+            theme=${this.theme}
+            uid=${this.uid}
+            uiOptions=${this.uiOptions}
+            versionCode=${this.versionCode}
+            volumeUuid=${this.volumeUuid}
+            zygotePreloadName=${this.zygotePreloadName}
+            """.trimIndent()
+
+    protected fun FeatureInfo.dumpToString() = """
+            flags=${Integer.toBinaryString(this.flags)}
+            name=${this.name}
+            reqGlEsVersion=${this.reqGlEsVersion}
+            version=${this.version}
+            """.trimIndent()
+
+    protected fun InstrumentationInfo.dumpToString() = """
+            credentialProtectedDataDir=${this.credentialProtectedDataDir}
+            dataDir=${this.dataDir}
+            deviceProtectedDataDir=${this.deviceProtectedDataDir}
+            functionalTest=${this.functionalTest}
+            handleProfiling=${this.handleProfiling}
+            nativeLibraryDir=${this.nativeLibraryDir}
+            primaryCpuAbi=${this.primaryCpuAbi}
+            publicSourceDir=${this.publicSourceDir}
+            secondaryCpuAbi=${this.secondaryCpuAbi}
+            secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir}
+            sourceDir=${this.sourceDir}
+            splitDependencies=${this.splitDependencies.sequence().map { it.first to it.second?.contentToString() }.joinToString()}
+            splitNames=${this.splitNames?.contentToString()}
+            splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()}
+            splitSourceDirs=${this.splitSourceDirs?.contentToString()}
+            targetPackage=${this.targetPackage}
+            targetProcesses=${this.targetProcesses}
+            """.trimIndent()
+
+    protected fun ActivityInfo.dumpToString() = """
+            colorMode=${this.colorMode}
+            configChanges=${this.configChanges}
+            documentLaunchMode=${this.documentLaunchMode}
+            flags=${Integer.toBinaryString(this.flags)}
+            launchMode=${this.launchMode}
+            launchToken=${this.launchToken}
+            lockTaskLaunchMode=${this.lockTaskLaunchMode}
+            maxAspectRatio=${this.maxAspectRatio}
+            maxRecents=${this.maxRecents}
+            minAspectRatio=${this.minAspectRatio}
+            parentActivityName=${this.parentActivityName}
+            permission=${this.permission}
+            persistableMode=${this.persistableMode}
+            privateFlags=${Integer.toBinaryString(this.privateFlags)}
+            requestedVrComponent=${this.requestedVrComponent}
+            resizeMode=${this.resizeMode}
+            rotationAnimation=${this.rotationAnimation}
+            screenOrientation=${this.screenOrientation}
+            softInputMode=${this.softInputMode}
+            targetActivity=${this.targetActivity}
+            taskAffinity=${this.taskAffinity}
+            theme=${this.theme}
+            uiOptions=${this.uiOptions}
+            windowLayout=${this.windowLayout?.dumpToString()}
+            """.trimIndent()
+
+    protected fun ActivityInfo.WindowLayout.dumpToString() = """
+            gravity=${this.gravity}
+            height=${this.height}
+            heightFraction=${this.heightFraction}
+            minHeight=${this.minHeight}
+            minWidth=${this.minWidth}
+            width=${this.width}
+            widthFraction=${this.widthFraction}
+            """.trimIndent()
+
+    protected fun PermissionInfo.dumpToString() = """
+            backgroundPermission=${this.backgroundPermission}
+            descriptionRes=${this.descriptionRes}
+            flags=${Integer.toBinaryString(this.flags)}
+            group=${this.group}
+            nonLocalizedDescription=${this.nonLocalizedDescription}
+            protectionLevel=${this.protectionLevel}
+            requestRes=${this.requestRes}
+            """.trimIndent()
+
+    protected fun ProviderInfo.dumpToString() = """
+            authority=${this.authority}
+            flags=${Integer.toBinaryString(this.flags)}
+            forceUriPermissions=${this.forceUriPermissions}
+            grantUriPermissions=${this.grantUriPermissions}
+            initOrder=${this.initOrder}
+            isSyncable=${this.isSyncable}
+            multiprocess=${this.multiprocess}
+            pathPermissions=${this.pathPermissions?.joinToString { "readPermission=${it.readPermission}\nwritePermission=${it.writePermission}" }}
+            readPermission=${this.readPermission}
+            uriPermissionPatterns=${this.uriPermissionPatterns?.contentToString()}
+            writePermission=${this.writePermission}
+            """.trimIndent()
+
+    protected fun ConfigurationInfo.dumpToString() = """
+            reqGlEsVersion=${this.reqGlEsVersion}
+            reqInputFeatures=${this.reqInputFeatures}
+            reqKeyboardType=${this.reqKeyboardType}
+            reqNavigation=${this.reqNavigation}
+            reqTouchScreen=${this.reqTouchScreen}
+            """.trimIndent()
+
+    protected fun PackageInfo.dumpToString() = """
+            activities=${this.activities?.joinToString { it.dumpToString() }}
+            applicationInfo=${this.applicationInfo.dumpToString()}
+            baseRevisionCode=${this.baseRevisionCode}
+            compileSdkVersion=${this.compileSdkVersion}
+            compileSdkVersionCodename=${this.compileSdkVersionCodename}
+            configPreferences=${this.configPreferences?.joinToString { it.dumpToString() }}
+            coreApp=${this.coreApp}
+            featureGroups=${this.featureGroups?.joinToString { it.features?.joinToString { featureInfo -> featureInfo.dumpToString() }.orEmpty() }}
+            firstInstallTime=${this.firstInstallTime}
+            gids=${gids?.contentToString()}
+            installLocation=${this.installLocation}
+            instrumentation=${instrumentation?.joinToString { it.dumpToString() }}
+            isApex=${this.isApex}
+            isStub=${this.isStub}
+            lastUpdateTime=${this.lastUpdateTime}
+            mOverlayIsStatic=${this.mOverlayIsStatic}
+            overlayCategory=${this.overlayCategory}
+            overlayPriority=${this.overlayPriority}
+            overlayTarget=${this.overlayTarget}
+            packageName=${this.packageName}
+            permissions=${this.permissions?.joinToString { it.dumpToString() }}
+            providers=${this.providers?.joinToString { it.dumpToString() }}
+            receivers=${this.receivers?.joinToString { it.dumpToString() }}
+            reqFeatures=${this.reqFeatures?.joinToString { it.dumpToString() }}
+            requestedPermissions=${this.requestedPermissions?.contentToString()}
+            requestedPermissionsFlags=${this.requestedPermissionsFlags?.contentToString()}
+            requiredAccountType=${this.requiredAccountType}
+            requiredForAllUsers=${this.requiredForAllUsers}
+            restrictedAccountType=${this.restrictedAccountType}
+            services=${this.services?.contentToString()}
+            sharedUserId=${this.sharedUserId}
+            sharedUserLabel=${this.sharedUserLabel}
+            signatures=${this.signatures?.joinToString { it.toCharsString() }}
+            signingInfo=${this.signingInfo?.signingCertificateHistory?.joinToString { it.toCharsString() }.orEmpty()}
+            splitNames=${this.splitNames?.contentToString()}
+            splitRevisionCodes=${this.splitRevisionCodes?.contentToString()}
+            targetOverlayableName=${this.targetOverlayableName}
+            versionCode=${this.versionCode}
+            versionCodeMajor=${this.versionCodeMajor}
+            versionName=${this.versionName}
+            """.trimIndent()
+
+    @Suppress("unused")
+    private fun <T> SparseArray<T>.sequence(): Sequence<Pair<Int, T>> {
+        var index = 0
+        return generateSequence {
+            index++.takeIf { it < size() }?.let { keyAt(it) to valueAt(index) }
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
index 4476918..642cedb 100644
--- a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
@@ -17,6 +17,12 @@
 package com.android.server.power;
 
 import static android.os.BatteryStats.Uid.NUM_USER_ACTIVITY_TYPES;
+import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE;
+
+import static com.android.server.power.AttentionDetector.DEFAULT_POST_DIM_CHECK_DURATION_MILLIS;
+import static com.android.server.power.AttentionDetector.DEFAULT_PRE_DIM_CHECK_DURATION_MILLIS;
+import static com.android.server.power.AttentionDetector.KEY_POST_DIM_CHECK_DURATION_MILLIS;
+import static com.android.server.power.AttentionDetector.KEY_PRE_DIM_CHECK_DURATION_MILLIS;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -37,6 +43,7 @@
 import android.os.PowerManagerInternal;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.service.attention.AttentionService;
 import android.test.AndroidTestCase;
@@ -53,6 +60,7 @@
 
 @SmallTest
 public class AttentionDetectorTest extends AndroidTestCase {
+    private static final long DEFAULT_DIM_DURATION_MILLIS = 6_000L;
 
     @Mock
     private PackageManager mPackageManager;
@@ -63,7 +71,8 @@
     @Mock
     private Runnable mOnUserAttention;
     private TestableAttentionDetector mAttentionDetector;
-    private long mAttentionTimeout;
+    private AttentionDetector mRealAttentionDetector;
+    private long mPreDimCheckDuration;
     private long mNextDimming;
     private int mIsSettingEnabled;
 
@@ -77,6 +86,7 @@
                 .thenReturn(true);
         when(mWindowManagerInternal.isKeyguardShowingAndNotOccluded()).thenReturn(false);
         mAttentionDetector = new TestableAttentionDetector();
+        mRealAttentionDetector = new AttentionDetector(mOnUserAttention, new Object());
         mAttentionDetector.onWakefulnessChangeStarted(PowerManagerInternal.WAKEFULNESS_AWAKE);
         mAttentionDetector.setAttentionServiceSupported(true);
         mNextDimming = SystemClock.uptimeMillis() + 3000L;
@@ -94,6 +104,13 @@
     public void tearDown() {
         Settings.System.putIntForUser(getContext().getContentResolver(),
                 Settings.System.ADAPTIVE_SLEEP, mIsSettingEnabled, UserHandle.USER_CURRENT);
+
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_PRE_DIM_CHECK_DURATION_MILLIS,
+                Long.toString(DEFAULT_PRE_DIM_CHECK_DURATION_MILLIS), false);
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_POST_DIM_CHECK_DURATION_MILLIS,
+                Long.toString(DEFAULT_POST_DIM_CHECK_DURATION_MILLIS), false);
     }
 
     @Test
@@ -175,7 +192,7 @@
         long now = SystemClock.uptimeMillis();
         mNextDimming = now;
         mAttentionDetector.onUserActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH);
-        mAttentionDetector.updateUserActivity(mNextDimming + 5000L);
+        mAttentionDetector.updateUserActivity(mNextDimming + 5000L, DEFAULT_DIM_DURATION_MILLIS);
         verify(mAttentionManagerInternal, never()).checkAttention(anyLong(), any());
     }
 
@@ -184,7 +201,8 @@
         long now = SystemClock.uptimeMillis();
         mNextDimming = now;
         mAttentionDetector.onUserActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH);
-        long nextTimeout = mAttentionDetector.updateUserActivity(mNextDimming + 5000L);
+        long nextTimeout = mAttentionDetector.updateUserActivity(mNextDimming + 5000L,
+                DEFAULT_DIM_DURATION_MILLIS);
         assertThat(nextTimeout).isEqualTo(mNextDimming + 5000L);
     }
 
@@ -192,7 +210,7 @@
     public void testOnUserActivity_ignoresAfterMaximumExtension() {
         long now = SystemClock.uptimeMillis();
         mAttentionDetector.onUserActivity(now - 15000L, PowerManager.USER_ACTIVITY_EVENT_TOUCH);
-        mAttentionDetector.updateUserActivity(now + 2000L);
+        mAttentionDetector.updateUserActivity(now + 2000L, DEFAULT_DIM_DURATION_MILLIS);
         verify(mAttentionManagerInternal, never()).checkAttention(anyLong(), any());
     }
 
@@ -203,7 +221,8 @@
         assertThat(when).isLessThan(mNextDimming);
         clearInvocations(mAttentionManagerInternal);
 
-        long redundantWhen = mAttentionDetector.updateUserActivity(mNextDimming);
+        long redundantWhen = mAttentionDetector.updateUserActivity(mNextDimming,
+                DEFAULT_DIM_DURATION_MILLIS);
         assertThat(redundantWhen).isEqualTo(mNextDimming);
         verify(mAttentionManagerInternal, never()).checkAttention(anyLong(), any());
     }
@@ -212,7 +231,8 @@
     public void testOnUserActivity_skipsIfAlreadyScheduled() {
         registerAttention();
         reset(mAttentionManagerInternal);
-        long when = mAttentionDetector.updateUserActivity(mNextDimming + 1);
+        long when = mAttentionDetector.updateUserActivity(mNextDimming + 1,
+                DEFAULT_DIM_DURATION_MILLIS);
         verify(mAttentionManagerInternal, never()).checkAttention(anyLong(), any());
         assertThat(when).isLessThan(mNextDimming);
     }
@@ -300,11 +320,95 @@
         verify(mOnUserAttention, never()).run();
     }
 
+    @Test
+    public void testGetPreDimCheckDurationMillis_handlesGoodFlagValue() {
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_PRE_DIM_CHECK_DURATION_MILLIS, "555", false);
+        assertThat(mRealAttentionDetector.getPreDimCheckDurationMillis()).isEqualTo(555);
+    }
+
+    @Test
+    public void testGetPreDimCheckDurationMillis_rejectsNegativeValue() {
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_PRE_DIM_CHECK_DURATION_MILLIS, "-50", false);
+        assertThat(mRealAttentionDetector.getPreDimCheckDurationMillis()).isEqualTo(
+                DEFAULT_PRE_DIM_CHECK_DURATION_MILLIS);
+    }
+
+    @Test
+    public void testGetPreDimCheckDurationMillis_rejectsTooBigValue() {
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_PRE_DIM_CHECK_DURATION_MILLIS, "20000", false);
+        assertThat(mRealAttentionDetector.getPreDimCheckDurationMillis()).isEqualTo(
+                DEFAULT_PRE_DIM_CHECK_DURATION_MILLIS);
+    }
+
+    @Test
+    public void testGetPreDimCheckDurationMillis_handlesBadFlagValue() {
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_PRE_DIM_CHECK_DURATION_MILLIS, "20000k", false);
+        assertThat(mRealAttentionDetector.getPreDimCheckDurationMillis()).isEqualTo(
+                DEFAULT_PRE_DIM_CHECK_DURATION_MILLIS);
+
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_PRE_DIM_CHECK_DURATION_MILLIS, "0.25", false);
+        assertThat(mRealAttentionDetector.getPreDimCheckDurationMillis()).isEqualTo(
+                DEFAULT_PRE_DIM_CHECK_DURATION_MILLIS);
+    }
+
+    @Test
+    public void testGetPostDimCheckDurationMillis_handlesGoodFlagValue() {
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_POST_DIM_CHECK_DURATION_MILLIS, "333", false);
+        assertThat(mRealAttentionDetector.getPostDimCheckDurationMillis(
+                DEFAULT_DIM_DURATION_MILLIS)).isEqualTo(333);
+    }
+
+    @Test
+    public void testGetPostDimCheckDurationMillis_capsGoodFlagValueByMaxDimDuration() {
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_POST_DIM_CHECK_DURATION_MILLIS, "7000", false);
+        assertThat(mRealAttentionDetector.getPostDimCheckDurationMillis(6500)).isEqualTo(6500);
+    }
+
+    @Test
+    public void testGetPostDimCheckDurationMillis_rejectsNegativeValue() {
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_POST_DIM_CHECK_DURATION_MILLIS, "-50", false);
+        assertThat(mRealAttentionDetector.getPostDimCheckDurationMillis(
+                DEFAULT_DIM_DURATION_MILLIS)).isEqualTo(
+                DEFAULT_POST_DIM_CHECK_DURATION_MILLIS);
+    }
+
+    @Test
+    public void testGetPostDimCheckDurationMillis_rejectsTooBigValue() {
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_POST_DIM_CHECK_DURATION_MILLIS, "20000", false);
+        assertThat(mRealAttentionDetector.getPostDimCheckDurationMillis(
+                DEFAULT_DIM_DURATION_MILLIS)).isEqualTo(
+                DEFAULT_POST_DIM_CHECK_DURATION_MILLIS);
+    }
+
+    @Test
+    public void testGetPostDimCheckDurationMillis_handlesBadFlagValue() {
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_POST_DIM_CHECK_DURATION_MILLIS, "20000k", false);
+        assertThat(mRealAttentionDetector.getPostDimCheckDurationMillis(
+                DEFAULT_DIM_DURATION_MILLIS)).isEqualTo(
+                DEFAULT_POST_DIM_CHECK_DURATION_MILLIS);
+
+        DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                KEY_POST_DIM_CHECK_DURATION_MILLIS, "0.25", false);
+        assertThat(mRealAttentionDetector.getPostDimCheckDurationMillis(
+                DEFAULT_DIM_DURATION_MILLIS)).isEqualTo(
+                DEFAULT_POST_DIM_CHECK_DURATION_MILLIS);
+    }
+
     private long registerAttention() {
-        mAttentionTimeout = 4000L;
+        mPreDimCheckDuration = 4000L;
         mAttentionDetector.onUserActivity(SystemClock.uptimeMillis(),
                 PowerManager.USER_ACTIVITY_EVENT_TOUCH);
-        return mAttentionDetector.updateUserActivity(mNextDimming);
+        return mAttentionDetector.updateUserActivity(mNextDimming, DEFAULT_DIM_DURATION_MILLIS);
     }
 
     private class TestableAttentionDetector extends AttentionDetector {
@@ -329,8 +433,8 @@
         }
 
         @Override
-        public long getAttentionTimeout() {
-            return mAttentionTimeout;
+        public long getPreDimCheckDurationMillis() {
+            return mPreDimCheckDuration;
         }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 0ca62e2..81fb0ec 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -61,7 +61,6 @@
 import android.os.PowerManager;
 import android.os.PowerSaveState;
 import android.os.SystemClock;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.test.mock.MockContentResolver;
@@ -97,10 +96,12 @@
  * Tests for {@link com.android.server.power.PowerManagerService}
  */
 public class PowerManagerServiceTest {
+    private static final String SYSTEM_PROPERTY_QUIESCENT = "ro.boot.quiescent";
+    private static final String SYSTEM_PROPERTY_REBOOT_REASON = "sys.boot.reason";
+
     private static final float PRECISION = 0.001f;
     private static final float BRIGHTNESS_FACTOR = 0.7f;
     private static final boolean BATTERY_SAVER_ENABLED = true;
-    private static final String TEST_LAST_REBOOT_PROPERTY = "test.sys.boot.reason";
 
     @Mock private BatterySaverPolicy mBatterySaverPolicyMock;
     @Mock private LightsManager mLightsManagerMock;
@@ -112,6 +113,7 @@
     @Mock private Notifier mNotifierMock;
     @Mock private WirelessChargerDetector mWirelessChargerDetectorMock;
     @Mock private AmbientDisplayConfiguration mAmbientDisplayConfigurationMock;
+    @Mock private SystemPropertiesWrapper mSystemPropertiesMock;
 
     @Mock
     private InattentiveSleepWarningController mInattentiveSleepWarningControllerMock;
@@ -159,6 +161,7 @@
         when(mBatteryManagerInternalMock.isPowered(anyInt())).thenReturn(false);
         when(mInattentiveSleepWarningControllerMock.isShown()).thenReturn(false);
         when(mDisplayManagerInternalMock.requestPowerState(any(), anyBoolean())).thenReturn(true);
+        when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), anyString())).thenReturn("");
 
         mDisplayPowerRequest = new DisplayPowerRequest();
         addLocalServiceMock(LightsManager.class, mLightsManagerMock);
@@ -218,6 +221,11 @@
             InattentiveSleepWarningController createInattentiveSleepWarningController() {
                 return mInattentiveSleepWarningControllerMock;
             }
+
+            @Override
+            public SystemPropertiesWrapper createSystemPropertiesWrapper() {
+                return mSystemPropertiesMock;
+            }
         });
         return mService;
     }
@@ -228,12 +236,6 @@
         LocalServices.removeServiceForTest(DisplayManagerInternal.class);
         LocalServices.removeServiceForTest(BatteryManagerInternal.class);
         LocalServices.removeServiceForTest(ActivityManagerInternal.class);
-
-        Settings.Global.putInt(
-                mContextSpy.getContentResolver(), Settings.Global.THEATER_MODE_ON, 0);
-        setAttentiveTimeout(-1);
-        Settings.Global.putInt(mContextSpy.getContentResolver(),
-                Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
     }
 
     /**
@@ -322,10 +324,10 @@
 
     @Test
     public void testGetLastShutdownReasonInternal() {
+        when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_REBOOT_REASON), any())).thenReturn(
+                "shutdown,thermal");
         createService();
-        SystemProperties.set(TEST_LAST_REBOOT_PROPERTY, "shutdown,thermal");
-        int reason = mService.getLastShutdownReasonInternal(TEST_LAST_REBOOT_PROPERTY);
-        SystemProperties.set(TEST_LAST_REBOOT_PROPERTY, "");
+        int reason = mService.getLastShutdownReasonInternal();
         assertThat(reason).isEqualTo(PowerManager.SHUTDOWN_REASON_THERMAL_SHUTDOWN);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeDetectorStrategyTest.java
new file mode 100644
index 0000000..7a0a28d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeDetectorStrategyTest.java
@@ -0,0 +1,661 @@
+/*
+ * 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.server.timedetector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.app.timedetector.ManualTimeSuggestion;
+import android.app.timedetector.PhoneTimeSuggestion;
+import android.content.Intent;
+import android.icu.util.Calendar;
+import android.icu.util.GregorianCalendar;
+import android.icu.util.TimeZone;
+import android.util.TimestampedValue;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.time.Duration;
+
+@RunWith(AndroidJUnit4.class)
+public class SimpleTimeDetectorStrategyTest {
+
+    private static final Scenario SCENARIO_1 = new Scenario.Builder()
+            .setInitialDeviceSystemClockUtc(1977, 1, 1, 12, 0, 0)
+            .setInitialDeviceRealtimeMillis(123456789L)
+            .setActualTimeUtc(2018, 1, 1, 12, 0, 0)
+            .build();
+
+    private static final int ARBITRARY_PHONE_ID = 123456;
+
+    private static final long ONE_DAY_MILLIS = Duration.ofDays(1).toMillis();
+
+    private Script mScript;
+
+    @Before
+    public void setUp() {
+        mScript = new Script();
+    }
+
+    @Test
+    public void testSuggestPhoneTime_autoTimeEnabled() {
+        Scenario scenario = SCENARIO_1;
+        mScript.pokeFakeClocks(scenario)
+                .pokeTimeDetectionEnabled(true);
+
+        PhoneTimeSuggestion timeSuggestion =
+                scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
+        final int clockIncrement = 1000;
+        long expectSystemClockMillis = scenario.getActualTimeMillis() + clockIncrement;
+
+        mScript.simulateTimePassing(clockIncrement)
+                .simulatePhoneTimeSuggestion(timeSuggestion)
+                .verifySystemClockWasSetAndResetCallTracking(
+                        expectSystemClockMillis, true /* expectNetworkBroadcast */);
+    }
+
+    @Test
+    public void testSuggestPhoneTime_emptySuggestionIgnored() {
+        Scenario scenario = SCENARIO_1;
+        mScript.pokeFakeClocks(scenario)
+                .pokeTimeDetectionEnabled(true);
+
+        PhoneTimeSuggestion timeSuggestion = createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, null);
+
+        mScript.simulatePhoneTimeSuggestion(timeSuggestion)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+    }
+
+    @Test
+    public void testSuggestPhoneTime_systemClockThreshold() {
+        Scenario scenario = SCENARIO_1;
+        final int systemClockUpdateThresholdMillis = 1000;
+        mScript.pokeFakeClocks(scenario)
+                .pokeThresholds(systemClockUpdateThresholdMillis)
+                .pokeTimeDetectionEnabled(true);
+
+        PhoneTimeSuggestion timeSuggestion1 =
+                scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
+        TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
+
+        final int clockIncrement = 100;
+        // Increment the the device clocks to simulate the passage of time.
+        mScript.simulateTimePassing(clockIncrement);
+
+        long expectSystemClockMillis1 =
+                TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
+
+        // Send the first time signal. It should be used.
+        mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
+                .verifySystemClockWasSetAndResetCallTracking(
+                        expectSystemClockMillis1, true /* expectNetworkBroadcast */);
+
+        // Now send another time signal, but one that is too similar to the last one and should be
+        // ignored.
+        int underThresholdMillis = systemClockUpdateThresholdMillis - 1;
+        TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
+                mScript.peekElapsedRealtimeMillis(),
+                mScript.peekSystemClockMillis() + underThresholdMillis);
+        PhoneTimeSuggestion timeSuggestion2 =
+                createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
+        mScript.simulateTimePassing(clockIncrement)
+                .simulatePhoneTimeSuggestion(timeSuggestion2)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+
+        // Now send another time signal, but one that is on the threshold and so should be used.
+        TimestampedValue<Long> utcTime3 = new TimestampedValue<>(
+                mScript.peekElapsedRealtimeMillis(),
+                mScript.peekSystemClockMillis() + systemClockUpdateThresholdMillis);
+
+        PhoneTimeSuggestion timeSuggestion3 =
+                createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime3);
+        mScript.simulateTimePassing(clockIncrement);
+
+        long expectSystemClockMillis3 =
+                TimeDetectorStrategy.getTimeAt(utcTime3, mScript.peekElapsedRealtimeMillis());
+
+        mScript.simulatePhoneTimeSuggestion(timeSuggestion3)
+                .verifySystemClockWasSetAndResetCallTracking(
+                        expectSystemClockMillis3, true /* expectNetworkBroadcast */);
+    }
+
+    @Test
+    public void testSuggestPhoneTime_autoTimeDisabled() {
+        Scenario scenario = SCENARIO_1;
+        mScript.pokeFakeClocks(scenario)
+                .pokeTimeDetectionEnabled(false);
+
+        PhoneTimeSuggestion timeSuggestion =
+                scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
+        mScript.simulatePhoneTimeSuggestion(timeSuggestion)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+    }
+
+    @Test
+    public void testSuggestPhoneTime_invalidNitzReferenceTimesIgnored() {
+        Scenario scenario = SCENARIO_1;
+        final int systemClockUpdateThreshold = 2000;
+        mScript.pokeFakeClocks(scenario)
+                .pokeThresholds(systemClockUpdateThreshold)
+                .pokeTimeDetectionEnabled(true);
+        PhoneTimeSuggestion timeSuggestion1 =
+                scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
+        TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
+
+        // Initialize the strategy / device with a time set from NITZ.
+        mScript.simulateTimePassing(100);
+        long expectedSystemClockMillis1 =
+                TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
+        mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
+                .verifySystemClockWasSetAndResetCallTracking(
+                        expectedSystemClockMillis1, true /* expectNetworkBroadcast */);
+
+        // The UTC time increment should be larger than the system clock update threshold so we
+        // know it shouldn't be ignored for other reasons.
+        long validUtcTimeMillis = utcTime1.getValue() + (2 * systemClockUpdateThreshold);
+
+        // Now supply a new signal that has an obviously bogus reference time : older than the last
+        // one.
+        long referenceTimeBeforeLastSignalMillis = utcTime1.getReferenceTimeMillis() - 1;
+        TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
+                referenceTimeBeforeLastSignalMillis, validUtcTimeMillis);
+        PhoneTimeSuggestion timeSuggestion2 =
+                createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
+        mScript.simulatePhoneTimeSuggestion(timeSuggestion2)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+
+        // Now supply a new signal that has an obviously bogus reference time : substantially in the
+        // future.
+        long referenceTimeInFutureMillis =
+                utcTime1.getReferenceTimeMillis() + Integer.MAX_VALUE + 1;
+        TimestampedValue<Long> utcTime3 = new TimestampedValue<>(
+                referenceTimeInFutureMillis, validUtcTimeMillis);
+        PhoneTimeSuggestion timeSuggestion3 =
+                createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime3);
+        mScript.simulatePhoneTimeSuggestion(timeSuggestion3)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+
+        // Just to prove validUtcTimeMillis is valid.
+        long validReferenceTimeMillis = utcTime1.getReferenceTimeMillis() + 100;
+        TimestampedValue<Long> utcTime4 = new TimestampedValue<>(
+                validReferenceTimeMillis, validUtcTimeMillis);
+        long expectedSystemClockMillis4 =
+                TimeDetectorStrategy.getTimeAt(utcTime4, mScript.peekElapsedRealtimeMillis());
+        PhoneTimeSuggestion timeSuggestion4 =
+                createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime4);
+        mScript.simulatePhoneTimeSuggestion(timeSuggestion4)
+                .verifySystemClockWasSetAndResetCallTracking(
+                        expectedSystemClockMillis4, true /* expectNetworkBroadcast */);
+    }
+
+    @Test
+    public void testSuggestPhoneTime_timeDetectionToggled() {
+        Scenario scenario = SCENARIO_1;
+        final int clockIncrementMillis = 100;
+        final int systemClockUpdateThreshold = 2000;
+        mScript.pokeFakeClocks(scenario)
+                .pokeThresholds(systemClockUpdateThreshold)
+                .pokeTimeDetectionEnabled(false);
+
+        PhoneTimeSuggestion timeSuggestion1 =
+                scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
+        TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
+
+        // Simulate time passing.
+        mScript.simulateTimePassing(clockIncrementMillis);
+
+        // Simulate the time signal being received. It should not be used because auto time
+        // detection is off but it should be recorded.
+        mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+
+        // Simulate more time passing.
+        mScript.simulateTimePassing(clockIncrementMillis);
+
+        long expectedSystemClockMillis1 =
+                TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
+
+        // Turn on auto time detection.
+        mScript.simulateAutoTimeDetectionToggle()
+                .verifySystemClockWasSetAndResetCallTracking(
+                        expectedSystemClockMillis1, true /* expectNetworkBroadcast */);
+
+        // Turn off auto time detection.
+        mScript.simulateAutoTimeDetectionToggle()
+                .verifySystemClockWasNotSetAndResetCallTracking();
+
+        // Receive another valid time signal.
+        // It should be on the threshold and accounting for the clock increments.
+        TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
+                mScript.peekElapsedRealtimeMillis(),
+                mScript.peekSystemClockMillis() + systemClockUpdateThreshold);
+        PhoneTimeSuggestion timeSuggestion2 =
+                createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
+
+        // Simulate more time passing.
+        mScript.simulateTimePassing(clockIncrementMillis);
+
+        long expectedSystemClockMillis2 =
+                TimeDetectorStrategy.getTimeAt(utcTime2, mScript.peekElapsedRealtimeMillis());
+
+        // The new time, though valid, should not be set in the system clock because auto time is
+        // disabled.
+        mScript.simulatePhoneTimeSuggestion(timeSuggestion2)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+
+        // Turn on auto time detection.
+        mScript.simulateAutoTimeDetectionToggle()
+                .verifySystemClockWasSetAndResetCallTracking(
+                        expectedSystemClockMillis2, true /* expectNetworkBroadcast */);
+    }
+
+    @Test
+    public void testSuggestManualTime_autoTimeDisabled() {
+        Scenario scenario = SCENARIO_1;
+        mScript.pokeFakeClocks(scenario)
+                .pokeTimeDetectionEnabled(false);
+
+        ManualTimeSuggestion timeSuggestion = scenario.createManualTimeSuggestionForActual();
+        final int clockIncrement = 1000;
+        long expectSystemClockMillis = scenario.getActualTimeMillis() + clockIncrement;
+
+        mScript.simulateTimePassing(clockIncrement)
+                .simulateManualTimeSuggestion(timeSuggestion)
+                .verifySystemClockWasSetAndResetCallTracking(
+                        expectSystemClockMillis, false /* expectNetworkBroadcast */);
+    }
+
+    @Test
+    public void testSuggestManualTime_retainsAutoSignal() {
+        Scenario scenario = SCENARIO_1;
+
+        // Configure the start state.
+        mScript.pokeFakeClocks(scenario)
+                .pokeTimeDetectionEnabled(true);
+
+        // Simulate a phone suggestion.
+        PhoneTimeSuggestion phoneTimeSuggestion =
+                scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
+        long expectedAutoClockMillis = phoneTimeSuggestion.getUtcTime().getValue();
+        final int clockIncrement = 1000;
+
+        // Simulate the passage of time.
+        mScript.simulateTimePassing(clockIncrement);
+        expectedAutoClockMillis += clockIncrement;
+
+        mScript.simulatePhoneTimeSuggestion(phoneTimeSuggestion)
+                .verifySystemClockWasSetAndResetCallTracking(
+                        expectedAutoClockMillis, true /* expectNetworkBroadcast */);
+
+        // Simulate the passage of time.
+        mScript.simulateTimePassing(clockIncrement);
+        expectedAutoClockMillis += clockIncrement;
+
+        // Switch to manual.
+        mScript.simulateAutoTimeDetectionToggle()
+                .verifySystemClockWasNotSetAndResetCallTracking();
+
+        // Simulate the passage of time.
+        mScript.simulateTimePassing(clockIncrement);
+        expectedAutoClockMillis += clockIncrement;
+
+
+        // Simulate a manual suggestion 1 day different from the auto suggestion.
+        long manualTimeMillis = SCENARIO_1.getActualTimeMillis() + ONE_DAY_MILLIS;
+        long expectedManualClockMillis = manualTimeMillis;
+        ManualTimeSuggestion manualTimeSuggestion = createManualTimeSuggestion(manualTimeMillis);
+        mScript.simulateManualTimeSuggestion(manualTimeSuggestion)
+                .verifySystemClockWasSetAndResetCallTracking(
+                        expectedManualClockMillis, false /* expectNetworkBroadcast */);
+
+        // Simulate the passage of time.
+        mScript.simulateTimePassing(clockIncrement);
+        expectedAutoClockMillis += clockIncrement;
+
+        // Switch back to auto.
+        mScript.simulateAutoTimeDetectionToggle();
+
+        mScript.verifySystemClockWasSetAndResetCallTracking(
+                        expectedAutoClockMillis, true /* expectNetworkBroadcast */);
+
+        // Switch back to manual - nothing should happen to the clock.
+        mScript.simulateAutoTimeDetectionToggle()
+                .verifySystemClockWasNotSetAndResetCallTracking();
+    }
+
+    /**
+     * Manual suggestions should be ignored if auto time is enabled.
+     */
+    @Test
+    public void testSuggestManualTime_autoTimeEnabled() {
+        Scenario scenario = SCENARIO_1;
+        mScript.pokeFakeClocks(scenario)
+                .pokeTimeDetectionEnabled(true);
+
+        ManualTimeSuggestion timeSuggestion = scenario.createManualTimeSuggestionForActual();
+        final int clockIncrement = 1000;
+
+        mScript.simulateTimePassing(clockIncrement)
+                .simulateManualTimeSuggestion(timeSuggestion)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+    }
+
+    /**
+     * A fake implementation of TimeDetectorStrategy.Callback. Besides tracking changes and behaving
+     * like the real thing should, it also asserts preconditions.
+     */
+    private static class FakeCallback implements TimeDetectorStrategy.Callback {
+        private boolean mTimeDetectionEnabled;
+        private boolean mWakeLockAcquired;
+        private long mElapsedRealtimeMillis;
+        private long mSystemClockMillis;
+        private int mSystemClockUpdateThresholdMillis = 2000;
+
+        // Tracking operations.
+        private boolean mSystemClockWasSet;
+        private Intent mBroadcastSent;
+
+        @Override
+        public int systemClockUpdateThresholdMillis() {
+            return mSystemClockUpdateThresholdMillis;
+        }
+
+        @Override
+        public boolean isAutoTimeDetectionEnabled() {
+            return mTimeDetectionEnabled;
+        }
+
+        @Override
+        public void acquireWakeLock() {
+            if (mWakeLockAcquired) {
+                fail("Wake lock already acquired");
+            }
+            mWakeLockAcquired = true;
+        }
+
+        @Override
+        public long elapsedRealtimeMillis() {
+            assertWakeLockAcquired();
+            return mElapsedRealtimeMillis;
+        }
+
+        @Override
+        public long systemClockMillis() {
+            assertWakeLockAcquired();
+            return mSystemClockMillis;
+        }
+
+        @Override
+        public void setSystemClock(long newTimeMillis) {
+            assertWakeLockAcquired();
+            mSystemClockWasSet = true;
+            mSystemClockMillis = newTimeMillis;
+        }
+
+        @Override
+        public void releaseWakeLock() {
+            assertWakeLockAcquired();
+            mWakeLockAcquired = false;
+        }
+
+        @Override
+        public void sendStickyBroadcast(Intent intent) {
+            assertNotNull(intent);
+            mBroadcastSent = intent;
+        }
+
+        // Methods below are for managing the fake's behavior.
+
+        public void pokeSystemClockUpdateThreshold(int thresholdMillis) {
+            mSystemClockUpdateThresholdMillis = thresholdMillis;
+        }
+
+        public void pokeElapsedRealtimeMillis(long elapsedRealtimeMillis) {
+            mElapsedRealtimeMillis = elapsedRealtimeMillis;
+        }
+
+        public void pokeSystemClockMillis(long systemClockMillis) {
+            mSystemClockMillis = systemClockMillis;
+        }
+
+        public void pokeAutoTimeDetectionEnabled(boolean enabled) {
+            mTimeDetectionEnabled = enabled;
+        }
+
+        public long peekElapsedRealtimeMillis() {
+            return mElapsedRealtimeMillis;
+        }
+
+        public long peekSystemClockMillis() {
+            return mSystemClockMillis;
+        }
+
+        public void simulateTimePassing(int incrementMillis) {
+            mElapsedRealtimeMillis += incrementMillis;
+            mSystemClockMillis += incrementMillis;
+        }
+
+        public void simulateAutoTimeZoneDetectionToggle() {
+            mTimeDetectionEnabled = !mTimeDetectionEnabled;
+        }
+
+        public void verifySystemClockNotSet() {
+            assertFalse(mSystemClockWasSet);
+        }
+
+        public void verifySystemClockWasSet(long expectSystemClockMillis) {
+            assertTrue(mSystemClockWasSet);
+            assertEquals(expectSystemClockMillis, mSystemClockMillis);
+        }
+
+        public void verifyIntentWasBroadcast() {
+            assertTrue(mBroadcastSent != null);
+        }
+
+        public void verifyIntentWasNotBroadcast() {
+            assertNull(mBroadcastSent);
+        }
+
+        public void resetCallTracking() {
+            mSystemClockWasSet = false;
+            mBroadcastSent = null;
+        }
+
+        private void assertWakeLockAcquired() {
+            assertTrue("The operation must be performed only after acquiring the wakelock",
+                    mWakeLockAcquired);
+        }
+    }
+
+    /**
+     * A fluent helper class for tests.
+     */
+    private class Script {
+
+        private final FakeCallback mFakeCallback;
+        private final SimpleTimeDetectorStrategy mSimpleTimeDetectorStrategy;
+
+        Script() {
+            mFakeCallback = new FakeCallback();
+            mSimpleTimeDetectorStrategy = new SimpleTimeDetectorStrategy();
+            mSimpleTimeDetectorStrategy.initialize(mFakeCallback);
+
+        }
+
+        Script pokeTimeDetectionEnabled(boolean enabled) {
+            mFakeCallback.pokeAutoTimeDetectionEnabled(enabled);
+            return this;
+        }
+
+        Script pokeFakeClocks(Scenario scenario) {
+            mFakeCallback.pokeElapsedRealtimeMillis(scenario.getInitialRealTimeMillis());
+            mFakeCallback.pokeSystemClockMillis(scenario.getInitialSystemClockMillis());
+            return this;
+        }
+
+        Script pokeThresholds(int systemClockUpdateThreshold) {
+            mFakeCallback.pokeSystemClockUpdateThreshold(systemClockUpdateThreshold);
+            return this;
+        }
+
+        long peekElapsedRealtimeMillis() {
+            return mFakeCallback.peekElapsedRealtimeMillis();
+        }
+
+        long peekSystemClockMillis() {
+            return mFakeCallback.peekSystemClockMillis();
+        }
+
+        Script simulatePhoneTimeSuggestion(PhoneTimeSuggestion timeSuggestion) {
+            mSimpleTimeDetectorStrategy.suggestPhoneTime(timeSuggestion);
+            return this;
+        }
+
+        Script simulateManualTimeSuggestion(ManualTimeSuggestion timeSuggestion) {
+            mSimpleTimeDetectorStrategy.suggestManualTime(timeSuggestion);
+            return this;
+        }
+
+        Script simulateAutoTimeDetectionToggle() {
+            mFakeCallback.simulateAutoTimeZoneDetectionToggle();
+            mSimpleTimeDetectorStrategy.handleAutoTimeDetectionChanged();
+            return this;
+        }
+
+        Script simulateTimePassing(int clockIncrement) {
+            mFakeCallback.simulateTimePassing(clockIncrement);
+            return this;
+        }
+
+        Script verifySystemClockWasNotSetAndResetCallTracking() {
+            mFakeCallback.verifySystemClockNotSet();
+            mFakeCallback.verifyIntentWasNotBroadcast();
+            mFakeCallback.resetCallTracking();
+            return this;
+        }
+
+        Script verifySystemClockWasSetAndResetCallTracking(
+                long expectSystemClockMillis, boolean expectNetworkBroadcast) {
+            mFakeCallback.verifySystemClockWasSet(expectSystemClockMillis);
+            if (expectNetworkBroadcast) {
+                mFakeCallback.verifyIntentWasBroadcast();
+            }
+            mFakeCallback.resetCallTracking();
+            return this;
+        }
+    }
+
+    /**
+     * A starting scenario used during tests. Describes a fictional "physical" reality.
+     */
+    private static class Scenario {
+
+        private final long mInitialDeviceSystemClockMillis;
+        private final long mInitialDeviceRealtimeMillis;
+        private final long mActualTimeMillis;
+
+        Scenario(long initialDeviceSystemClock, long elapsedRealtime, long timeMillis) {
+            mInitialDeviceSystemClockMillis = initialDeviceSystemClock;
+            mActualTimeMillis = timeMillis;
+            mInitialDeviceRealtimeMillis = elapsedRealtime;
+        }
+
+        long getInitialRealTimeMillis() {
+            return mInitialDeviceRealtimeMillis;
+        }
+
+        long getInitialSystemClockMillis() {
+            return mInitialDeviceSystemClockMillis;
+        }
+
+        long getActualTimeMillis() {
+            return mActualTimeMillis;
+        }
+
+        PhoneTimeSuggestion createPhoneTimeSuggestionForActual(int phoneId) {
+            TimestampedValue<Long> time = new TimestampedValue<>(
+                    mInitialDeviceRealtimeMillis, mActualTimeMillis);
+            return createPhoneTimeSuggestion(phoneId, time);
+        }
+
+        ManualTimeSuggestion createManualTimeSuggestionForActual() {
+            TimestampedValue<Long> time = new TimestampedValue<>(
+                    mInitialDeviceRealtimeMillis, mActualTimeMillis);
+            return new ManualTimeSuggestion(time);
+        }
+
+        static class Builder {
+
+            private long mInitialDeviceSystemClockMillis;
+            private long mInitialDeviceRealtimeMillis;
+            private long mActualTimeMillis;
+
+            Builder setInitialDeviceSystemClockUtc(int year, int monthInYear, int day,
+                    int hourOfDay, int minute, int second) {
+                mInitialDeviceSystemClockMillis = createUtcTime(year, monthInYear, day, hourOfDay,
+                        minute, second);
+                return this;
+            }
+
+            Builder setInitialDeviceRealtimeMillis(long realtimeMillis) {
+                mInitialDeviceRealtimeMillis = realtimeMillis;
+                return this;
+            }
+
+            Builder setActualTimeUtc(int year, int monthInYear, int day, int hourOfDay,
+                    int minute, int second) {
+                mActualTimeMillis =
+                        createUtcTime(year, monthInYear, day, hourOfDay, minute, second);
+                return this;
+            }
+
+            Scenario build() {
+                return new Scenario(mInitialDeviceSystemClockMillis, mInitialDeviceRealtimeMillis,
+                        mActualTimeMillis);
+            }
+        }
+    }
+
+    private static PhoneTimeSuggestion createPhoneTimeSuggestion(int phoneId,
+            TimestampedValue<Long> utcTime) {
+        return new PhoneTimeSuggestion.Builder(phoneId)
+                .setUtcTime(utcTime)
+                .build();
+    }
+
+    private ManualTimeSuggestion createManualTimeSuggestion(long timeMillis) {
+        TimestampedValue<Long> utcTime =
+                new TimestampedValue<>(mScript.peekElapsedRealtimeMillis(), timeMillis);
+        return new ManualTimeSuggestion(utcTime);
+    }
+
+    private static long createUtcTime(int year, int monthInYear, int day, int hourOfDay, int minute,
+            int second) {
+        Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Etc/UTC"));
+        cal.clear();
+        cal.set(year, monthInYear - 1, day, hourOfDay, minute, second);
+        return cal.getTimeInMillis();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
deleted file mode 100644
index d797955..0000000
--- a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
+++ /dev/null
@@ -1,510 +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.server.timedetector;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.app.timedetector.PhoneTimeSuggestion;
-import android.content.Intent;
-import android.icu.util.Calendar;
-import android.icu.util.GregorianCalendar;
-import android.icu.util.TimeZone;
-import android.util.TimestampedValue;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class SimpleTimeZoneDetectorStrategyTest {
-
-    private static final Scenario SCENARIO_1 = new Scenario.Builder()
-            .setInitialDeviceSystemClockUtc(1977, 1, 1, 12, 0, 0)
-            .setInitialDeviceRealtimeMillis(123456789L)
-            .setActualTimeUtc(2018, 1, 1, 12, 0, 0)
-            .build();
-
-    private static final int ARBITRARY_PHONE_ID = 123456;
-
-    private Script mScript;
-
-    @Before
-    public void setUp() {
-        mScript = new Script();
-    }
-
-    @Test
-    public void testSuggestPhoneTime_nitz_timeDetectionEnabled() {
-        Scenario scenario = SCENARIO_1;
-        mScript.pokeFakeClocks(scenario)
-                .pokeTimeDetectionEnabled(true);
-
-        PhoneTimeSuggestion timeSuggestion =
-                scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
-        final int clockIncrement = 1000;
-        long expectSystemClockMillis = scenario.getActualTimeMillis() + clockIncrement;
-
-        mScript.simulateTimePassing(clockIncrement)
-                .simulatePhoneTimeSuggestion(timeSuggestion)
-                .verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis);
-    }
-
-    @Test
-    public void testSuggestPhoneTime_systemClockThreshold() {
-        Scenario scenario = SCENARIO_1;
-        final int systemClockUpdateThresholdMillis = 1000;
-        mScript.pokeFakeClocks(scenario)
-                .pokeThresholds(systemClockUpdateThresholdMillis)
-                .pokeTimeDetectionEnabled(true);
-
-        PhoneTimeSuggestion timeSuggestion1 =
-                scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
-        TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
-
-        final int clockIncrement = 100;
-        // Increment the the device clocks to simulate the passage of time.
-        mScript.simulateTimePassing(clockIncrement);
-
-        long expectSystemClockMillis1 =
-                TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
-
-        // Send the first time signal. It should be used.
-        mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
-                .verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis1);
-
-        // Now send another time signal, but one that is too similar to the last one and should be
-        // ignored.
-        int underThresholdMillis = systemClockUpdateThresholdMillis - 1;
-        TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
-                mScript.peekElapsedRealtimeMillis(),
-                mScript.peekSystemClockMillis() + underThresholdMillis);
-        PhoneTimeSuggestion timeSuggestion2 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
-        mScript.simulateTimePassing(clockIncrement)
-                .simulatePhoneTimeSuggestion(timeSuggestion2)
-                .verifySystemClockWasNotSetAndResetCallTracking();
-
-        // Now send another time signal, but one that is on the threshold and so should be used.
-        TimestampedValue<Long> utcTime3 = new TimestampedValue<>(
-                mScript.peekElapsedRealtimeMillis(),
-                mScript.peekSystemClockMillis() + systemClockUpdateThresholdMillis);
-
-        PhoneTimeSuggestion timeSuggestion3 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime3);
-        mScript.simulateTimePassing(clockIncrement);
-
-        long expectSystemClockMillis3 =
-                TimeDetectorStrategy.getTimeAt(utcTime3, mScript.peekElapsedRealtimeMillis());
-
-        mScript.simulatePhoneTimeSuggestion(timeSuggestion3)
-                .verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis3);
-    }
-
-    @Test
-    public void testSuggestPhoneTime_nitz_timeDetectionDisabled() {
-        Scenario scenario = SCENARIO_1;
-        mScript.pokeFakeClocks(scenario)
-                .pokeTimeDetectionEnabled(false);
-
-        PhoneTimeSuggestion timeSuggestion =
-                scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
-        mScript.simulatePhoneTimeSuggestion(timeSuggestion)
-                .verifySystemClockWasNotSetAndResetCallTracking();
-    }
-
-    @Test
-    public void testSuggestPhoneTime_nitz_invalidNitzReferenceTimesIgnored() {
-        Scenario scenario = SCENARIO_1;
-        final int systemClockUpdateThreshold = 2000;
-        mScript.pokeFakeClocks(scenario)
-                .pokeThresholds(systemClockUpdateThreshold)
-                .pokeTimeDetectionEnabled(true);
-        PhoneTimeSuggestion timeSuggestion1 =
-                scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
-        TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
-
-        // Initialize the strategy / device with a time set from NITZ.
-        mScript.simulateTimePassing(100);
-        long expectedSystemClockMillis1 =
-                TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
-        mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
-                .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1);
-
-        // The UTC time increment should be larger than the system clock update threshold so we
-        // know it shouldn't be ignored for other reasons.
-        long validUtcTimeMillis = utcTime1.getValue() + (2 * systemClockUpdateThreshold);
-
-        // Now supply a new signal that has an obviously bogus reference time : older than the last
-        // one.
-        long referenceTimeBeforeLastSignalMillis = utcTime1.getReferenceTimeMillis() - 1;
-        TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
-                referenceTimeBeforeLastSignalMillis, validUtcTimeMillis);
-        PhoneTimeSuggestion timeSuggestion2 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
-        mScript.simulatePhoneTimeSuggestion(timeSuggestion2)
-                .verifySystemClockWasNotSetAndResetCallTracking();
-
-        // Now supply a new signal that has an obviously bogus reference time : substantially in the
-        // future.
-        long referenceTimeInFutureMillis =
-                utcTime1.getReferenceTimeMillis() + Integer.MAX_VALUE + 1;
-        TimestampedValue<Long> utcTime3 = new TimestampedValue<>(
-                referenceTimeInFutureMillis, validUtcTimeMillis);
-        PhoneTimeSuggestion timeSuggestion3 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime3);
-        mScript.simulatePhoneTimeSuggestion(timeSuggestion3)
-                .verifySystemClockWasNotSetAndResetCallTracking();
-
-        // Just to prove validUtcTimeMillis is valid.
-        long validReferenceTimeMillis = utcTime1.getReferenceTimeMillis() + 100;
-        TimestampedValue<Long> utcTime4 = new TimestampedValue<>(
-                validReferenceTimeMillis, validUtcTimeMillis);
-        long expectedSystemClockMillis4 =
-                TimeDetectorStrategy.getTimeAt(utcTime4, mScript.peekElapsedRealtimeMillis());
-        PhoneTimeSuggestion timeSuggestion4 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime4);
-        mScript.simulatePhoneTimeSuggestion(timeSuggestion4)
-                .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis4);
-    }
-
-    @Test
-    public void testSuggestPhoneTime_timeDetectionToggled() {
-        Scenario scenario = SCENARIO_1;
-        final int clockIncrementMillis = 100;
-        final int systemClockUpdateThreshold = 2000;
-        mScript.pokeFakeClocks(scenario)
-                .pokeThresholds(systemClockUpdateThreshold)
-                .pokeTimeDetectionEnabled(false);
-
-        PhoneTimeSuggestion timeSuggestion1 =
-                scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
-        TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
-
-        // Simulate time passing.
-        mScript.simulateTimePassing(clockIncrementMillis);
-
-        // Simulate the time signal being received. It should not be used because auto time
-        // detection is off but it should be recorded.
-        mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
-                .verifySystemClockWasNotSetAndResetCallTracking();
-
-        // Simulate more time passing.
-        mScript.simulateTimePassing(clockIncrementMillis);
-
-        long expectedSystemClockMillis1 =
-                TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
-
-        // Turn on auto time detection.
-        mScript.simulateAutoTimeDetectionToggle()
-                .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1);
-
-        // Turn off auto time detection.
-        mScript.simulateAutoTimeDetectionToggle()
-                .verifySystemClockWasNotSetAndResetCallTracking();
-
-        // Receive another valid time signal.
-        // It should be on the threshold and accounting for the clock increments.
-        TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
-                mScript.peekElapsedRealtimeMillis(),
-                mScript.peekSystemClockMillis() + systemClockUpdateThreshold);
-        PhoneTimeSuggestion timeSuggestion2 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
-
-        // Simulate more time passing.
-        mScript.simulateTimePassing(clockIncrementMillis);
-
-        long expectedSystemClockMillis2 =
-                TimeDetectorStrategy.getTimeAt(utcTime2, mScript.peekElapsedRealtimeMillis());
-
-        // The new time, though valid, should not be set in the system clock because auto time is
-        // disabled.
-        mScript.simulatePhoneTimeSuggestion(timeSuggestion2)
-                .verifySystemClockWasNotSetAndResetCallTracking();
-
-        // Turn on auto time detection.
-        mScript.simulateAutoTimeDetectionToggle()
-                .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis2);
-    }
-
-    /**
-     * A fake implementation of TimeDetectorStrategy.Callback. Besides tracking changes and behaving
-     * like the real thing should, it also asserts preconditions.
-     */
-    private static class FakeCallback implements TimeDetectorStrategy.Callback {
-        private boolean mTimeDetectionEnabled;
-        private boolean mWakeLockAcquired;
-        private long mElapsedRealtimeMillis;
-        private long mSystemClockMillis;
-        private int mSystemClockUpdateThresholdMillis = 2000;
-
-        // Tracking operations.
-        private boolean mSystemClockWasSet;
-        private Intent mBroadcastSent;
-
-        @Override
-        public int systemClockUpdateThresholdMillis() {
-            return mSystemClockUpdateThresholdMillis;
-        }
-
-        @Override
-        public boolean isTimeDetectionEnabled() {
-            return mTimeDetectionEnabled;
-        }
-
-        @Override
-        public void acquireWakeLock() {
-            if (mWakeLockAcquired) {
-                fail("Wake lock already acquired");
-            }
-            mWakeLockAcquired = true;
-        }
-
-        @Override
-        public long elapsedRealtimeMillis() {
-            assertWakeLockAcquired();
-            return mElapsedRealtimeMillis;
-        }
-
-        @Override
-        public long systemClockMillis() {
-            assertWakeLockAcquired();
-            return mSystemClockMillis;
-        }
-
-        @Override
-        public void setSystemClock(long newTimeMillis) {
-            assertWakeLockAcquired();
-            mSystemClockWasSet = true;
-            mSystemClockMillis = newTimeMillis;
-        }
-
-        @Override
-        public void releaseWakeLock() {
-            assertWakeLockAcquired();
-            mWakeLockAcquired = false;
-        }
-
-        @Override
-        public void sendStickyBroadcast(Intent intent) {
-            assertNotNull(intent);
-            mBroadcastSent = intent;
-        }
-
-        // Methods below are for managing the fake's behavior.
-
-        public void pokeSystemClockUpdateThreshold(int thresholdMillis) {
-            mSystemClockUpdateThresholdMillis = thresholdMillis;
-        }
-
-        public void pokeElapsedRealtimeMillis(long elapsedRealtimeMillis) {
-            mElapsedRealtimeMillis = elapsedRealtimeMillis;
-        }
-
-        public void pokeSystemClockMillis(long systemClockMillis) {
-            mSystemClockMillis = systemClockMillis;
-        }
-
-        public void pokeTimeDetectionEnabled(boolean enabled) {
-            mTimeDetectionEnabled = enabled;
-        }
-
-        public long peekElapsedRealtimeMillis() {
-            return mElapsedRealtimeMillis;
-        }
-
-        public long peekSystemClockMillis() {
-            return mSystemClockMillis;
-        }
-
-        public void simulateTimePassing(int incrementMillis) {
-            mElapsedRealtimeMillis += incrementMillis;
-            mSystemClockMillis += incrementMillis;
-        }
-
-        public void verifySystemClockNotSet() {
-            assertFalse(mSystemClockWasSet);
-        }
-
-        public void verifySystemClockWasSet(long expectSystemClockMillis) {
-            assertTrue(mSystemClockWasSet);
-            assertEquals(expectSystemClockMillis, mSystemClockMillis);
-        }
-
-        public void verifyIntentWasBroadcast() {
-            assertTrue(mBroadcastSent != null);
-        }
-
-        public void verifyIntentWasNotBroadcast() {
-            assertNull(mBroadcastSent);
-        }
-
-        public void resetCallTracking() {
-            mSystemClockWasSet = false;
-            mBroadcastSent = null;
-        }
-
-        private void assertWakeLockAcquired() {
-            assertTrue("The operation must be performed only after acquiring the wakelock",
-                    mWakeLockAcquired);
-        }
-    }
-
-    /**
-     * A fluent helper class for tests.
-     */
-    private class Script {
-
-        private final FakeCallback mFakeCallback;
-        private final SimpleTimeDetectorStrategy mSimpleTimeDetectorStrategy;
-
-        public Script() {
-            mFakeCallback = new FakeCallback();
-            mSimpleTimeDetectorStrategy = new SimpleTimeDetectorStrategy();
-            mSimpleTimeDetectorStrategy.initialize(mFakeCallback);
-
-        }
-
-        Script pokeTimeDetectionEnabled(boolean enabled) {
-            mFakeCallback.pokeTimeDetectionEnabled(enabled);
-            return this;
-        }
-
-        Script pokeFakeClocks(Scenario scenario) {
-            mFakeCallback.pokeElapsedRealtimeMillis(scenario.getInitialRealTimeMillis());
-            mFakeCallback.pokeSystemClockMillis(scenario.getInitialSystemClockMillis());
-            return this;
-        }
-
-        Script pokeThresholds(int systemClockUpdateThreshold) {
-            mFakeCallback.pokeSystemClockUpdateThreshold(systemClockUpdateThreshold);
-            return this;
-        }
-
-        long peekElapsedRealtimeMillis() {
-            return mFakeCallback.peekElapsedRealtimeMillis();
-        }
-
-        long peekSystemClockMillis() {
-            return mFakeCallback.peekSystemClockMillis();
-        }
-
-        Script simulatePhoneTimeSuggestion(PhoneTimeSuggestion timeSuggestion) {
-            mSimpleTimeDetectorStrategy.suggestPhoneTime(timeSuggestion);
-            return this;
-        }
-
-        Script simulateAutoTimeDetectionToggle() {
-            boolean enabled = !mFakeCallback.isTimeDetectionEnabled();
-            mFakeCallback.pokeTimeDetectionEnabled(enabled);
-            mSimpleTimeDetectorStrategy.handleAutoTimeDetectionToggle(enabled);
-            return this;
-        }
-
-        Script simulateTimePassing(int clockIncrement) {
-            mFakeCallback.simulateTimePassing(clockIncrement);
-            return this;
-        }
-
-        Script verifySystemClockWasNotSetAndResetCallTracking() {
-            mFakeCallback.verifySystemClockNotSet();
-            mFakeCallback.verifyIntentWasNotBroadcast();
-            mFakeCallback.resetCallTracking();
-            return this;
-        }
-
-        Script verifySystemClockWasSetAndResetCallTracking(long expectSystemClockMillis) {
-            mFakeCallback.verifySystemClockWasSet(expectSystemClockMillis);
-            mFakeCallback.verifyIntentWasBroadcast();
-            mFakeCallback.resetCallTracking();
-            return this;
-        }
-    }
-
-    /**
-     * A starting scenario used during tests. Describes a fictional "physical" reality.
-     */
-    private static class Scenario {
-
-        private final long mInitialDeviceSystemClockMillis;
-        private final long mInitialDeviceRealtimeMillis;
-        private final long mActualTimeMillis;
-
-        Scenario(long initialDeviceSystemClock, long elapsedRealtime, long timeMillis) {
-            mInitialDeviceSystemClockMillis = initialDeviceSystemClock;
-            mActualTimeMillis = timeMillis;
-            mInitialDeviceRealtimeMillis = elapsedRealtime;
-        }
-
-        long getInitialRealTimeMillis() {
-            return mInitialDeviceRealtimeMillis;
-        }
-
-        long getInitialSystemClockMillis() {
-            return mInitialDeviceSystemClockMillis;
-        }
-
-        long getActualTimeMillis() {
-            return mActualTimeMillis;
-        }
-
-        PhoneTimeSuggestion createPhoneTimeSuggestionForActual(int phoneId) {
-            TimestampedValue<Long> time = new TimestampedValue<>(
-                    mInitialDeviceRealtimeMillis, mActualTimeMillis);
-            return new PhoneTimeSuggestion(phoneId, time);
-        }
-
-        static class Builder {
-
-            private long mInitialDeviceSystemClockMillis;
-            private long mInitialDeviceRealtimeMillis;
-            private long mActualTimeMillis;
-
-            Builder setInitialDeviceSystemClockUtc(int year, int monthInYear, int day,
-                    int hourOfDay, int minute, int second) {
-                mInitialDeviceSystemClockMillis = createUtcTime(year, monthInYear, day, hourOfDay,
-                        minute, second);
-                return this;
-            }
-
-            Builder setInitialDeviceRealtimeMillis(long realtimeMillis) {
-                mInitialDeviceRealtimeMillis = realtimeMillis;
-                return this;
-            }
-
-            Builder setActualTimeUtc(int year, int monthInYear, int day, int hourOfDay,
-                    int minute, int second) {
-                mActualTimeMillis =
-                        createUtcTime(year, monthInYear, day, hourOfDay, minute, second);
-                return this;
-            }
-
-            Scenario build() {
-                return new Scenario(mInitialDeviceSystemClockMillis, mInitialDeviceRealtimeMillis,
-                        mActualTimeMillis);
-            }
-        }
-    }
-
-    private static long createUtcTime(int year, int monthInYear, int day, int hourOfDay, int minute,
-            int second) {
-        Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Etc/UTC"));
-        cal.clear();
-        cal.set(year, monthInYear - 1, day, hourOfDay, minute, second);
-        return cal.getTimeInMillis();
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index 37da018..84b495f 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -17,26 +17,30 @@
 package com.android.server.timedetector;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.timedetector.ManualTimeSuggestion;
 import android.app.timedetector.PhoneTimeSuggestion;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
 import android.util.TimestampedValue;
 
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.timedetector.TimeDetectorStrategy.Callback;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -51,45 +55,66 @@
     private Callback mMockCallback;
 
     private TimeDetectorService mTimeDetectorService;
+    private HandlerThread mHandlerThread;
+    private TestHandler mTestHandler;
+
 
     @Before
     public void setUp() {
         mMockContext = mock(Context.class);
+
+        // Create a thread + handler for processing the work that the service posts.
+        mHandlerThread = new HandlerThread("TimeDetectorServiceTest");
+        mHandlerThread.start();
+        mTestHandler = new TestHandler(mHandlerThread.getLooper());
+
         mMockCallback = mock(Callback.class);
         mStubbedTimeDetectorStrategy = new StubbedTimeDetectorStrategy();
 
         mTimeDetectorService = new TimeDetectorService(
-                mMockContext, mMockCallback,
+                mMockContext, mTestHandler, mMockCallback,
                 mStubbedTimeDetectorStrategy);
     }
 
-    @Test(expected=SecurityException.class)
-    public void testStubbedCall_withoutPermission() {
-        doThrow(new SecurityException("Mock"))
-                .when(mMockContext).enforceCallingPermission(anyString(), any());
-        PhoneTimeSuggestion phoneTimeSuggestion = createPhoneTimeSuggestion();
-
-        try {
-            mTimeDetectorService.suggestPhoneTime(phoneTimeSuggestion);
-        } finally {
-            verify(mMockContext).enforceCallingPermission(
-                    eq(android.Manifest.permission.SET_TIME), anyString());
-        }
+    @After
+    public void tearDown() throws Exception {
+        mHandlerThread.quit();
+        mHandlerThread.join();
     }
 
     @Test
-    public void testSuggestPhoneTime() {
+    public void testSuggestPhoneTime() throws Exception {
         doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
 
         PhoneTimeSuggestion phoneTimeSuggestion = createPhoneTimeSuggestion();
         mTimeDetectorService.suggestPhoneTime(phoneTimeSuggestion);
+        mTestHandler.assertTotalMessagesEnqueued(1);
 
-        verify(mMockContext)
-                .enforceCallingPermission(eq(android.Manifest.permission.SET_TIME), anyString());
+        verify(mMockContext).enforceCallingPermission(
+                eq(android.Manifest.permission.SET_TIME),
+                anyString());
+
+        mTestHandler.waitForEmptyQueue();
         mStubbedTimeDetectorStrategy.verifySuggestPhoneTimeCalled(phoneTimeSuggestion);
     }
 
     @Test
+    public void testSuggestManualTime() throws Exception {
+        doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
+
+        ManualTimeSuggestion manualTimeSuggestion = createManualTimeSuggestion();
+        mTimeDetectorService.suggestManualTime(manualTimeSuggestion);
+        mTestHandler.assertTotalMessagesEnqueued(1);
+
+        verify(mMockContext).enforceCallingPermission(
+                eq(android.Manifest.permission.SET_TIME),
+                anyString());
+
+        mTestHandler.waitForEmptyQueue();
+        mStubbedTimeDetectorStrategy.verifySuggestManualTimeCalled(manualTimeSuggestion);
+    }
+
+    @Test
     public void testDump() {
         when(mMockContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP))
                 .thenReturn(PackageManager.PERMISSION_GRANTED);
@@ -101,31 +126,37 @@
     }
 
     @Test
-    public void testAutoTimeDetectionToggle() {
-        when(mMockCallback.isTimeDetectionEnabled()).thenReturn(true);
+    public void testAutoTimeDetectionToggle() throws Exception {
+        mTimeDetectorService.handleAutoTimeDetectionToggle();
+        mTestHandler.assertTotalMessagesEnqueued(1);
+        mTestHandler.waitForEmptyQueue();
+        mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionToggleCalled();
 
         mTimeDetectorService.handleAutoTimeDetectionToggle();
-
-        mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionToggleCalled(true);
-
-        when(mMockCallback.isTimeDetectionEnabled()).thenReturn(false);
-
-        mTimeDetectorService.handleAutoTimeDetectionToggle();
-
-        mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionToggleCalled(false);
+        mTestHandler.assertTotalMessagesEnqueued(2);
+        mTestHandler.waitForEmptyQueue();
+        mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionToggleCalled();
     }
 
     private static PhoneTimeSuggestion createPhoneTimeSuggestion() {
         int phoneId = 1234;
         TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L);
-        return new PhoneTimeSuggestion(phoneId, timeValue);
+        return new PhoneTimeSuggestion.Builder(phoneId)
+                .setUtcTime(timeValue)
+                .build();
+    }
+
+    private static ManualTimeSuggestion createManualTimeSuggestion() {
+        TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L);
+        return new ManualTimeSuggestion(timeValue);
     }
 
     private static class StubbedTimeDetectorStrategy implements TimeDetectorStrategy {
 
         // Call tracking.
         private PhoneTimeSuggestion mLastPhoneSuggestion;
-        private Boolean mLastAutoTimeDetectionToggle;
+        private ManualTimeSuggestion mLastManualSuggestion;
+        private boolean mLastAutoTimeDetectionToggleCalled;
         private boolean mDumpCalled;
 
         @Override
@@ -139,9 +170,15 @@
         }
 
         @Override
-        public void handleAutoTimeDetectionToggle(boolean enabled) {
+        public void suggestManualTime(ManualTimeSuggestion timeSuggestion) {
             resetCallTracking();
-            mLastAutoTimeDetectionToggle = enabled;
+            mLastManualSuggestion = timeSuggestion;
+        }
+
+        @Override
+        public void handleAutoTimeDetectionChanged() {
+            resetCallTracking();
+            mLastAutoTimeDetectionToggleCalled = true;
         }
 
         @Override
@@ -152,21 +189,58 @@
 
         void resetCallTracking() {
             mLastPhoneSuggestion = null;
-            mLastAutoTimeDetectionToggle = null;
+            mLastManualSuggestion = null;
+            mLastAutoTimeDetectionToggleCalled = false;
             mDumpCalled = false;
         }
 
-        void verifySuggestPhoneTimeCalled(PhoneTimeSuggestion expectedSignal) {
-            assertEquals(expectedSignal, mLastPhoneSuggestion);
+        void verifySuggestPhoneTimeCalled(PhoneTimeSuggestion expectedSuggestion) {
+            assertEquals(expectedSuggestion, mLastPhoneSuggestion);
         }
 
-        void verifyHandleAutoTimeDetectionToggleCalled(boolean expectedEnable) {
-            assertNotNull(mLastAutoTimeDetectionToggle);
-            assertEquals(expectedEnable, mLastAutoTimeDetectionToggle);
+        public void verifySuggestManualTimeCalled(ManualTimeSuggestion expectedSuggestion) {
+            assertEquals(expectedSuggestion, mLastManualSuggestion);
+        }
+
+        void verifyHandleAutoTimeDetectionToggleCalled() {
+            assertTrue(mLastAutoTimeDetectionToggleCalled);
         }
 
         void verifyDumpCalled() {
             assertTrue(mDumpCalled);
         }
     }
+
+    /**
+     * A Handler that can track posts/sends and wait for work to be completed.
+     */
+    private static class TestHandler extends Handler {
+
+        private int mMessagesSent;
+
+        TestHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
+            mMessagesSent++;
+            return super.sendMessageAtTime(msg, uptimeMillis);
+        }
+
+        /** Asserts the number of messages posted or sent is as expected. */
+        void assertTotalMessagesEnqueued(int expected) {
+            assertEquals(expected, mMessagesSent);
+        }
+
+        /**
+         * Waits for all currently enqueued work due to be processed to be completed before
+         * returning.
+         */
+        void waitForEmptyQueue() throws InterruptedException {
+            while (!getLooper().getQueue().isIdle()) {
+                Thread.sleep(100);
+            }
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java
new file mode 100644
index 0000000..cb49fef
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java
@@ -0,0 +1,626 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezonedetector;
+
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE;
+
+import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.PHONE_SCORE_HIGH;
+import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.PHONE_SCORE_HIGHEST;
+import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.PHONE_SCORE_LOW;
+import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.PHONE_SCORE_MEDIUM;
+import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.PHONE_SCORE_NONE;
+import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.PHONE_SCORE_USAGE_THRESHOLD;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.app.timezonedetector.ManualTimeZoneSuggestion;
+import android.app.timezonedetector.PhoneTimeZoneSuggestion;
+import android.app.timezonedetector.PhoneTimeZoneSuggestion.MatchType;
+import android.app.timezonedetector.PhoneTimeZoneSuggestion.Quality;
+
+import com.android.server.timezonedetector.TimeZoneDetectorStrategy.QualifiedPhoneTimeZoneSuggestion;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+
+/**
+ * White-box unit tests for {@link TimeZoneDetectorStrategy}.
+ */
+public class TimeZoneDetectorStrategyTest {
+
+    /** A time zone used for initialization that does not occur elsewhere in tests. */
+    private static final String ARBITRARY_TIME_ZONE_ID = "Etc/UTC";
+    private static final int PHONE1_ID = 10000;
+    private static final int PHONE2_ID = 20000;
+
+    // Suggestion test cases are ordered so that each successive one is of the same or higher score
+    // than the previous.
+    private static final SuggestionTestCase[] TEST_CASES = new SuggestionTestCase[] {
+            newTestCase(MATCH_TYPE_NETWORK_COUNTRY_ONLY,
+                    QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS, PHONE_SCORE_LOW),
+            newTestCase(MATCH_TYPE_NETWORK_COUNTRY_ONLY, QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET,
+                    PHONE_SCORE_MEDIUM),
+            newTestCase(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET,
+                    QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET, PHONE_SCORE_MEDIUM),
+            newTestCase(MATCH_TYPE_NETWORK_COUNTRY_ONLY, QUALITY_SINGLE_ZONE, PHONE_SCORE_HIGH),
+            newTestCase(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, QUALITY_SINGLE_ZONE,
+                    PHONE_SCORE_HIGH),
+            newTestCase(MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY,
+                    QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET, PHONE_SCORE_HIGHEST),
+            newTestCase(MATCH_TYPE_EMULATOR_ZONE_ID, QUALITY_SINGLE_ZONE, PHONE_SCORE_HIGHEST),
+    };
+
+    private TimeZoneDetectorStrategy mTimeZoneDetectorStrategy;
+    private FakeTimeZoneDetectorStrategyCallback mFakeTimeZoneDetectorStrategyCallback;
+
+    @Before
+    public void setUp() {
+        mFakeTimeZoneDetectorStrategyCallback = new FakeTimeZoneDetectorStrategyCallback();
+        mTimeZoneDetectorStrategy =
+                new TimeZoneDetectorStrategy(mFakeTimeZoneDetectorStrategyCallback);
+    }
+
+    @Test
+    public void testEmptyPhoneSuggestions() {
+        PhoneTimeZoneSuggestion phone1TimeZoneSuggestion = createEmptyPhone1Suggestion();
+        PhoneTimeZoneSuggestion phone2TimeZoneSuggestion = createEmptyPhone2Suggestion();
+        Script script = new Script()
+                .initializeAutoTimeZoneDetection(true)
+                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+
+        script.suggestPhoneTimeZone(phone1TimeZoneSuggestion)
+                .verifyTimeZoneNotSet();
+
+        // Assert internal service state.
+        QualifiedPhoneTimeZoneSuggestion expectedPhone1ScoredSuggestion =
+                new QualifiedPhoneTimeZoneSuggestion(phone1TimeZoneSuggestion, PHONE_SCORE_NONE);
+        assertEquals(expectedPhone1ScoredSuggestion,
+                mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+        assertNull(mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE2_ID));
+        assertEquals(expectedPhone1ScoredSuggestion,
+                mTimeZoneDetectorStrategy.findBestPhoneSuggestionForTests());
+
+        script.suggestPhoneTimeZone(phone2TimeZoneSuggestion)
+                .verifyTimeZoneNotSet();
+
+        // Assert internal service state.
+        QualifiedPhoneTimeZoneSuggestion expectedPhone2ScoredSuggestion =
+                new QualifiedPhoneTimeZoneSuggestion(phone2TimeZoneSuggestion, PHONE_SCORE_NONE);
+        assertEquals(expectedPhone1ScoredSuggestion,
+                mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+        assertEquals(expectedPhone2ScoredSuggestion,
+                mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE2_ID));
+        // Phone 1 should always beat phone 2, all other things being equal.
+        assertEquals(expectedPhone1ScoredSuggestion,
+                mTimeZoneDetectorStrategy.findBestPhoneSuggestionForTests());
+    }
+
+    @Test
+    public void testFirstPlausiblePhoneSuggestionAcceptedWhenTimeZoneUninitialized() {
+        SuggestionTestCase testCase = newTestCase(MATCH_TYPE_NETWORK_COUNTRY_ONLY,
+                QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS, PHONE_SCORE_LOW);
+        PhoneTimeZoneSuggestion lowQualitySuggestion =
+                testCase.createSuggestion(PHONE1_ID, "America/New_York");
+
+        // The device time zone setting is left uninitialized.
+        Script script = new Script()
+                .initializeAutoTimeZoneDetection(true);
+
+        // The very first suggestion will be taken.
+        script.suggestPhoneTimeZone(lowQualitySuggestion)
+                .verifyTimeZoneSetAndReset(lowQualitySuggestion);
+
+        // Assert internal service state.
+        QualifiedPhoneTimeZoneSuggestion expectedScoredSuggestion =
+                new QualifiedPhoneTimeZoneSuggestion(lowQualitySuggestion, testCase.expectedScore);
+        assertEquals(expectedScoredSuggestion,
+                mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+        assertEquals(expectedScoredSuggestion,
+                mTimeZoneDetectorStrategy.findBestPhoneSuggestionForTests());
+
+        // Another low quality suggestion will be ignored now that the setting is initialized.
+        PhoneTimeZoneSuggestion lowQualitySuggestion2 =
+                testCase.createSuggestion(PHONE1_ID, "America/Los_Angeles");
+        script.suggestPhoneTimeZone(lowQualitySuggestion2)
+                .verifyTimeZoneNotSet();
+
+        // Assert internal service state.
+        QualifiedPhoneTimeZoneSuggestion expectedScoredSuggestion2 =
+                new QualifiedPhoneTimeZoneSuggestion(lowQualitySuggestion2, testCase.expectedScore);
+        assertEquals(expectedScoredSuggestion2,
+                mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+        assertEquals(expectedScoredSuggestion2,
+                mTimeZoneDetectorStrategy.findBestPhoneSuggestionForTests());
+    }
+
+    /**
+     * Confirms that toggling the auto time zone detection setting has the expected behavior when
+     * the strategy is "opinionated".
+     */
+    @Test
+    public void testTogglingAutoTimeZoneDetection() {
+        Script script = new Script();
+
+        for (SuggestionTestCase testCase : TEST_CASES) {
+            // Start with the device in a known state.
+            script.initializeAutoTimeZoneDetection(false)
+                    .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+
+            PhoneTimeZoneSuggestion suggestion =
+                    testCase.createSuggestion(PHONE1_ID, "Europe/London");
+            script.suggestPhoneTimeZone(suggestion);
+
+            // When time zone detection is not enabled, the time zone suggestion will not be set
+            // regardless of the score.
+            script.verifyTimeZoneNotSet();
+
+            // Assert internal service state.
+            QualifiedPhoneTimeZoneSuggestion expectedScoredSuggestion =
+                    new QualifiedPhoneTimeZoneSuggestion(suggestion, testCase.expectedScore);
+            assertEquals(expectedScoredSuggestion,
+                    mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+            assertEquals(expectedScoredSuggestion,
+                    mTimeZoneDetectorStrategy.findBestPhoneSuggestionForTests());
+
+            // Toggling the time zone setting on should cause the device setting to be set.
+            script.autoTimeZoneDetectionEnabled(true);
+
+            // When time zone detection is already enabled the suggestion (if it scores highly
+            // enough) should be set immediately.
+            if (testCase.expectedScore >= PHONE_SCORE_USAGE_THRESHOLD) {
+                script.verifyTimeZoneSetAndReset(suggestion);
+            } else {
+                script.verifyTimeZoneNotSet();
+            }
+
+            // Assert internal service state.
+            assertEquals(expectedScoredSuggestion,
+                    mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+            assertEquals(expectedScoredSuggestion,
+                    mTimeZoneDetectorStrategy.findBestPhoneSuggestionForTests());
+
+            // Toggling the time zone setting should off should do nothing.
+            script.autoTimeZoneDetectionEnabled(false)
+                    .verifyTimeZoneNotSet();
+
+            // Assert internal service state.
+            assertEquals(expectedScoredSuggestion,
+                    mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+            assertEquals(expectedScoredSuggestion,
+                    mTimeZoneDetectorStrategy.findBestPhoneSuggestionForTests());
+        }
+    }
+
+    @Test
+    public void testPhoneSuggestionsSinglePhone() {
+        Script script = new Script()
+                .initializeAutoTimeZoneDetection(true)
+                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+
+        for (SuggestionTestCase testCase : TEST_CASES) {
+            makePhone1SuggestionAndCheckState(script, testCase);
+        }
+
+        /*
+         * This is the same test as above but the test cases are in
+         * reverse order of their expected score. New suggestions always replace previous ones:
+         * there's effectively no history and so ordering shouldn't make any difference.
+         */
+
+        // Each test case will have the same or lower score than the last.
+        ArrayList<SuggestionTestCase> descendingCasesByScore =
+                new ArrayList<>(Arrays.asList(TEST_CASES));
+        Collections.reverse(descendingCasesByScore);
+
+        for (SuggestionTestCase testCase : descendingCasesByScore) {
+            makePhone1SuggestionAndCheckState(script, testCase);
+        }
+    }
+
+    private void makePhone1SuggestionAndCheckState(Script script, SuggestionTestCase testCase) {
+        // Give the next suggestion a different zone from the currently set device time zone;
+        String currentZoneId = mFakeTimeZoneDetectorStrategyCallback.getDeviceTimeZone();
+        String suggestionZoneId =
+                "Europe/London".equals(currentZoneId) ? "Europe/Paris" : "Europe/London";
+        PhoneTimeZoneSuggestion zonePhone1Suggestion =
+                testCase.createSuggestion(PHONE1_ID, suggestionZoneId);
+        QualifiedPhoneTimeZoneSuggestion expectedZonePhone1ScoredSuggestion =
+                new QualifiedPhoneTimeZoneSuggestion(zonePhone1Suggestion, testCase.expectedScore);
+
+        script.suggestPhoneTimeZone(zonePhone1Suggestion);
+        if (testCase.expectedScore >= PHONE_SCORE_USAGE_THRESHOLD) {
+            script.verifyTimeZoneSetAndReset(zonePhone1Suggestion);
+        } else {
+            script.verifyTimeZoneNotSet();
+        }
+
+        // Assert internal service state.
+        assertEquals(expectedZonePhone1ScoredSuggestion,
+                mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+        assertEquals(expectedZonePhone1ScoredSuggestion,
+                mTimeZoneDetectorStrategy.findBestPhoneSuggestionForTests());
+    }
+
+    /**
+     * Tries a set of test cases to see if the phone with the lowest ID is given preference. This
+     * test also confirms that the time zone setting would only be set if a suggestion is of
+     * sufficient quality.
+     */
+    @Test
+    public void testMultiplePhoneSuggestionScoringAndPhoneIdBias() {
+        String[] zoneIds = { "Europe/London", "Europe/Paris" };
+        PhoneTimeZoneSuggestion emptyPhone1Suggestion = createEmptyPhone1Suggestion();
+        PhoneTimeZoneSuggestion emptyPhone2Suggestion = createEmptyPhone2Suggestion();
+        QualifiedPhoneTimeZoneSuggestion expectedEmptyPhone1ScoredSuggestion =
+                new QualifiedPhoneTimeZoneSuggestion(emptyPhone1Suggestion, PHONE_SCORE_NONE);
+        QualifiedPhoneTimeZoneSuggestion expectedEmptyPhone2ScoredSuggestion =
+                new QualifiedPhoneTimeZoneSuggestion(emptyPhone2Suggestion, PHONE_SCORE_NONE);
+
+        Script script = new Script()
+                .initializeAutoTimeZoneDetection(true)
+                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
+                // Initialize the latest suggestions as empty so we don't need to worry about nulls
+                // below for the first loop.
+                .suggestPhoneTimeZone(emptyPhone1Suggestion)
+                .suggestPhoneTimeZone(emptyPhone2Suggestion)
+                .resetState();
+
+        for (SuggestionTestCase testCase : TEST_CASES) {
+            PhoneTimeZoneSuggestion zonePhone1Suggestion =
+                    testCase.createSuggestion(PHONE1_ID, zoneIds[0]);
+            PhoneTimeZoneSuggestion zonePhone2Suggestion =
+                    testCase.createSuggestion(PHONE2_ID, zoneIds[1]);
+            QualifiedPhoneTimeZoneSuggestion expectedZonePhone1ScoredSuggestion =
+                    new QualifiedPhoneTimeZoneSuggestion(zonePhone1Suggestion,
+                            testCase.expectedScore);
+            QualifiedPhoneTimeZoneSuggestion expectedZonePhone2ScoredSuggestion =
+                    new QualifiedPhoneTimeZoneSuggestion(zonePhone2Suggestion,
+                            testCase.expectedScore);
+
+            // Start the test by making a suggestion for phone 1.
+            script.suggestPhoneTimeZone(zonePhone1Suggestion);
+            if (testCase.expectedScore >= PHONE_SCORE_USAGE_THRESHOLD) {
+                script.verifyTimeZoneSetAndReset(zonePhone1Suggestion);
+            } else {
+                script.verifyTimeZoneNotSet();
+            }
+
+            // Assert internal service state.
+            assertEquals(expectedZonePhone1ScoredSuggestion,
+                    mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+            assertEquals(expectedEmptyPhone2ScoredSuggestion,
+                    mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE2_ID));
+            assertEquals(expectedZonePhone1ScoredSuggestion,
+                    mTimeZoneDetectorStrategy.findBestPhoneSuggestionForTests());
+
+            // Phone 2 then makes an alternative suggestion with an identical score. Phone 1's
+            // suggestion should still "win" if it is above the required threshold.
+            script.suggestPhoneTimeZone(zonePhone2Suggestion);
+            script.verifyTimeZoneNotSet();
+
+            // Assert internal service state.
+            assertEquals(expectedZonePhone1ScoredSuggestion,
+                    mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+            assertEquals(expectedZonePhone2ScoredSuggestion,
+                    mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE2_ID));
+            // Phone 1 should always beat phone 2, all other things being equal.
+            assertEquals(expectedZonePhone1ScoredSuggestion,
+                    mTimeZoneDetectorStrategy.findBestPhoneSuggestionForTests());
+
+            // Withdrawing phone 1's suggestion should leave phone 2 as the new winner. Since the
+            // zoneId is different, the time zone setting should be updated if the score is high
+            // enough.
+            script.suggestPhoneTimeZone(emptyPhone1Suggestion);
+            if (testCase.expectedScore >= PHONE_SCORE_USAGE_THRESHOLD) {
+                script.verifyTimeZoneSetAndReset(zonePhone2Suggestion);
+            } else {
+                script.verifyTimeZoneNotSet();
+            }
+
+            // Assert internal service state.
+            assertEquals(expectedEmptyPhone1ScoredSuggestion,
+                    mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+            assertEquals(expectedZonePhone2ScoredSuggestion,
+                    mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE2_ID));
+            assertEquals(expectedZonePhone2ScoredSuggestion,
+                    mTimeZoneDetectorStrategy.findBestPhoneSuggestionForTests());
+
+            // Reset the state for the next loop.
+            script.suggestPhoneTimeZone(emptyPhone2Suggestion)
+                    .verifyTimeZoneNotSet();
+            assertEquals(expectedEmptyPhone1ScoredSuggestion,
+                    mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+            assertEquals(expectedEmptyPhone2ScoredSuggestion,
+                    mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE2_ID));
+        }
+    }
+
+    /**
+     * The {@link TimeZoneDetectorStrategy.Callback} is left to detect whether changing the time
+     * zone is actually necessary. This test proves that the service doesn't assume it knows the
+     * current setting.
+     */
+    @Test
+    public void testTimeZoneDetectorStrategyDoesNotAssumeCurrentSetting() {
+        Script script = new Script()
+                .initializeAutoTimeZoneDetection(true);
+
+        SuggestionTestCase testCase =
+                newTestCase(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, QUALITY_SINGLE_ZONE,
+                        PHONE_SCORE_HIGH);
+        PhoneTimeZoneSuggestion losAngelesSuggestion =
+                testCase.createSuggestion(PHONE1_ID, "America/Los_Angeles");
+        PhoneTimeZoneSuggestion newYorkSuggestion =
+                testCase.createSuggestion(PHONE1_ID, "America/New_York");
+
+        // Initialization.
+        script.suggestPhoneTimeZone(losAngelesSuggestion)
+                .verifyTimeZoneSetAndReset(losAngelesSuggestion);
+        // Suggest it again - it should not be set because it is already set.
+        script.suggestPhoneTimeZone(losAngelesSuggestion)
+                .verifyTimeZoneNotSet();
+
+        // Toggling time zone detection should set the device time zone only if the current setting
+        // value is different from the most recent phone suggestion.
+        script.autoTimeZoneDetectionEnabled(false)
+                .verifyTimeZoneNotSet()
+                .autoTimeZoneDetectionEnabled(true)
+                .verifyTimeZoneNotSet();
+
+        // Simulate a user turning auto detection off, a new suggestion being made while auto
+        // detection is off, and the user turning it on again.
+        script.autoTimeZoneDetectionEnabled(false)
+                .suggestPhoneTimeZone(newYorkSuggestion)
+                .verifyTimeZoneNotSet();
+        // Latest suggestion should be used.
+        script.autoTimeZoneDetectionEnabled(true)
+                .verifyTimeZoneSetAndReset(newYorkSuggestion);
+    }
+
+    @Test
+    public void testManualSuggestion_autoTimeZoneDetectionEnabled() {
+        Script script = new Script()
+                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
+                .initializeAutoTimeZoneDetection(true);
+
+        // Auto time zone detection is enabled so the manual suggestion should be ignored.
+        script.suggestManualTimeZone(createManualSuggestion("Europe/Paris"))
+            .verifyTimeZoneNotSet();
+    }
+
+
+    @Test
+    public void testManualSuggestion_autoTimeZoneDetectionDisabled() {
+        Script script = new Script()
+                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
+                .initializeAutoTimeZoneDetection(false);
+
+        // Auto time zone detection is disabled so the manual suggestion should be used.
+        ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Europe/Paris");
+        script.suggestManualTimeZone(manualSuggestion)
+            .verifyTimeZoneSetAndReset(manualSuggestion);
+    }
+
+    private ManualTimeZoneSuggestion createManualSuggestion(String zoneId) {
+        return new ManualTimeZoneSuggestion(zoneId);
+    }
+
+    private static PhoneTimeZoneSuggestion createEmptyPhone1Suggestion() {
+        return new PhoneTimeZoneSuggestion.Builder(PHONE1_ID).build();
+    }
+
+    private static PhoneTimeZoneSuggestion createEmptyPhone2Suggestion() {
+        return new PhoneTimeZoneSuggestion.Builder(PHONE2_ID).build();
+    }
+
+    static class FakeTimeZoneDetectorStrategyCallback implements TimeZoneDetectorStrategy.Callback {
+
+        private boolean mAutoTimeZoneDetectionEnabled;
+        private TestState<String> mTimeZoneId = new TestState<>();
+
+        @Override
+        public boolean isAutoTimeZoneDetectionEnabled() {
+            return mAutoTimeZoneDetectionEnabled;
+        }
+
+        @Override
+        public boolean isDeviceTimeZoneInitialized() {
+            return mTimeZoneId != null;
+        }
+
+        @Override
+        public String getDeviceTimeZone() {
+            return mTimeZoneId.getLatest();
+        }
+
+        @Override
+        public void setDeviceTimeZone(String zoneId) {
+            mTimeZoneId.set(zoneId);
+        }
+
+        void initializeAutoTimeZoneDetection(boolean enabled) {
+            mAutoTimeZoneDetectionEnabled = enabled;
+        }
+
+        void initializeTimeZone(String zoneId) {
+            mTimeZoneId.init(zoneId);
+        }
+
+        void setAutoTimeZoneDetectionEnabled(boolean enabled) {
+            mAutoTimeZoneDetectionEnabled = enabled;
+        }
+
+        void assertTimeZoneNotSet() {
+            mTimeZoneId.assertHasNotBeenSet();
+        }
+
+        void assertTimeZoneSet(String timeZoneId) {
+            mTimeZoneId.assertHasBeenSet();
+            mTimeZoneId.assertChangeCount(1);
+            mTimeZoneId.assertLatestEquals(timeZoneId);
+        }
+
+        void commitAllChanges() {
+            mTimeZoneId.commitLatest();
+        }
+    }
+
+    /** Some piece of state that tests want to track. */
+    private static class TestState<T> {
+        private T mInitialValue;
+        private LinkedList<T> mValues = new LinkedList<>();
+
+        void init(T value) {
+            mValues.clear();
+            mInitialValue = value;
+        }
+
+        void set(T value) {
+            mValues.addFirst(value);
+        }
+
+        boolean hasBeenSet() {
+            return mValues.size() > 0;
+        }
+
+        void assertHasNotBeenSet() {
+            assertFalse(hasBeenSet());
+        }
+
+        void assertHasBeenSet() {
+            assertTrue(hasBeenSet());
+        }
+
+        void commitLatest() {
+            if (hasBeenSet()) {
+                mInitialValue = mValues.getLast();
+                mValues.clear();
+            }
+        }
+
+        void assertLatestEquals(T expected) {
+            assertEquals(expected, getLatest());
+        }
+
+        void assertChangeCount(int expectedCount) {
+            assertEquals(expectedCount, mValues.size());
+        }
+
+        public T getLatest() {
+            if (hasBeenSet()) {
+                return mValues.getFirst();
+            }
+            return mInitialValue;
+        }
+    }
+
+    /**
+     * A "fluent" class allows reuse of code in tests: initialization, simulation and verification
+     * logic.
+     */
+    private class Script {
+
+        Script initializeAutoTimeZoneDetection(boolean enabled) {
+            mFakeTimeZoneDetectorStrategyCallback.initializeAutoTimeZoneDetection(enabled);
+            return this;
+        }
+
+        Script initializeTimeZoneSetting(String zoneId) {
+            mFakeTimeZoneDetectorStrategyCallback.initializeTimeZone(zoneId);
+            return this;
+        }
+
+        Script autoTimeZoneDetectionEnabled(boolean enabled) {
+            mFakeTimeZoneDetectorStrategyCallback.setAutoTimeZoneDetectionEnabled(enabled);
+            mTimeZoneDetectorStrategy.handleAutoTimeZoneDetectionChange();
+            return this;
+        }
+
+        /** Simulates the time zone detection strategy receiving a phone-originated suggestion. */
+        Script suggestPhoneTimeZone(PhoneTimeZoneSuggestion phoneTimeZoneSuggestion) {
+            mTimeZoneDetectorStrategy.suggestPhoneTimeZone(phoneTimeZoneSuggestion);
+            return this;
+        }
+
+        /** Simulates the time zone detection strategy receiving a user-originated suggestion. */
+        Script suggestManualTimeZone(ManualTimeZoneSuggestion manualTimeZoneSuggestion) {
+            mTimeZoneDetectorStrategy.suggestManualTimeZone(manualTimeZoneSuggestion);
+            return this;
+        }
+
+        Script verifyTimeZoneNotSet() {
+            mFakeTimeZoneDetectorStrategyCallback.assertTimeZoneNotSet();
+            return this;
+        }
+
+        Script verifyTimeZoneSetAndReset(PhoneTimeZoneSuggestion suggestion) {
+            mFakeTimeZoneDetectorStrategyCallback.assertTimeZoneSet(suggestion.getZoneId());
+            mFakeTimeZoneDetectorStrategyCallback.commitAllChanges();
+            return this;
+        }
+
+        Script verifyTimeZoneSetAndReset(ManualTimeZoneSuggestion suggestion) {
+            mFakeTimeZoneDetectorStrategyCallback.assertTimeZoneSet(suggestion.getZoneId());
+            mFakeTimeZoneDetectorStrategyCallback.commitAllChanges();
+            return this;
+        }
+
+        Script resetState() {
+            mFakeTimeZoneDetectorStrategyCallback.commitAllChanges();
+            return this;
+        }
+    }
+
+    private static class SuggestionTestCase {
+        public final int matchType;
+        public final int quality;
+        public final int expectedScore;
+
+        SuggestionTestCase(int matchType, int quality, int expectedScore) {
+            this.matchType = matchType;
+            this.quality = quality;
+            this.expectedScore = expectedScore;
+        }
+
+        private PhoneTimeZoneSuggestion createSuggestion(int phoneId, String zoneId) {
+            return new PhoneTimeZoneSuggestion.Builder(phoneId)
+                    .setZoneId(zoneId)
+                    .setMatchType(matchType)
+                    .setQuality(quality)
+                    .build();
+        }
+    }
+
+    private static SuggestionTestCase newTestCase(
+            @MatchType int matchType, @Quality int quality, int expectedScore) {
+        return new SuggestionTestCase(matchType, quality, expectedScore);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
index e32103f..e6bb244 100644
--- a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
+++ b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
@@ -45,6 +45,7 @@
 import java.io.IOException;
 import java.util.List;
 import java.util.Locale;
+import java.util.Set;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
@@ -93,6 +94,8 @@
                 for (File f : usageFiles) {
                     f.delete();
                 }
+            } else {
+                intervalDir.delete();
             }
         }
     }
@@ -587,6 +590,7 @@
         db.readMappingsLocked();
         db.init(1);
         db.putUsageStats(interval, mIntervalStats);
+        db.writeMappingsLocked();
 
         final String removedPackage = "fake.package.name0";
         // invoke handler call directly from test to remove package
@@ -594,19 +598,19 @@
 
         List<IntervalStats> stats = db.queryUsageStats(interval, 0, mEndTime,
                 mIntervalStatsVerifier);
-        for (int i = 0; i < stats.size(); i++) {
-            final IntervalStats stat = stats.get(i);
-            if (stat.packageStats.containsKey(removedPackage)) {
-                fail("Found removed package " + removedPackage + " in package stats.");
+        assertEquals(1, stats.size(),
+                "Only one interval stats object should exist for the given time range.");
+        final IntervalStats stat = stats.get(0);
+        if (stat.packageStats.containsKey(removedPackage)) {
+            fail("Found removed package " + removedPackage + " in package stats.");
+            return;
+        }
+        for (int i = 0; i < stat.events.size(); i++) {
+            final Event event = stat.events.get(i);
+            if (removedPackage.equals(event.mPackage)) {
+                fail("Found an event from removed package " + removedPackage);
                 return;
             }
-            for (int j = 0; j < stat.events.size(); j++) {
-                final Event event = stat.events.get(j);
-                if (removedPackage.equals(event.mPackage)) {
-                    fail("Found an event from removed package " + removedPackage);
-                    return;
-                }
-            }
         }
     }
 
@@ -617,4 +621,90 @@
         verifyPackageNotRetained(UsageStatsManager.INTERVAL_MONTHLY);
         verifyPackageNotRetained(UsageStatsManager.INTERVAL_YEARLY);
     }
+
+    private void verifyPackageDataIsRemoved(UsageStatsDatabase db, int interval,
+            String removedPackage) {
+        List<IntervalStats> stats = db.queryUsageStats(interval, 0, mEndTime,
+                mIntervalStatsVerifier);
+        assertEquals(1, stats.size(),
+                "Only one interval stats object should exist for the given time range.");
+        final IntervalStats stat = stats.get(0);
+        if (stat.packageStats.containsKey(removedPackage)) {
+            fail("Found removed package " + removedPackage + " in package stats.");
+            return;
+        }
+        for (int i = 0; i < stat.events.size(); i++) {
+            final Event event = stat.events.get(i);
+            if (removedPackage.equals(event.mPackage)) {
+                fail("Found an event from removed package " + removedPackage);
+                return;
+            }
+        }
+    }
+
+    private void verifyPackageDataIsNotRemoved(UsageStatsDatabase db, int interval,
+            Set<String> installedPackages) {
+        List<IntervalStats> stats = db.queryUsageStats(interval, 0, mEndTime,
+                mIntervalStatsVerifier);
+        assertEquals(1, stats.size(),
+                "Only one interval stats object should exist for the given time range.");
+        final IntervalStats stat = stats.get(0);
+        if (!stat.packageStats.containsAll(installedPackages)) {
+            fail("Could not find some installed packages in package stats.");
+            return;
+        }
+        // attempt to find an event from each installed package
+        for (String installedPackage : installedPackages) {
+            for (int i = 0; i < stat.events.size(); i++) {
+                if (installedPackage.equals(stat.events.get(i).mPackage)) {
+                    break;
+                }
+                if (i == stat.events.size() - 1) {
+                    fail("Could not find any event for: " + installedPackage);
+                    return;
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testPackageDataIsRemoved() throws IOException {
+        UsageStatsDatabase db = new UsageStatsDatabase(mTestDir);
+        db.readMappingsLocked();
+        db.init(1);
+
+        // write stats to disk for each interval
+        db.putUsageStats(UsageStatsManager.INTERVAL_DAILY, mIntervalStats);
+        db.putUsageStats(UsageStatsManager.INTERVAL_WEEKLY, mIntervalStats);
+        db.putUsageStats(UsageStatsManager.INTERVAL_MONTHLY, mIntervalStats);
+        db.putUsageStats(UsageStatsManager.INTERVAL_YEARLY, mIntervalStats);
+        db.writeMappingsLocked();
+
+        final Set<String> installedPackages = mIntervalStats.packageStats.keySet();
+        final String removedPackage = installedPackages.iterator().next();
+        installedPackages.remove(removedPackage);
+
+        // mimic a package uninstall
+        db.onPackageRemoved(removedPackage, System.currentTimeMillis());
+
+        // mimic the idle prune job being triggered
+        db.pruneUninstalledPackagesData();
+
+        // read data from disk into a new db instance
+        UsageStatsDatabase newDB = new UsageStatsDatabase(mTestDir);
+        newDB.readMappingsLocked();
+        newDB.init(mEndTime);
+
+        // query data for each interval and ensure data for package doesn't exist
+        verifyPackageDataIsRemoved(newDB, UsageStatsManager.INTERVAL_DAILY, removedPackage);
+        verifyPackageDataIsRemoved(newDB, UsageStatsManager.INTERVAL_WEEKLY, removedPackage);
+        verifyPackageDataIsRemoved(newDB, UsageStatsManager.INTERVAL_MONTHLY, removedPackage);
+        verifyPackageDataIsRemoved(newDB, UsageStatsManager.INTERVAL_YEARLY, removedPackage);
+
+        // query data for each interval and ensure some data for installed packages exists
+        verifyPackageDataIsNotRemoved(newDB, UsageStatsManager.INTERVAL_DAILY, installedPackages);
+        verifyPackageDataIsNotRemoved(newDB, UsageStatsManager.INTERVAL_WEEKLY, installedPackages);
+        verifyPackageDataIsNotRemoved(newDB, UsageStatsManager.INTERVAL_MONTHLY, installedPackages);
+        verifyPackageDataIsNotRemoved(newDB, UsageStatsManager.INTERVAL_YEARLY, installedPackages);
+    }
 }
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml b/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml
index 909e9bb..201cd05 100644
--- a/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml
+++ b/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml
@@ -18,8 +18,7 @@
         package="com.android.servicestests.apps.conntestapp">
 
     <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
-    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+    <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" />
 
     <application>
         <activity android:name=".ConnTestActivity"
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index 92198fa..f608bab 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -20,6 +20,7 @@
         "androidx.test.rules", "hamcrest-library",
         "mockito-target-inline-minus-junit4",
         "platform-test-annotations",
+        "platformprotosnano",
         "hamcrest-library",
         "testables",
         "truth-prebuilt",
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
index a00afec..9ad6986 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.AlarmManager;
+import android.app.NotificationHistory;
 import android.app.NotificationHistory.HistoricalNotification;
 import android.content.Context;
 import android.graphics.drawable.Icon;
@@ -199,6 +200,16 @@
     }
 
     @Test
+    public void testReadNotificationHistory_readsBuffer() throws Exception {
+        HistoricalNotification hn = getHistoricalNotification(1);
+        mDataBase.addNotification(hn);
+
+        NotificationHistory nh = mDataBase.readNotificationHistory();
+
+        assertThat(nh.getNotificationsToWrite()).contains(hn);
+    }
+
+    @Test
     public void testReadNotificationHistory_withNumFilterDoesNotReadExtraFiles() throws Exception {
         AtomicFile af = mock(AtomicFile.class);
         when(af.getBaseFile()).thenReturn(new File(mRootDir, "af"));
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java
index aa3c465..92c0546 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java
@@ -15,11 +15,12 @@
  */
 package com.android.server.notification;
 
-import static android.os.UserHandle.USER_ALL;
+import static android.os.UserHandle.MIN_SECONDARY_USER_ID;
 import static android.os.UserHandle.USER_SYSTEM;
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
@@ -28,9 +29,11 @@
 
 import android.app.NotificationHistory;
 import android.app.NotificationHistory.HistoricalNotification;
-import android.content.Context;
+import android.content.pm.UserInfo;
 import android.graphics.drawable.Icon;
+import android.os.Handler;
 import android.os.UserManager;
+import android.provider.Settings;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
@@ -44,23 +47,22 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
+import java.util.List;
+
 
 @RunWith(AndroidJUnit4.class)
 public class NotificationHistoryManagerTest extends UiServiceTestCase {
 
     @Mock
-    Context mContext;
-    @Mock
     UserManager mUserManager;
     @Mock
     NotificationHistoryDatabase mDb;
+    @Mock
+    Handler mHandler;
+    List<UserInfo> mUsers;
 
     NotificationHistoryManager mHistoryManager;
 
-    private HistoricalNotification getHistoricalNotification(int index) {
-        return getHistoricalNotification("package" + index, index);
-    }
-
     private HistoricalNotification getHistoricalNotification(String packageName, int index) {
         String expectedChannelName = "channelName" + index;
         String expectedChannelId = "channelId" + index;
@@ -88,13 +90,28 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
-        when(mContext.getUser()).thenReturn(getContext().getUser());
-        when(mContext.getPackageName()).thenReturn(getContext().getPackageName());
+
+        getContext().addMockSystemService(UserManager.class, mUserManager);
+
+        mUsers = new ArrayList<>();
+        UserInfo userSystem = new UserInfo();
+        userSystem.id = USER_SYSTEM;
+        mUsers.add(userSystem);
+        UserInfo userAll = new UserInfo();
+        userAll.id = MIN_SECONDARY_USER_ID;
+        mUsers.add(userAll);
+        mUsers.add(userAll);
+        when(mUserManager.getUsers()).thenReturn(mUsers);
+
+        for (UserInfo info : mUsers) {
+            Settings.Secure.putIntForUser(getContext().getContentResolver(),
+                    Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 1, info.id);
+        }
 
         NotificationHistoryDatabaseFactory.setTestingNotificationHistoryDatabase(mDb);
 
-        mHistoryManager = new NotificationHistoryManager(mContext);
+        mHistoryManager = new NotificationHistoryManager(getContext(), mHandler);
+        mHistoryManager.onBootPhaseAppsCanStart();
     }
 
     @Test
@@ -107,6 +124,20 @@
         verify(mDb, times(1)).init();
     }
 
+    public void testOnUserUnlocked_historyDisabled() {
+        Settings.Secure.putIntForUser(getContext().getContentResolver(),
+                Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, USER_SYSTEM);
+        mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
+        assertThat(mHistoryManager.doesHistoryExistForUser(USER_SYSTEM)).isFalse();
+        assertThat(mHistoryManager.isUserUnlocked(USER_SYSTEM)).isFalse();
+
+        mHistoryManager.onUserUnlocked(USER_SYSTEM);
+
+        assertThat(mHistoryManager.doesHistoryExistForUser(USER_SYSTEM)).isFalse();
+        assertThat(mHistoryManager.isUserUnlocked(USER_SYSTEM)).isFalse();
+        verify(mDb, times(1)).disableHistory();
+    }
+
     @Test
     public void testOnUserUnlocked_cleansUpRemovedPackages() {
         String pkg = "pkg";
@@ -144,6 +175,7 @@
 
         assertThat(mHistoryManager.doesHistoryExistForUser(USER_SYSTEM)).isFalse();
         assertThat(mHistoryManager.isUserUnlocked(USER_SYSTEM)).isFalse();
+        assertThat(mHistoryManager.isHistoryEnabled(USER_SYSTEM)).isFalse();
     }
 
     @Test
@@ -187,6 +219,18 @@
     }
 
     @Test
+    public void testOnPackageRemoved_historyDisabled() {
+        Settings.Secure.putIntForUser(getContext().getContentResolver(),
+                Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, USER_SYSTEM);
+        mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
+        String pkg = "pkg";
+        mHistoryManager.onPackageRemoved(USER_SYSTEM, pkg);
+
+        assertThat(mHistoryManager.getPendingPackageRemovalsForUser(USER_SYSTEM))
+                .isNull();
+    }
+
+    @Test
     public void testOnPackageRemoved_multiUser() {
         String pkg = "pkg";
         NotificationHistoryDatabase userHistorySystem = mock(NotificationHistoryDatabase.class);
@@ -195,8 +239,8 @@
         mHistoryManager.onUserUnlocked(USER_SYSTEM);
         mHistoryManager.replaceNotificationHistoryDatabase(USER_SYSTEM, userHistorySystem);
 
-        mHistoryManager.onUserUnlocked(USER_ALL);
-        mHistoryManager.replaceNotificationHistoryDatabase(USER_ALL, userHistoryAll);
+        mHistoryManager.onUserUnlocked(MIN_SECONDARY_USER_ID);
+        mHistoryManager.replaceNotificationHistoryDatabase(MIN_SECONDARY_USER_ID, userHistoryAll);
 
         mHistoryManager.onPackageRemoved(USER_SYSTEM, pkg);
 
@@ -212,8 +256,8 @@
         mHistoryManager.onUserUnlocked(USER_SYSTEM);
         mHistoryManager.replaceNotificationHistoryDatabase(USER_SYSTEM, userHistorySystem);
 
-        mHistoryManager.onUserUnlocked(USER_ALL);
-        mHistoryManager.replaceNotificationHistoryDatabase(USER_ALL, userHistoryAll);
+        mHistoryManager.onUserUnlocked(MIN_SECONDARY_USER_ID);
+        mHistoryManager.replaceNotificationHistoryDatabase(MIN_SECONDARY_USER_ID, userHistoryAll);
 
         mHistoryManager.triggerWriteToDisk();
 
@@ -229,9 +273,9 @@
         mHistoryManager.onUserUnlocked(USER_SYSTEM);
         mHistoryManager.replaceNotificationHistoryDatabase(USER_SYSTEM, userHistorySystem);
 
-        mHistoryManager.onUserUnlocked(USER_ALL);
-        mHistoryManager.replaceNotificationHistoryDatabase(USER_ALL, userHistoryAll);
-        mHistoryManager.onUserStopped(USER_ALL);
+        mHistoryManager.onUserUnlocked(MIN_SECONDARY_USER_ID);
+        mHistoryManager.replaceNotificationHistoryDatabase(MIN_SECONDARY_USER_ID, userHistoryAll);
+        mHistoryManager.onUserStopped(MIN_SECONDARY_USER_ID);
 
         mHistoryManager.triggerWriteToDisk();
 
@@ -240,6 +284,21 @@
     }
 
     @Test
+    public void testTriggerWriteToDisk_historyDisabled() {
+        Settings.Secure.putIntForUser(getContext().getContentResolver(),
+                Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, USER_SYSTEM);
+        mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
+        NotificationHistoryDatabase userHistorySystem = mock(NotificationHistoryDatabase.class);
+
+        mHistoryManager.onUserUnlocked(USER_SYSTEM);
+        mHistoryManager.replaceNotificationHistoryDatabase(USER_SYSTEM, userHistorySystem);
+
+        mHistoryManager.triggerWriteToDisk();
+
+        verify(userHistorySystem, never()).forceWriteToDisk();
+    }
+
+    @Test
     public void testAddNotification_userLocked_noCrash() {
         HistoricalNotification hn = getHistoricalNotification("pkg", 1);
 
@@ -247,9 +306,23 @@
     }
 
     @Test
+    public void testAddNotification_historyDisabled() {
+        HistoricalNotification hn = getHistoricalNotification("pkg", 1);
+
+        Settings.Secure.putIntForUser(getContext().getContentResolver(),
+                Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, hn.getUserId());
+        mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
+
+        mHistoryManager.onUserUnlocked(hn.getUserId());
+        mHistoryManager.addNotification(hn);
+
+        verify(mDb, never()).addNotification(any());
+    }
+
+    @Test
     public void testAddNotification() {
         HistoricalNotification hnSystem = getHistoricalNotification("pkg", USER_SYSTEM);
-        HistoricalNotification hnAll = getHistoricalNotification("pkg", USER_ALL);
+        HistoricalNotification hnAll = getHistoricalNotification("pkg", MIN_SECONDARY_USER_ID);
 
         NotificationHistoryDatabase userHistorySystem = mock(NotificationHistoryDatabase.class);
         NotificationHistoryDatabase userHistoryAll = mock(NotificationHistoryDatabase.class);
@@ -257,8 +330,8 @@
         mHistoryManager.onUserUnlocked(USER_SYSTEM);
         mHistoryManager.replaceNotificationHistoryDatabase(USER_SYSTEM, userHistorySystem);
 
-        mHistoryManager.onUserUnlocked(USER_ALL);
-        mHistoryManager.replaceNotificationHistoryDatabase(USER_ALL, userHistoryAll);
+        mHistoryManager.onUserUnlocked(MIN_SECONDARY_USER_ID);
+        mHistoryManager.replaceNotificationHistoryDatabase(MIN_SECONDARY_USER_ID, userHistoryAll);
 
         mHistoryManager.addNotification(hnSystem);
         mHistoryManager.addNotification(hnAll);
@@ -270,7 +343,7 @@
     @Test
     public void testReadNotificationHistory() {
         HistoricalNotification hnSystem = getHistoricalNotification("pkg", USER_SYSTEM);
-        HistoricalNotification hnAll = getHistoricalNotification("pkg", USER_ALL);
+        HistoricalNotification hnAll = getHistoricalNotification("pkg", MIN_SECONDARY_USER_ID);
 
         NotificationHistoryDatabase userHistorySystem = mock(NotificationHistoryDatabase.class);
         NotificationHistoryDatabase userHistoryAll = mock(NotificationHistoryDatabase.class);
@@ -283,8 +356,8 @@
         when(nhSystem.getNotificationsToWrite()).thenReturn(nhSystemList);
         when(userHistorySystem.readNotificationHistory()).thenReturn(nhSystem);
 
-        mHistoryManager.onUserUnlocked(USER_ALL);
-        mHistoryManager.replaceNotificationHistoryDatabase(USER_ALL, userHistoryAll);
+        mHistoryManager.onUserUnlocked(MIN_SECONDARY_USER_ID);
+        mHistoryManager.replaceNotificationHistoryDatabase(MIN_SECONDARY_USER_ID, userHistoryAll);
         NotificationHistory nhAll = mock(NotificationHistory.class);
         ArrayList<HistoricalNotification> nhAllList = new ArrayList<>();
         nhAllList.add(hnAll);
@@ -293,13 +366,47 @@
 
         // ensure read history returns both historical notifs
         NotificationHistory nh = mHistoryManager.readNotificationHistory(
-                new int[] {USER_SYSTEM, USER_ALL});
+                new int[] {USER_SYSTEM, MIN_SECONDARY_USER_ID});
         assertThat(nh.getNotificationsToWrite()).contains(hnSystem);
         assertThat(nh.getNotificationsToWrite()).contains(hnAll);
     }
 
     @Test
-    public void readFilteredNotificationHistory_userUnlocked() {
+    public void testReadNotificationHistory_historyDisabled() {
+        HistoricalNotification hnSystem = getHistoricalNotification("pkg", USER_SYSTEM);
+
+        mHistoryManager.onUserUnlocked(USER_SYSTEM);
+        NotificationHistory nhSystem = mock(NotificationHistory.class);
+        ArrayList<HistoricalNotification> nhSystemList = new ArrayList<>();
+        nhSystemList.add(hnSystem);
+        when(nhSystem.getNotificationsToWrite()).thenReturn(nhSystemList);
+        when(mDb.readNotificationHistory()).thenReturn(nhSystem);
+
+        mHistoryManager.onUserUnlocked(USER_SYSTEM);
+
+        Settings.Secure.putIntForUser(getContext().getContentResolver(),
+                Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0,  USER_SYSTEM);
+        mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
+
+        NotificationHistory nh =
+                mHistoryManager.readNotificationHistory(new int[] {USER_SYSTEM,});
+        assertThat(nh.getNotificationsToWrite()).isEmpty();
+    }
+
+    @Test
+    public void testReadFilteredNotificationHistory_userLocked() {
+        NotificationHistory nh =
+                mHistoryManager.readFilteredNotificationHistory(USER_SYSTEM, "", "", 1000);
+        assertThat(nh.getNotificationsToWrite()).isEmpty();
+    }
+
+    @Test
+    public void testReadFilteredNotificationHistory_historyDisabled() {
+        Settings.Secure.putIntForUser(getContext().getContentResolver(),
+                Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0,  USER_SYSTEM);
+        mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
+
+        mHistoryManager.onUserUnlocked(USER_SYSTEM);
         NotificationHistory nh =
                 mHistoryManager.readFilteredNotificationHistory(USER_SYSTEM, "", "", 1000);
         assertThat(nh.getNotificationsToWrite()).isEmpty();
@@ -312,4 +419,15 @@
         mHistoryManager.readFilteredNotificationHistory(USER_SYSTEM, "pkg", "chn", 1000);
         verify(mDb, times(1)).readNotificationHistory("pkg", "chn", 1000);
     }
+
+    @Test
+    public void testIsHistoryEnabled() {
+        assertThat(mHistoryManager.isHistoryEnabled(USER_SYSTEM)).isTrue();
+
+        Settings.Secure.putIntForUser(getContext().getContentResolver(),
+                Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0,  USER_SYSTEM);
+        mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
+
+        assertThat(mHistoryManager.isHistoryEnabled(USER_SYSTEM)).isFalse();
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 21de668..876e77a 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -218,6 +218,8 @@
     @Mock
     RankingHandler mRankingHandler;
 
+    private static final int MAX_POST_DELAY = 1000;
+
     private NotificationChannel mTestNotificationChannel = new NotificationChannel(
             TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
 
@@ -246,6 +248,8 @@
             mNotificationAssistantAccessGrantedCallback;
     @Mock
     UserManager mUm;
+    @Mock
+    NotificationHistoryManager mHistoryManager;
 
     // Use a Testable subclass so we can simulate calls from the system without failing.
     private static class TestableNotificationManagerService extends NotificationManagerService {
@@ -404,13 +408,13 @@
 
         when(mAssistants.isAdjustmentAllowed(anyString())).thenReturn(true);
 
-        mService.init(mTestableLooper.getLooper(), mRankingHandler,
-                mPackageManager, mPackageManagerClient, mockLightsManager,
+        mService.init(mService.new WorkerHandler(mTestableLooper.getLooper()),
+                mRankingHandler, mPackageManager, mPackageManagerClient, mockLightsManager,
                 mListeners, mAssistants, mConditionProviders,
                 mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager,
                 mGroupHelper, mAm, mAppUsageStats,
                 mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal,
-                mAppOpsManager, mUm);
+                mAppOpsManager, mUm, mHistoryManager);
         mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
 
         mService.setAudioManager(mAudioManager);
@@ -430,6 +434,7 @@
     public void tearDown() throws Exception {
         if (mFile != null) mFile.delete();
         clearDeviceConfig();
+        mService.unregisterDeviceConfigChange();
         InstrumentationRegistry.getInstrumentation()
                 .getUiAutomation().dropShellPermissionIdentity();
     }
@@ -5947,4 +5952,61 @@
     }
 
     // TODO: add tests for the rest of the non-empty cases
+
+    @Test
+    public void testOnUnlockUser() {
+        UserInfo ui = new UserInfo();
+        ui.id = 10;
+        mService.onUnlockUser(ui);
+        waitForIdle();
+
+        verify(mHistoryManager, timeout(MAX_POST_DELAY).times(1)).onUserUnlocked(ui.id);
+    }
+
+    @Test
+    public void testOnStopUser() {
+        UserInfo ui = new UserInfo();
+        ui.id = 10;
+        mService.onStopUser(ui);
+        waitForIdle();
+
+        verify(mHistoryManager, timeout(MAX_POST_DELAY).times(1)).onUserStopped(ui.id);
+    }
+
+    @Test
+    public void testOnBootPhase() {
+        mService.onBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY);
+
+        verify(mHistoryManager, never()).onBootPhaseAppsCanStart();
+
+        mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
+
+        verify(mHistoryManager, times(1)).onBootPhaseAppsCanStart();
+    }
+
+    @Test
+    public void testHandleOnPackageChanged() {
+        String[] pkgs = new String[] {PKG, PKG_N_MR1};
+        int[] uids = new int[] {mUid, UserHandle.PER_USER_RANGE + 1};
+
+        mService.handleOnPackageChanged(false, USER_SYSTEM, pkgs, uids);
+
+        verify(mHistoryManager, never()).onPackageRemoved(anyInt(), anyString());
+
+        mService.handleOnPackageChanged(true, USER_SYSTEM, pkgs, uids);
+
+        verify(mHistoryManager, times(1)).onPackageRemoved(UserHandle.getUserId(uids[0]), pkgs[0]);
+        verify(mHistoryManager, times(1)).onPackageRemoved(UserHandle.getUserId(uids[1]), pkgs[1]);
+    }
+
+    @Test
+    public void testNotificationHistory_addNoisyNotification() throws Exception {
+        NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
+                null /* tvExtender */, false);
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.sbn.getTag(),
+                nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId());
+        waitForIdle();
+
+        verify(mHistoryManager, times(1)).addNotification(any());
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PulledStatsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PulledStatsTest.java
new file mode 100644
index 0000000..f685c68
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PulledStatsTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.notification;
+
+import static com.android.server.notification.NotificationManagerService.REPORT_REMOTE_VIEWS;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotSame;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.service.notification.nano.NotificationRemoteViewsProto;
+import android.test.MoreAsserts;
+import android.util.proto.ProtoOutputStream;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.server.UiServiceTestCase;
+
+import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
+
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+@SmallTest
+public class PulledStatsTest extends UiServiceTestCase {
+
+    @Test
+    public void testPulledStats_Empty() {
+        PulledStats stats = new PulledStats(0L);
+        assertEquals(0L, stats.endTimeMs());
+    }
+
+    @Test
+    public void testPulledStats_UnknownReport() {
+        PulledStats stats = new PulledStats(0L);
+        stats.addUndecoratedPackage("foo", 456);
+        stats.addUndecoratedPackage("bar", 123);
+
+        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+        final ProtoOutputStream proto = new ProtoOutputStream(bytes);
+        stats.writeToProto(1023123, proto); // a very large number
+        proto.flush();
+
+        // expect empty output in response to an unrecognized request
+        assertEquals(0L, bytes.size());
+    }
+
+    @Test
+    public void testPulledStats_RemoteViewReportPackages() {
+        List<String> expectedPkgs = new ArrayList<>(2);
+        expectedPkgs.add("foo");
+        expectedPkgs.add("bar");
+
+        PulledStats stats = new PulledStats(0L);
+        for(String pkg: expectedPkgs) {
+            stats.addUndecoratedPackage(pkg, 111);
+        }
+
+        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+        final ProtoOutputStream protoStream = new ProtoOutputStream(bytes);
+        stats.writeToProto(REPORT_REMOTE_VIEWS, protoStream);
+        protoStream.flush();
+
+        try {
+            NotificationRemoteViewsProto proto =
+                    NotificationRemoteViewsProto.parseFrom(bytes.toByteArray());
+            List<String> actualPkgs = new ArrayList<>(2);
+            for(int i = 0 ; i < proto.packageRemoteViewInfo.length; i++) {
+                actualPkgs.add(proto.packageRemoteViewInfo[i].packageName);
+            }
+            assertEquals(2, actualPkgs.size());
+            assertTrue("missing packages", actualPkgs.containsAll(expectedPkgs));
+            assertTrue("unexpected packages", expectedPkgs.containsAll(actualPkgs));
+        } catch (InvalidProtocolBufferNanoException e) {
+            e.printStackTrace();
+            fail("writeToProto generated unparsable output");
+        }
+
+    }
+    @Test
+    public void testPulledStats_RemoteViewReportEndTime() {
+        List<String> expectedPkgs = new ArrayList<>(2);
+        expectedPkgs.add("foo");
+        expectedPkgs.add("bar");
+
+        PulledStats stats = new PulledStats(0L);
+        long t = 111;
+        for(String pkg: expectedPkgs) {
+            t += 1000;
+            stats.addUndecoratedPackage(pkg, t);
+        }
+        assertEquals(t, stats.endTimeMs());
+    }
+
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
index 7f9f489..c828f02 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
@@ -129,7 +129,8 @@
         mRoleObserver = mService.new RoleObserver(mRoleManager, mPm, mExecutor);
 
         try {
-            mService.init(mock(Looper.class), mock(RankingHandler.class),
+            mService.init(mService.new WorkerHandler(mock(Looper.class)),
+                    mock(RankingHandler.class),
                     mock(IPackageManager.class), mock(PackageManager.class),
                     mock(LightsManager.class),
                     mock(NotificationListeners.class), mock(NotificationAssistants.class),
@@ -140,7 +141,7 @@
                     mock(UsageStatsManagerInternal.class),
                     mock(DevicePolicyManagerInternal.class), mock(IUriGrantsManager.class),
                     mock(UriGrantsManagerInternal.class),
-                    mock(AppOpsManager.class), mUm);
+                    mock(AppOpsManager.class), mUm, mock(NotificationHistoryManager.class));
         } catch (SecurityException e) {
             if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
                 throw e;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
index 36175a9..5841e59 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -350,6 +350,26 @@
     }
 
     @Test
+    public void testUpdateAfterCancel() throws Exception {
+        // snooze a notification
+        NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+        mSnoozeHelper.snooze(r , 1000);
+
+        // cancel the notification
+        mSnoozeHelper.cancel(UserHandle.USER_SYSTEM, false);
+
+        // update the notification
+        r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+        mSnoozeHelper.update(UserHandle.USER_SYSTEM, r);
+
+        // verify callback is called when repost (snooze is expired)
+        verify(mCallback, never()).repost(anyInt(), any(NotificationRecord.class));
+        mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM);
+        verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r);
+        assertFalse(r.isCanceled);
+    }
+
+    @Test
     public void testGetSnoozedByUser() throws Exception {
         NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
         NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM);
diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp
index cdba9a1..cd4f0da 100644
--- a/services/tests/wmtests/Android.bp
+++ b/services/tests/wmtests/Android.bp
@@ -13,7 +13,7 @@
     ],
 
     static_libs: [
-        "frameworks-base-testutils",
+        "frameworks-base-testutils-minus-mockito",
         "services.core",
         "androidx.test.runner",
         "androidx.test.rules",
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index 5336811..de2bba2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -123,7 +123,7 @@
         assertTrue(stack1.isFocusedStackOnDisplay());
 
         // Stack2 should be focused after removing stack1.
-        display.removeChild(stack1);
+        display.removeStack(stack1);
         assertTrue(stack2.isFocusedStackOnDisplay());
     }
 
@@ -224,7 +224,7 @@
         final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true)
                 .setStack(alwaysOnTopStack).build();
         alwaysOnTopStack.setAlwaysOnTop(true);
-        display.positionChildAtTop(alwaysOnTopStack, false /* includingParents */);
+        display.positionStackAtTop(alwaysOnTopStack, false /* includingParents */);
         assertTrue(alwaysOnTopStack.isAlwaysOnTop());
         // Ensure always on top state is synced to the children of the stack.
         assertTrue(alwaysOnTopStack.getTopNonFinishingActivity().isAlwaysOnTop());
@@ -238,36 +238,36 @@
         final ActivityStack anotherAlwaysOnTopStack = display.createStack(
                 WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
         anotherAlwaysOnTopStack.setAlwaysOnTop(true);
-        display.positionChildAtTop(anotherAlwaysOnTopStack, false /* includingParents */);
+        display.positionStackAtTop(anotherAlwaysOnTopStack, false /* includingParents */);
         assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
-        int topPosition = display.getChildCount() - 1;
+        int topPosition = display.getStackCount() - 1;
         // Ensure the new alwaysOnTop stack is put below the pinned stack, but on top of the
         // existing alwaysOnTop stack.
-        assertEquals(anotherAlwaysOnTopStack, display.getChildAt(topPosition - 1));
+        assertEquals(anotherAlwaysOnTopStack, display.getStackAt(topPosition - 1));
 
         final ActivityStack nonAlwaysOnTopStack = display.createStack(
                 WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
         assertEquals(display, nonAlwaysOnTopStack.getDisplay());
-        topPosition = display.getChildCount() - 1;
+        topPosition = display.getStackCount() - 1;
         // Ensure the non-alwaysOnTop stack is put below the three alwaysOnTop stacks, but above the
         // existing other non-alwaysOnTop stacks.
-        assertEquals(nonAlwaysOnTopStack, display.getChildAt(topPosition - 3));
+        assertEquals(nonAlwaysOnTopStack, display.getStackAt(topPosition - 3));
 
         anotherAlwaysOnTopStack.setAlwaysOnTop(false);
-        display.positionChildAtTop(anotherAlwaysOnTopStack, false /* includingParents */);
+        display.positionStackAtTop(anotherAlwaysOnTopStack, false /* includingParents */);
         assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
         // Ensure, when always on top is turned off for a stack, the stack is put just below all
         // other always on top stacks.
-        assertEquals(anotherAlwaysOnTopStack, display.getChildAt(topPosition - 2));
+        assertEquals(anotherAlwaysOnTopStack, display.getStackAt(topPosition - 2));
         anotherAlwaysOnTopStack.setAlwaysOnTop(true);
 
         // Ensure always on top state changes properly when windowing mode changes.
         anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
-        assertEquals(anotherAlwaysOnTopStack, display.getChildAt(topPosition - 2));
+        assertEquals(anotherAlwaysOnTopStack, display.getStackAt(topPosition - 2));
         anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FREEFORM);
         assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
-        assertEquals(anotherAlwaysOnTopStack, display.getChildAt(topPosition - 1));
+        assertEquals(anotherAlwaysOnTopStack, display.getStackAt(topPosition - 1));
     }
 
     @Test
@@ -299,14 +299,14 @@
 
         // Reordering stacks while removing stacks.
         doAnswer(invocation -> {
-            display.positionChildAtTop(stack3, false);
+            display.positionStackAtTop(stack3, false);
             return true;
         }).when(mSupervisor).removeTaskByIdLocked(eq(task4.mTaskId), anyBoolean(), anyBoolean(),
                 any());
 
         // Removing stacks from the display while removing stacks.
         doAnswer(invocation -> {
-            display.removeChild(stack2);
+            display.removeStack(stack2);
             return true;
         }).when(mSupervisor).removeTaskByIdLocked(eq(task2.mTaskId), anyBoolean(), anyBoolean(),
                 any());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index 734761f..12074dc3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -18,6 +18,7 @@
 
 import static android.app.ActivityManager.START_SUCCESS;
 import static android.app.ActivityManager.START_TASK_TO_FRONT;
+import static android.content.ComponentName.createRelative;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -34,7 +35,7 @@
 import android.content.Intent;
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
-import android.util.SparseIntArray;
+import android.util.ArrayMap;
 
 import androidx.test.filters.SmallTest;
 
@@ -58,11 +59,13 @@
 @Presubmit
 public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase {
     private ActivityMetricsLogger mActivityMetricsLogger;
+    private ActivityMetricsLogger.LaunchingState mLaunchingState;
     private ActivityMetricsLaunchObserver mLaunchObserver;
     private ActivityMetricsLaunchObserverRegistry mLaunchObserverRegistry;
 
     private ActivityRecord mTrampolineActivity;
     private ActivityRecord mTopActivity;
+    private boolean mLaunchTopByTrampoline;
 
     @Before
     public void setUpAMLO() {
@@ -76,9 +79,13 @@
 
         // Sometimes we need an ActivityRecord for ActivityMetricsLogger to do anything useful.
         // This seems to be the easiest way to create an ActivityRecord.
-        mTrampolineActivity = new ActivityBuilder(mService).setCreateTask(true).build();
+        mTrampolineActivity = new ActivityBuilder(mService)
+                .setCreateTask(true)
+                .setComponent(createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, "TrampolineActivity"))
+                .build();
         mTopActivity = new ActivityBuilder(mService)
                 .setTask(mTrampolineActivity.getTask())
+                .setComponent(createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, "TopActivity"))
                 .build();
     }
 
@@ -114,42 +121,42 @@
         return verify(mock, timeout(TimeUnit.SECONDS.toMillis(5)));
     }
 
-    private void onIntentStarted() {
-        Intent intent = new Intent("action 1");
+    private void onIntentStarted(Intent intent) {
+        notifyActivityLaunching(intent);
 
-        mActivityMetricsLogger.notifyActivityLaunching(intent);
-
-        verifyAsync(mLaunchObserver).onIntentStarted(eq(intent), anyLong());
+        // If it is launching top activity from trampoline activity, the observer shouldn't receive
+        // onActivityLaunched because the activities should belong to the same transition.
+        if (!mLaunchTopByTrampoline) {
+            verifyAsync(mLaunchObserver).onIntentStarted(eq(intent), anyLong());
+        }
         verifyNoMoreInteractions(mLaunchObserver);
     }
 
     @Test
     public void testOnIntentFailed() {
-        onIntentStarted();
+        onIntentStarted(new Intent("testOnIntentFailed"));
 
         // Bringing an intent that's already running 'to front' is not considered
         // as an ACTIVITY_LAUNCHED state transition.
-        mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT,
-                null /* launchedActivity */);
+        notifyActivityLaunched(START_TASK_TO_FRONT, null /* launchedActivity */);
 
         verifyAsync(mLaunchObserver).onIntentFailed();
         verifyNoMoreInteractions(mLaunchObserver);
     }
 
-    private void onActivityLaunched() {
-        onIntentStarted();
+    private void onActivityLaunched(ActivityRecord activity) {
+        onIntentStarted(activity.intent);
+        notifyActivityLaunched(START_SUCCESS, activity);
 
-        mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTopActivity);
-
-        verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTopActivity), anyInt());
+        verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(activity), anyInt());
         verifyNoMoreInteractions(mLaunchObserver);
     }
 
     @Test
     public void testOnActivityLaunchFinished() {
-        onActivityLaunched();
+        onActivityLaunched(mTopActivity);
 
-        notifyTransitionStarting();
+        notifyTransitionStarting(mTopActivity);
         notifyWindowsDrawn(mTopActivity);
 
         verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong());
@@ -158,12 +165,12 @@
 
     @Test
     public void testOnActivityLaunchCancelled_hasDrawn() {
-        onActivityLaunched();
+        onActivityLaunched(mTopActivity);
 
         mTopActivity.mVisibleRequested = mTopActivity.mDrawn = true;
 
         // Cannot time already-visible activities.
-        mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity);
+        notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity);
 
         verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTopActivity));
         verifyNoMoreInteractions(mLaunchObserver);
@@ -182,8 +189,8 @@
                 .build();
         mSupervisor.readyToResume();
 
-        mActivityMetricsLogger.notifyActivityLaunching(noDrawnActivity.intent);
-        mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, noDrawnActivity);
+        notifyActivityLaunching(noDrawnActivity.intent);
+        notifyActivityLaunched(START_SUCCESS, noDrawnActivity);
 
         noDrawnActivity.destroyIfPossible("test");
         mActivityMetricsLogger.notifyVisibilityChanged(noDrawnActivity);
@@ -193,12 +200,12 @@
 
     @Test
     public void testOnReportFullyDrawn() {
-        onActivityLaunched();
+        onActivityLaunched(mTopActivity);
 
         // The activity reports fully drawn before windows drawn, then the fully drawn event will
         // be pending (see {@link WindowingModeTransitionInfo#pendingFullyDrawn}).
         mActivityMetricsLogger.logAppTransitionReportedDrawn(mTopActivity, false);
-        notifyTransitionStarting();
+        notifyTransitionStarting(mTopActivity);
         // The pending fully drawn event should send when the actual windows drawn event occurs.
         notifyWindowsDrawn(mTopActivity);
 
@@ -208,35 +215,56 @@
     }
 
     private void onActivityLaunchedTrampoline() {
-        onIntentStarted();
-
-        mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTrampolineActivity);
+        onIntentStarted(mTrampolineActivity.intent);
+        notifyActivityLaunched(START_SUCCESS, mTrampolineActivity);
 
         verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTrampolineActivity), anyInt());
 
         // A second, distinct, activity launch is coalesced into the current app launch sequence.
-        mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTopActivity);
+        mLaunchTopByTrampoline = true;
+        onIntentStarted(mTopActivity.intent);
+        notifyActivityLaunched(START_SUCCESS, mTopActivity);
 
+        // The observer shouldn't receive onActivityLaunched for an existing transition.
         verifyNoMoreInteractions(mLaunchObserver);
     }
 
-    private void notifyTransitionStarting() {
-        mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(),
-                SystemClock.elapsedRealtimeNanos());
+    private void notifyActivityLaunching(Intent intent) {
+        final ActivityMetricsLogger.LaunchingState previousState = mLaunchingState;
+        mLaunchingState = mActivityMetricsLogger.notifyActivityLaunching(intent,
+                mLaunchTopByTrampoline ? mTrampolineActivity : null /* caller */);
+        if (mLaunchTopByTrampoline) {
+            // The transition of TrampolineActivity has not been completed, so when the next
+            // activity is starting from it, the same launching state should be returned.
+            assertWithMessage("Use existing launching state for a caller in active transition")
+                    .that(previousState).isEqualTo(mLaunchingState);
+        }
+    }
+
+    private void notifyActivityLaunched(int resultCode, ActivityRecord activity) {
+        mActivityMetricsLogger.notifyActivityLaunched(mLaunchingState, resultCode, activity);
+    }
+
+    private void notifyTransitionStarting(ActivityRecord activity) {
+        final ArrayMap<ActivityRecord, Integer> reasons = new ArrayMap<>();
+        reasons.put(activity, ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN);
+        mActivityMetricsLogger.notifyTransitionStarting(reasons);
     }
 
     private void notifyWindowsDrawn(ActivityRecord r) {
-        mActivityMetricsLogger.notifyWindowsDrawn(r.getWindowingMode(),
-                SystemClock.elapsedRealtimeNanos());
+        mActivityMetricsLogger.notifyWindowsDrawn(r, SystemClock.elapsedRealtimeNanos());
     }
 
     @Test
     public void testOnActivityLaunchFinishedTrampoline() {
         onActivityLaunchedTrampoline();
 
-        notifyTransitionStarting();
+        notifyTransitionStarting(mTopActivity);
         notifyWindowsDrawn(mTrampolineActivity);
 
+        assertWithMessage("Trampoline activity is drawn but the top activity is not yet")
+                .that(mLaunchingState.allDrawn()).isFalse();
+
         notifyWindowsDrawn(mTopActivity);
 
         verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong());
@@ -244,13 +272,23 @@
     }
 
     @Test
+    public void testDoNotCountInvisibleActivityToBeDrawn() {
+        onActivityLaunchedTrampoline();
+        mTrampolineActivity.setVisibility(false);
+        notifyWindowsDrawn(mTopActivity);
+
+        assertWithMessage("Trampoline activity is invisble so there should be no undrawn windows")
+                .that(mLaunchingState.allDrawn()).isTrue();
+    }
+
+    @Test
     public void testOnActivityLaunchCancelledTrampoline() {
         onActivityLaunchedTrampoline();
 
         mTopActivity.mDrawn = true;
 
         // Cannot time already-visible activities.
-        mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity);
+        notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity);
 
         verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTopActivity));
         verifyNoMoreInteractions(mLaunchObserver);
@@ -268,4 +306,32 @@
                 .that(activityRecordToProto(mTrampolineActivity).length)
                 .isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
     }
+
+    @Test
+    public void testConcurrentLaunches() {
+        onActivityLaunched(mTopActivity);
+        final ActivityMetricsLogger.LaunchingState previousState = mLaunchingState;
+
+        final ActivityRecord otherActivity = new ActivityBuilder(mService)
+                .setComponent(createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, "OtherActivity"))
+                .setCreateTask(true)
+                .build();
+        // Assume the calling uid is different from the uid of TopActivity, so a new launching
+        // state should be created here.
+        onActivityLaunched(otherActivity);
+
+        assertWithMessage("Different callers should get 2 indepedent launching states")
+                .that(previousState).isNotEqualTo(mLaunchingState);
+
+        notifyTransitionStarting(otherActivity);
+        notifyWindowsDrawn(otherActivity);
+
+        verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(otherActivity), anyLong());
+
+        // The first transition should still be valid.
+        notifyTransitionStarting(mTopActivity);
+        notifyWindowsDrawn(mTopActivity);
+
+        verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong());
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index b1b386b..dbcfa94 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -203,7 +203,7 @@
         // An activity can be launched on default display.
         assertTrue(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY));
         // An activity cannot be launched on a non-existent display.
-        assertFalse(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY + 1));
+        assertFalse(activity.canBeLaunchedOnDisplay(Integer.MAX_VALUE));
     }
 
     @Test
@@ -455,7 +455,7 @@
             verify(mService.getLifecycleManager()).scheduleTransaction(
                     eq(mActivity.app.getThread()), eq(mActivity.appToken), eq(expected));
         } finally {
-            stack.getDisplay().removeChild(stack);
+            stack.getDisplay().removeStack(stack);
         }
     }
 
@@ -914,7 +914,7 @@
         // Add another stack to become focused and make the activity there visible. This way it
         // simulates finishing in non-focused stack in split-screen.
         final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
-        final ActivityRecord focusedActivity = stack.getChildAt(0).getChildAt(0);
+        final ActivityRecord focusedActivity = stack.getTopMostActivity();
         focusedActivity.nowVisible = true;
         focusedActivity.mVisibleRequested = true;
         focusedActivity.setState(RESUMED, "test");
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index ba54859..7806d40 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -241,7 +241,7 @@
 
         final RootActivityContainer.FindTaskResult result =
                 new RootActivityContainer.FindTaskResult();
-        mStack.findTaskLocked(r, result);
+        result.process(r, mStack);
 
         assertEquals(r, task.getTopNonFinishingActivity(false /* includeOverlays */));
         assertEquals(taskOverlay, task.getTopNonFinishingActivity(true /* includeOverlays */));
@@ -266,14 +266,14 @@
         final ActivityRecord r1 = new ActivityBuilder(mService).setComponent(
                 target).setTargetActivity(targetActivity).build();
         RootActivityContainer.FindTaskResult result = new RootActivityContainer.FindTaskResult();
-        mStack.findTaskLocked(r1, result);
+        result.process(r1, mStack);
         assertThat(result.mRecord).isNotNull();
 
         // Using alias activity to find task.
         final ActivityRecord r2 = new ActivityBuilder(mService).setComponent(
                 alias).setTargetActivity(targetActivity).build();
         result = new RootActivityContainer.FindTaskResult();
-        mStack.findTaskLocked(r2, result);
+        result.process(r2, mStack);
         assertThat(result.mRecord).isNotNull();
     }
 
@@ -290,7 +290,7 @@
         verify(stack2).positionChildAtBottom(any(), eq(false) /* includingParents */);
 
         // Also move display to back because there is only one stack left.
-        display.removeChild(stack1);
+        display.removeStack(stack1);
         stack2.moveToBack("testMoveStackToBackIncludingParent", stack2.topTask());
         verify(stack2).positionChildAtBottom(any(), eq(true) /* includingParents */);
     }
@@ -576,7 +576,7 @@
 
     @Test
     public void testMoveHomeStackBehindBottomMostVisibleStack_NoMoveHomeBehindFullscreen() {
-        mDefaultDisplay.removeChild(mStack);
+        mDefaultDisplay.removeStack(mStack);
 
         final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
@@ -595,7 +595,7 @@
 
     @Test
     public void testMoveHomeStackBehindBottomMostVisibleStack_NoMoveHomeBehindTranslucent() {
-        mDefaultDisplay.removeChild(mStack);
+        mDefaultDisplay.removeStack(mStack);
 
         final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
@@ -614,7 +614,7 @@
 
     @Test
     public void testMoveHomeStackBehindBottomMostVisibleStack_NoMoveHomeOnTop() {
-        mDefaultDisplay.removeChild(mStack);
+        mDefaultDisplay.removeStack(mStack);
 
         final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -633,7 +633,7 @@
 
     @Test
     public void testMoveHomeStackBehindBottomMostVisibleStack_MoveHomeBehindFullscreen() {
-        mDefaultDisplay.removeChild(mStack);
+        mDefaultDisplay.removeStack(mStack);
 
         final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
@@ -660,7 +660,7 @@
     @Test
     public void
             testMoveHomeStackBehindBottomMostVisibleStack_MoveHomeBehindFullscreenAndTranslucent() {
-        mDefaultDisplay.removeChild(mStack);
+        mDefaultDisplay.removeStack(mStack);
 
         final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
@@ -684,7 +684,7 @@
 
     @Test
     public void testMoveHomeStackBehindStack_BehindHomeStack() {
-        mDefaultDisplay.removeChild(mStack);
+        mDefaultDisplay.removeStack(mStack);
 
         final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
                 mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
@@ -707,7 +707,7 @@
 
     @Test
     public void testMoveHomeStackBehindStack() {
-        mDefaultDisplay.removeChild(mStack);
+        mDefaultDisplay.removeStack(mStack);
 
         final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
                 mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
@@ -814,16 +814,16 @@
     }
 
     @SuppressWarnings("TypeParameterUnusedInFormals")
-    private <T extends ActivityStack> T createStackForShouldBeVisibleTest(
+    private ActivityStack createStackForShouldBeVisibleTest(
             ActivityDisplay display, int windowingMode, int activityType, boolean onTop) {
         final ActivityStack stack;
         if (activityType == ACTIVITY_TYPE_HOME) {
             // Home stack and activity are created in ActivityTestsBase#setupActivityManagerService
             stack = mDefaultDisplay.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
             if (onTop) {
-                mDefaultDisplay.positionChildAtTop(stack, false /* includingParents */);
+                mDefaultDisplay.positionStackAtTop(stack, false /* includingParents */);
             } else {
-                mDefaultDisplay.positionChildAtBottom(stack);
+                mDefaultDisplay.positionStackAtBottom(stack);
             }
         } else {
             stack = new StackBuilder(mRootActivityContainer)
@@ -834,7 +834,7 @@
                     .setCreateActivity(true)
                     .build();
         }
-        return (T) stack;
+        return stack;
     }
 
     @Test
@@ -846,9 +846,9 @@
         mStack.mResumedActivity = secondActivity;
 
         // Note the activities have non-null ActivityRecord.app, so it won't remove directly.
-        mStack.finishDisabledPackageActivitiesLocked(firstActivity.packageName,
-                null /* filterByClasses */, true /* doit */, true /* evenPersistent */,
-                UserHandle.USER_ALL);
+        mRootActivityContainer.mFinishDisabledPackageActivitiesHelper.process(
+                firstActivity.packageName, null /* filterByClasses */, true /* doit */,
+                true /* evenPersistent */, UserHandle.USER_ALL);
 
         // If the activity is disabled with {@link android.content.pm.PackageManager#DONT_KILL_APP}
         // the activity should still follow the normal flow to finish and destroy.
@@ -875,9 +875,9 @@
 
         assertEquals(2, mTask.getChildCount());
 
-        mStack.finishDisabledPackageActivitiesLocked(activity.packageName,
-                null  /* filterByClasses */, true /* doit */, true /* evenPersistent */,
-                UserHandle.USER_ALL);
+        mRootActivityContainer.mFinishDisabledPackageActivitiesHelper.process(
+                activity.packageName, null  /* filterByClasses */, true /* doit */,
+                true /* evenPersistent */, UserHandle.USER_ALL);
 
         // Although the overlay activity is in another package, the non-overlay activities are
         // removed from the task. Since the overlay activity should be removed as well, the task
@@ -1051,7 +1051,7 @@
         StackOrderChangedListener listener = new StackOrderChangedListener();
         mDefaultDisplay.registerStackOrderChangedListener(listener);
         try {
-            mDefaultDisplay.removeChild(mStack);
+            mDefaultDisplay.removeStack(mStack);
         } finally {
             mDefaultDisplay.unregisterStackOrderChangedListener(listener);
         }
@@ -1060,12 +1060,12 @@
 
     @Test
     public void testStackOrderChangedOnAddPositionStack() {
-        mDefaultDisplay.removeChild(mStack);
+        mDefaultDisplay.removeStack(mStack);
 
         StackOrderChangedListener listener = new StackOrderChangedListener();
         mDefaultDisplay.registerStackOrderChangedListener(listener);
         try {
-            mDefaultDisplay.addChild(mStack, 0);
+            mDefaultDisplay.addStack(mStack, 0);
         } finally {
             mDefaultDisplay.unregisterStackOrderChangedListener(listener);
         }
@@ -1080,7 +1080,7 @@
                     mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
                     true /* onTop */);
             mDefaultDisplay.registerStackOrderChangedListener(listener);
-            mDefaultDisplay.positionChildAtBottom(fullscreenStack1);
+            mDefaultDisplay.positionStackAtBottom(fullscreenStack1);
         } finally {
             mDefaultDisplay.unregisterStackOrderChangedListener(listener);
         }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
index 4165052..d78e3af 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
@@ -167,16 +167,8 @@
 
     @Test
     public void testSuspendedPackage() {
-        mAInfo.applicationInfo.flags = FLAG_SUSPENDED;
         final String suspendingPackage = "com.test.suspending.package";
-        final SuspendDialogInfo dialogInfo = new SuspendDialogInfo.Builder()
-                .setMessage("Test Message")
-                .setIcon(0x11110001)
-                .build();
-        when(mPackageManagerInternal.getSuspendingPackage(TEST_PACKAGE_NAME, TEST_USER_ID))
-                .thenReturn(suspendingPackage);
-        when(mPackageManagerInternal.getSuspendedDialogInfo(TEST_PACKAGE_NAME, suspendingPackage,
-                TEST_USER_ID)).thenReturn(dialogInfo);
+        final SuspendDialogInfo dialogInfo = suspendPackage(suspendingPackage);
         // THEN calling intercept returns true
         assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
 
@@ -190,6 +182,19 @@
         assertEquals(TEST_USER_ID, mInterceptor.mIntent.getIntExtra(Intent.EXTRA_USER_ID, -1000));
     }
 
+    private SuspendDialogInfo suspendPackage(String suspendingPackage) {
+        mAInfo.applicationInfo.flags = FLAG_SUSPENDED;
+        final SuspendDialogInfo dialogInfo = new SuspendDialogInfo.Builder()
+                .setMessage("Test Message")
+                .setIcon(0x11110001)
+                .build();
+        when(mPackageManagerInternal.getSuspendingPackage(TEST_PACKAGE_NAME, TEST_USER_ID))
+                .thenReturn(suspendingPackage);
+        when(mPackageManagerInternal.getSuspendedDialogInfo(TEST_PACKAGE_NAME, suspendingPackage,
+                TEST_USER_ID)).thenReturn(dialogInfo);
+        return dialogInfo;
+    }
+
     @Test
     public void testInterceptQuietProfile() {
         // GIVEN that the user the activity is starting as is currently in quiet mode
@@ -204,6 +209,20 @@
     }
 
     @Test
+    public void testInterceptQuietProfileWhenPackageSuspended() {
+        suspendPackage("com.test.suspending.package");
+        // GIVEN that the user the activity is starting as is currently in quiet mode
+        when(mUserManager.isQuietModeEnabled(eq(UserHandle.of(TEST_USER_ID)))).thenReturn(true);
+
+        // THEN calling intercept returns true
+        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
+
+        // THEN the returned intent is the quiet mode intent
+        assertTrue(UnlaunchableAppActivity.createInQuietModeDialogIntent(TEST_USER_ID)
+                .filterEquals(mInterceptor.mIntent));
+    }
+
+    @Test
     public void testWorkChallenge() {
         // GIVEN that the user the activity is starting as is currently locked
         when(mAmInternal.shouldConfirmCredentials(TEST_USER_ID)).thenReturn(true);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index ae1bb8e..d5fdf98 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -517,8 +517,8 @@
     }
 
     private void assertNoTasks(ActivityDisplay display) {
-        for (int i = display.getChildCount() - 1; i >= 0; --i) {
-            final ActivityStack stack = display.getChildAt(i);
+        for (int i = display.getStackCount() - 1; i >= 0; --i) {
+            final ActivityStack stack = display.getStackAt(i);
             assertThat(stack.getAllTasks()).isEmpty();
         }
     }
@@ -962,4 +962,19 @@
         }
         assertThat(exceptionCaught).isTrue();
     }
+
+    @Test
+    public void testRecycleTaskFromAnotherUser() {
+        final ActivityStarter starter = prepareStarter(0 /* flags */);
+        starter.mStartActivity = new ActivityBuilder(mService).build();
+        final Task task = new TaskBuilder(mService.mStackSupervisor)
+                .setStack(mService.mRootActivityContainer.getDefaultDisplay().createStack(
+                        WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */))
+                .setUserId(10)
+                .build();
+
+        final int result = starter.recycleTask(task, null, null);
+        assertThat(result == START_SUCCESS).isTrue();
+        assertThat(starter.mAddingToTask).isTrue();
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 7322ac3..0021cc5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -203,6 +203,15 @@
         }
 
         ActivityRecord build() {
+            try {
+                mService.deferWindowLayout();
+                return buildInner();
+            } finally {
+                mService.continueWindowLayout();
+            }
+        }
+
+        ActivityRecord buildInner() {
             if (mComponent == null) {
                 final int id = sCurrentActivityId++;
                 mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME,
@@ -236,7 +245,7 @@
 
             ActivityOptions options = null;
             if (mLaunchTaskBehind) {
-                options =  ActivityOptions.makeTaskLaunchBehind();
+                options = ActivityOptions.makeTaskLaunchBehind();
             }
 
             final ActivityRecord activity = new ActivityRecord(mService, null /* caller */,
@@ -399,11 +408,18 @@
             return this;
         }
 
+        // TODO(display-merge): Remove
         StackBuilder setDisplay(ActivityDisplay display) {
             mDisplay = display;
             return this;
         }
 
+        StackBuilder setDisplay(DisplayContent display) {
+            // TODO(display-merge): Remove cast
+            mDisplay = (ActivityDisplay) display;
+            return this;
+        }
+
         StackBuilder setOnTop(boolean onTop) {
             mOnTop = onTop;
             return this;
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 9f3bd75..0382bf8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -54,6 +54,7 @@
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
+import android.view.IWindowManager;
 import android.view.Surface;
 import android.view.WindowManager;
 
@@ -334,7 +335,7 @@
         mActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
 
         mDisplayContent.getDisplayRotation().setFixedToUserRotation(
-                DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED);
+                IWindowManager.FIXED_TO_USER_ROTATION_ENABLED);
         reset(mTask);
         mActivity.reportDescendantOrientationChangeIfNeeded();
         verify(mTask).onConfigurationChanged(any(Configuration.class));
diff --git a/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java
index beec1a8..0ad0f95 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java
@@ -47,6 +47,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test class for {@link BoundsAnimationController} to ensure that it sends the right callbacks
@@ -63,6 +64,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class BoundsAnimationControllerTests extends WindowTestsBase {
 
     /**
diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
index 73420a0..0aa6961 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
@@ -36,12 +36,14 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Build/Install/Run:
  *  atest FrameworksServicesTests:DimmerTests
  */
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class DimmerTests extends WindowTestsBase {
 
     private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 5070fb6..716e777 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -82,6 +82,7 @@
 import android.view.IDisplayWindowRotationCallback;
 import android.view.IDisplayWindowRotationController;
 import android.view.ISystemGestureExclusionListener;
+import android.view.IWindowManager;
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.ViewRootImpl;
@@ -704,17 +705,17 @@
     public void testAllowsTopmostFullscreenOrientation() {
         final DisplayContent dc = createNewDisplay();
         dc.getDisplayRotation().setFixedToUserRotation(
-                DisplayRotation.FIXED_TO_USER_ROTATION_DISABLED);
+                IWindowManager.FIXED_TO_USER_ROTATION_DISABLED);
 
         final ActivityStack stack =
                 new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootActivityContainer)
-                        .setDisplay(dc.mActivityDisplay)
+                        .setDisplay(dc)
                         .build();
         doReturn(true).when(stack).isVisible();
 
         final ActivityStack freeformStack =
                 new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootActivityContainer)
-                        .setDisplay(dc.mActivityDisplay)
+                        .setDisplay(dc)
                         .setWindowingMode(WINDOWING_MODE_FREEFORM)
                         .build();
         doReturn(true).when(freeformStack).isVisible();
@@ -735,14 +736,14 @@
     public void testOnDescendantOrientationRequestChanged() {
         final DisplayContent dc = createNewDisplay();
         dc.getDisplayRotation().setFixedToUserRotation(
-                DisplayRotation.FIXED_TO_USER_ROTATION_DISABLED);
+                IWindowManager.FIXED_TO_USER_ROTATION_DISABLED);
         final int newOrientation = dc.getLastOrientation() == SCREEN_ORIENTATION_LANDSCAPE
                 ? SCREEN_ORIENTATION_PORTRAIT
                 : SCREEN_ORIENTATION_LANDSCAPE;
 
         final ActivityStack stack =
                 new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootActivityContainer)
-                        .setDisplay(dc.mActivityDisplay).build();
+                        .setDisplay(dc).build();
         final ActivityRecord activity = stack.topTask().getTopNonFinishingActivity();
 
         activity.setRequestedOrientation(newOrientation);
@@ -757,19 +758,20 @@
     public void testOnDescendantOrientationRequestChanged_FrozenToUserRotation() {
         final DisplayContent dc = createNewDisplay();
         dc.getDisplayRotation().setFixedToUserRotation(
-                DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED);
+                IWindowManager.FIXED_TO_USER_ROTATION_ENABLED);
         final int newOrientation = dc.getLastOrientation() == SCREEN_ORIENTATION_LANDSCAPE
                 ? SCREEN_ORIENTATION_PORTRAIT
                 : SCREEN_ORIENTATION_LANDSCAPE;
 
         final ActivityStack stack =
                 new ActivityTestsBase.StackBuilder(mWm.mAtmService.mRootActivityContainer)
-                        .setDisplay(dc.mActivityDisplay).build();
+                        .setDisplay(dc).build();
         final ActivityRecord activity = stack.topTask().getTopNonFinishingActivity();
 
         activity.setRequestedOrientation(newOrientation);
 
-        verify(dc.mActivityDisplay, never()).updateDisplayOverrideConfigurationLocked(any(),
+        // TODO(display-merge): Remove cast
+        verify((ActivityDisplay) dc, never()).updateDisplayOverrideConfigurationLocked(any(),
                 eq(activity), anyBoolean(), same(null));
         assertEquals(dc.getDisplayRotation().getUserRotation(), dc.getRotation());
     }
@@ -939,6 +941,7 @@
         final DisplayContent displayContent = createNewDisplay();
         Mockito.doReturn(mockLogger).when(displayContent).getMetricsLogger();
         Mockito.doReturn(oldConfig).doReturn(newConfig).when(displayContent).getConfiguration();
+        doNothing().when(displayContent).preOnConfigurationChanged();
 
         displayContent.onConfigurationChanged(newConfig);
 
@@ -958,12 +961,12 @@
         Mockito.doCallRealMethod().when(dr).updateRotationUnchecked(anyBoolean());
         Mockito.doReturn(ROTATION_90).when(dr).rotationForOrientation(anyInt(), anyInt());
         final boolean[] continued = new boolean[1];
-        spyOn(dc.mActivityDisplay);
+        // TODO(display-merge): Remove cast
         Mockito.doAnswer(
                 invocation -> {
                     continued[0] = true;
                     return true;
-                }).when(dc.mActivityDisplay).updateDisplayOverrideConfigurationLocked();
+                }).when((ActivityDisplay) dc).updateDisplayOverrideConfigurationLocked();
         final boolean[] called = new boolean[1];
         mWm.mDisplayRotationController =
                 new IDisplayWindowRotationController.Stub() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyInsetsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyInsetsTests.java
index 6767465..f754c59 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyInsetsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyInsetsTests.java
@@ -32,9 +32,11 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ErrorCollector;
+import org.junit.runner.RunWith;
 
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class DisplayPolicyInsetsTests extends DisplayPolicyTestsBase {
 
     @Rule
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index bb4d35f..da807d8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -19,6 +19,9 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT;
+import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_DISABLED;
+import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_ENABLED;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
@@ -32,9 +35,6 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
-import static com.android.server.wm.DisplayRotation.FIXED_TO_USER_ROTATION_DEFAULT;
-import static com.android.server.wm.DisplayRotation.FIXED_TO_USER_ROTATION_DISABLED;
-import static com.android.server.wm.DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index e375f83..8566412 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -18,6 +18,9 @@
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT;
+import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_DISABLED;
+import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_ENABLED;
 import static android.view.WindowManager.REMOVE_CONTENT_MODE_DESTROY;
 import static android.view.WindowManager.REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY;
 
@@ -28,9 +31,6 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.android.server.wm.DisplayRotation.FIXED_TO_USER_ROTATION_DEFAULT;
-import static com.android.server.wm.DisplayRotation.FIXED_TO_USER_ROTATION_DISABLED;
-import static com.android.server.wm.DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -80,6 +80,9 @@
 @RunWith(WindowTestRunner.class)
 public class DisplayWindowSettingsTests extends WindowTestsBase {
 
+    private static final byte DISPLAY_PORT = (byte) 0xFF;
+    private static final long DISPLAY_MODEL = 0xEEEEEEEEL;
+
     private static final File TEST_FOLDER = getInstrumentation().getTargetContext().getCacheDir();
     private DisplayWindowSettings mTarget;
 
@@ -479,10 +482,11 @@
 
     @Test
     public void testReadingDisplaySettingsFromStorage_UsePortAsId() {
-        final DisplayAddress.Physical displayAddress = DisplayAddress.fromPhysicalDisplayId(123456);
+        final DisplayAddress.Physical displayAddress =
+                DisplayAddress.fromPortAndModel(DISPLAY_PORT, DISPLAY_MODEL);
         mPrimaryDisplay.getDisplayInfo().address = displayAddress;
 
-        final String displayIdentifier = "port:" + displayAddress.getPort();
+        final String displayIdentifier = "port:" + Byte.toUnsignedInt(DISPLAY_PORT);
         prepareDisplaySettings(displayIdentifier, true /* usePortAsId */);
 
         readAndAssertDisplaySettings(mPrimaryDisplay);
@@ -521,7 +525,8 @@
     @Test
     public void testWritingDisplaySettingsToStorage_UsePortAsId() throws Exception {
         // Store config to use port as identifier.
-        final DisplayAddress.Physical displayAddress = DisplayAddress.fromPhysicalDisplayId(123456);
+        final DisplayAddress.Physical displayAddress =
+                DisplayAddress.fromPortAndModel(DISPLAY_PORT, DISPLAY_MODEL);
         mSecondaryDisplay.getDisplayInfo().address = displayAddress;
         prepareDisplaySettings(null /* displayIdentifier */, true /* usePortAsId */);
 
@@ -532,7 +537,7 @@
         assertTrue(mStorage.wasWriteSuccessful());
 
         // Verify that settings were stored correctly.
-        assertEquals("Attribute value must be stored", "port:" + displayAddress.getPort(),
+        assertEquals("Attribute value must be stored", "port:" + Byte.toUnsignedInt(DISPLAY_PORT),
                 getStoredDisplayAttributeValue("name"));
         assertEquals("Attribute value must be stored", "true",
                 getStoredDisplayAttributeValue("shouldShowSystemDecors"));
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index 79ad0c4..9e5d9da 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -46,6 +46,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 
 import java.io.File;
@@ -63,6 +64,7 @@
  */
 @MediumTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class LaunchParamsPersisterTests extends ActivityTestsBase {
     private static final int TEST_USER_ID = 3;
     private static final int ALTERNATIVE_USER_ID = 0;
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 4f2d5d2..9f97c48 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -977,9 +977,9 @@
     private void assertNotRestoreTask(Runnable action) {
         // Verify stack count doesn't change because task with fullscreen mode and standard type
         // would have its own stack.
-        final int orignalStackCount = mDisplay.getChildCount();
+        final int originalStackCount = mDisplay.getStackCount();
         action.run();
-        assertEquals(orignalStackCount, mDisplay.getChildCount());
+        assertEquals(originalStackCount, mDisplay.getStackCount());
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 1abd366..2374847 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -138,7 +138,8 @@
     @Test
     public void testIncludedApps_expectTargetAndVisible() {
         mWm.setRecentsAnimationController(mController);
-        final ActivityStack homeStack = mDisplayContent.mActivityDisplay.getOrCreateStack(
+        // TODO(display-merge): Remove cast
+        final ActivityStack homeStack = ((ActivityDisplay) mDisplayContent).getOrCreateStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
         final ActivityRecord homeActivity =
                 new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
@@ -163,7 +164,8 @@
     @Test
     public void testWallpaperIncluded_expectTarget() throws Exception {
         mWm.setRecentsAnimationController(mController);
-        final ActivityStack homeStack = mDisplayContent.mActivityDisplay.getOrCreateStack(
+        // TODO(display-merge): Remove cast
+        final ActivityStack homeStack = ((ActivityDisplay) mDisplayContent).getOrCreateStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
         final ActivityRecord homeAppWindow =
                 new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
@@ -192,7 +194,8 @@
     @Test
     public void testWallpaperAnimatorCanceled_expectAnimationKeepsRunning() throws Exception {
         mWm.setRecentsAnimationController(mController);
-        final ActivityStack homeStack = mDisplayContent.mActivityDisplay.getOrCreateStack(
+        // TODO(display-merge): Remove cast
+        final ActivityStack homeStack = ((ActivityDisplay) mDisplayContent).getOrCreateStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
         final ActivityRecord homeActivity =
                 new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
@@ -223,7 +226,8 @@
     @Test
     public void testFinish_expectTargetAndWallpaperAdaptersRemoved() {
         mWm.setRecentsAnimationController(mController);
-        final ActivityStack homeStack = mDisplayContent.mActivityDisplay.getOrCreateStack(
+        // TODO(display-merge): Remove cast
+        final ActivityStack homeStack = ((ActivityDisplay) mDisplayContent).getOrCreateStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
         final ActivityRecord homeActivity =
                 new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index e67380c..4abab63 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -119,7 +119,7 @@
         final ActivityDisplay defaultDisplay = mRootActivityContainer.getDefaultDisplay();
         final ActivityStack homeStack =
                 defaultDisplay.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
-        defaultDisplay.positionChildAtTop(homeStack, false /* includingParents */);
+        defaultDisplay.positionStackAtTop(homeStack, false /* includingParents */);
         ActivityRecord topRunningHomeActivity = homeStack.topRunningActivityLocked();
         if (topRunningHomeActivity == null) {
             topRunningHomeActivity = new ActivityBuilder(mService)
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index e353903..112479b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -54,6 +54,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -64,6 +65,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class RemoteAnimationControllerTest extends WindowTestsBase {
 
     @Mock SurfaceControl mMockLeash;
@@ -84,7 +86,7 @@
         when(mMockRunner.asBinder()).thenReturn(new Binder());
         mAdapter = new RemoteAnimationAdapter(mMockRunner, 100, 50, true /* changeNeedsSnapshot */);
         mAdapter.setCallingPidUid(123, 456);
-        mWm.mH.runWithScissors(() -> mHandler = new TestHandler(null, mClock), 0);
+        runWithScissors(mWm.mH, () -> mHandler = new TestHandler(null, mClock), 0);
         mController = new RemoteAnimationController(mWm, mAdapter, mHandler);
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index e2bdf87..59c7c02 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -73,6 +73,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.function.Consumer;
 
 /**
  * Tests for the {@link RootActivityContainer} class.
@@ -149,9 +150,7 @@
         final Task task = stack.getAllTasks().get(0);
         final ArrayList<ActivityRecord> stackActivities = new ArrayList<>();
 
-        for (int i = 0; i < task.getChildCount(); i++) {
-            stackActivities.add(task.getChildAt(i));
-        }
+        task.forAllActivities((Consumer<ActivityRecord>) stackActivities::add, false);
 
         assertEquals("Expecting " + Arrays.deepToString(activities) + " got " + stackActivities,
                 stackActivities.size(), activities != null ? activities.length : 0);
@@ -227,20 +226,20 @@
     @Test
     public void testRemovingStackOnAppCrash() {
         final ActivityDisplay defaultDisplay = mRootActivityContainer.getDefaultDisplay();
-        final int originalStackCount = defaultDisplay.getChildCount();
+        final int originalStackCount = defaultDisplay.getStackCount();
         final ActivityStack stack = mRootActivityContainer.getDefaultDisplay().createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
         final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
                 .setStack(stack).build();
 
-        assertEquals(originalStackCount + 1, defaultDisplay.getChildCount());
+        assertEquals(originalStackCount + 1, defaultDisplay.getStackCount());
 
         // Let's pretend that the app has crashed.
         firstActivity.app.setThread(null);
         mRootActivityContainer.finishTopCrashedActivities(firstActivity.app, "test");
 
         // Verify that the stack was removed.
-        assertEquals(originalStackCount, defaultDisplay.getChildCount());
+        assertEquals(originalStackCount, defaultDisplay.getStackCount());
     }
 
     @Test
@@ -393,7 +392,7 @@
                 ACTIVITY_TYPE_STANDARD, false /* onTop */));
         final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
         final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
-        display.positionChildAtBottom(targetStack);
+        display.positionStackAtBottom(targetStack);
 
         // Assume the stack is not at the topmost position (e.g. behind always-on-top stacks) but it
         // is the current top focused stack.
@@ -494,7 +493,7 @@
         final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
         final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
         activity.setState(ActivityState.RESUMED, "test");
-        display.positionChildAtBottom(targetStack);
+        display.positionStackAtBottom(targetStack);
 
         // Assume the stack is at the topmost position
         assertFalse(targetStack.isTopStackOnDisplay());
diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
index eba2bc8..5c9ccae 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -74,7 +74,7 @@
         final int numTasks = 10;
         int activeTime = 0;
         for (int i = 0; i < numTasks; i++) {
-            createTask(display.getChildAt(i % numStacks), ".Task" + i, i, activeTime++);
+            createTask(display.getStackAt(i % numStacks), ".Task" + i, i, activeTime++);
         }
 
         // Ensure that the latest tasks were returned in order of decreasing last active time,
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
index c483489..3008a75 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
@@ -50,6 +50,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -63,6 +64,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class SurfaceAnimationRunnerTest extends WindowTestsBase {
 
     @Mock SurfaceControl mMockSurface;
@@ -98,6 +100,7 @@
         verify(mMockTransaction, atLeastOnce()).setMatrix(eq(mMockSurface), eq(m), any());
         verify(mMockTransaction, atLeastOnce()).setAlpha(eq(mMockSurface), eq(1.0f));
 
+        waitHandlerIdle(SurfaceAnimationThread.getHandler());
         mFinishCallbackLatch.await(1, SECONDS);
         assertFinishCallbackCalled();
 
@@ -176,6 +179,7 @@
         assertTrue(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
         mSurfaceAnimationRunner.continueStartingAnimations();
         waitUntilNextFrame();
+        waitHandlerIdle(SurfaceAnimationThread.getHandler());
         assertFalse(mSurfaceAnimationRunner.mRunningAnimations.isEmpty());
         mFinishCallbackLatch.await(1, SECONDS);
         assertFinishCallbackCalled();
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
index 979aab6..2894241 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -44,6 +44,7 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -56,6 +57,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class SurfaceAnimatorTest extends WindowTestsBase {
 
     @Mock AnimationAdapter mSpec;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 27ebd5a..9a91efe 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -53,6 +53,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -66,6 +67,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
     private static final Rect DISPLAY_BOUNDS = new Rect(/* left */ 0, /* top */ 0,
             /* right */ 1920, /* bottom */ 1080);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
index 9275512b..8970571 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
@@ -19,7 +19,6 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.server.wm.TaskPositioner.MIN_ASPECT;
 import static com.android.server.wm.WindowManagerService.dipToPixel;
@@ -33,7 +32,6 @@
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
-import android.app.IActivityTaskManager;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.util.DisplayMetrics;
@@ -46,6 +44,7 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Tests for the {@link TaskPositioner} class.
@@ -55,6 +54,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class TaskPositionerTests extends WindowTestsBase {
 
     private static final boolean DEBUGGING = false;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index c8f81f4..599edb1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -27,6 +27,7 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.util.DisplayMetrics.DENSITY_DEFAULT;
+import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_ENABLED;
 import static android.view.Surface.ROTATION_0;
 import static android.view.Surface.ROTATION_90;
 
@@ -36,7 +37,6 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.server.policy.WindowManagerPolicy.USER_ROTATION_FREE;
-import static com.android.server.wm.DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -471,8 +471,9 @@
         // Add an extra activity on top of the root one
         new ActivityBuilder(mService).setTask(task).build();
 
-        assertEquals("The root activity in the task must be reported.",
-                0, task.findRootIndex(false /* effectiveRoot*/));
+        assertEquals("The root activity in the task must be reported.", task.getChildAt(0),
+                task.getRootActivity(
+                        true /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
     }
 
     /**
@@ -483,14 +484,15 @@
     public void testFindRootIndex_finishing() {
         final Task task = getTestTask();
         // Add extra two activities and mark the two on the bottom as finishing.
-        final ActivityRecord activity0 = task.getChildAt(0);
+        final ActivityRecord activity0 = task.getBottomMostActivity();
         activity0.finishing = true;
         final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
         activity1.finishing = true;
         new ActivityBuilder(mService).setTask(task).build();
 
         assertEquals("The first non-finishing activity in the task must be reported.",
-                2, task.findRootIndex(false /* effectiveRoot*/));
+                task.getChildAt(2), task.getRootActivity(
+                        true /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
     }
 
     /**
@@ -504,7 +506,8 @@
         new ActivityBuilder(mService).setTask(task).build();
 
         assertEquals("The root activity in the task must be reported.",
-                0, task.findRootIndex(true /* effectiveRoot*/));
+                task.getChildAt(0), task.getRootActivity(
+                        false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
     }
 
     /**
@@ -516,14 +519,15 @@
         final Task task = getTestTask();
         // Add extra two activities. Mark the one on the bottom with "relinquishTaskIdentity" and
         // one above as finishing.
-        final ActivityRecord activity0 = task.getChildAt(0);
+        final ActivityRecord activity0 = task.getBottomMostActivity();
         activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
         final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
         activity1.finishing = true;
         new ActivityBuilder(mService).setTask(task).build();
 
         assertEquals("The first non-finishing activity and non-relinquishing task identity "
-                        + "must be reported.", 2, task.findRootIndex(true /* effectiveRoot*/));
+                + "must be reported.", task.getChildAt(2), task.getRootActivity(
+                        false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
     }
 
     /**
@@ -534,10 +538,11 @@
     public void testFindRootIndex_effectiveRoot_relinquishingAndSingleActivity() {
         final Task task = getTestTask();
         // Set relinquishTaskIdentity for the only activity in the task
-        task.getChildAt(0).info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
+        task.getBottomMostActivity().info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
 
         assertEquals("The root activity in the task must be reported.",
-                0, task.findRootIndex(true /* effectiveRoot*/));
+                task.getChildAt(0), task.getRootActivity(
+                        false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
     }
 
     /**
@@ -548,13 +553,14 @@
     public void testFindRootIndex_effectiveRoot_relinquishingMultipleActivities() {
         final Task task = getTestTask();
         // Set relinquishTaskIdentity for all activities in the task
-        final ActivityRecord activity0 = task.getChildAt(0);
+        final ActivityRecord activity0 = task.getBottomMostActivity();
         activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
         final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
         activity1.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
 
         assertEquals("The topmost activity in the task must be reported.",
-                task.getChildCount() - 1, task.findRootIndex(true /* effectiveRoot*/));
+                task.getChildAt(task.getChildCount() - 1), task.getRootActivity(
+                        false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
     }
 
     /** Test that bottom-most activity is reported in {@link Task#getRootActivity()}. */
@@ -565,7 +571,7 @@
         new ActivityBuilder(mService).setTask(task).build();
 
         assertEquals("The root activity in the task must be reported.",
-                task.getChildAt(0), task.getRootActivity());
+                task.getBottomMostActivity(), task.getRootActivity());
     }
 
     /**
@@ -577,7 +583,7 @@
         // Add an extra activity on top of the root one
         new ActivityBuilder(mService).setTask(task).build();
         // Mark the root as finishing
-        task.getChildAt(0).finishing = true;
+        task.getBottomMostActivity().finishing = true;
 
         assertEquals("The first non-finishing activity in the task must be reported.",
                 task.getChildAt(1), task.getRootActivity());
@@ -590,13 +596,13 @@
     public void testGetRootActivity_relinquishTaskIdentity() {
         final Task task = getTestTask();
         // Mark the bottom-most activity with FLAG_RELINQUISH_TASK_IDENTITY.
-        final ActivityRecord activity0 = task.getChildAt(0);
+        final ActivityRecord activity0 = task.getBottomMostActivity();
         activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
         // Add an extra activity on top of the root one.
         new ActivityBuilder(mService).setTask(task).build();
 
         assertEquals("The root activity in the task must be reported.",
-                task.getChildAt(0), task.getRootActivity());
+                task.getBottomMostActivity(), task.getRootActivity());
     }
 
     /**
@@ -607,7 +613,7 @@
     public void testGetRootActivity_allFinishing() {
         final Task task = getTestTask();
         // Mark the bottom-most activity as finishing.
-        final ActivityRecord activity0 = task.getChildAt(0);
+        final ActivityRecord activity0 = task.getBottomMostActivity();
         activity0.finishing = true;
         // Add an extra activity on top of the root one and mark it as finishing
         final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
@@ -623,7 +629,7 @@
     public void testIsRootActivity() {
         final Task task = getTestTask();
         // Mark the bottom-most activity as finishing.
-        final ActivityRecord activity0 = task.getChildAt(0);
+        final ActivityRecord activity0 = task.getBottomMostActivity();
         activity0.finishing = true;
         // Add an extra activity on top of the root one.
         final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
@@ -640,7 +646,7 @@
     public void testIsRootActivity_allFinishing() {
         final Task task = getTestTask();
         // Mark the bottom-most activity as finishing.
-        final ActivityRecord activity0 = task.getChildAt(0);
+        final ActivityRecord activity0 = task.getBottomMostActivity();
         activity0.finishing = true;
         // Add an extra activity on top of the root one and mark it as finishing
         final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
@@ -657,10 +663,10 @@
     @Test
     public void testGetTaskForActivity() {
         final Task task0 = getTestTask();
-        final ActivityRecord activity0 = task0.getChildAt(0);
+        final ActivityRecord activity0 = task0.getBottomMostActivity();
 
         final Task task1 = getTestTask();
-        final ActivityRecord activity1 = task1.getChildAt(0);
+        final ActivityRecord activity1 = task1.getBottomMostActivity();
 
         assertEquals(task0.mTaskId,
                 ActivityRecord.getTaskForActivityLocked(activity0.appToken, false /* onlyRoot */));
@@ -676,7 +682,7 @@
     public void testGetTaskForActivity_onlyRoot_finishing() {
         final Task task = getTestTask();
         // Make the current root activity finishing
-        final ActivityRecord activity0 = task.getChildAt(0);
+        final ActivityRecord activity0 = task.getBottomMostActivity();
         activity0.finishing = true;
         // Add an extra activity on top - this will be the new root
         final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
@@ -699,7 +705,7 @@
     public void testGetTaskForActivity_onlyRoot_relinquishTaskIdentity() {
         final Task task = getTestTask();
         // Make the current root activity relinquish task identity
-        final ActivityRecord activity0 = task.getChildAt(0);
+        final ActivityRecord activity0 = task.getBottomMostActivity();
         activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
         // Add an extra activity on top - this will be the new root
         final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
@@ -722,7 +728,7 @@
     public void testGetTaskForActivity_notOnlyRoot() {
         final Task task = getTestTask();
         // Mark the bottom-most activity as finishing.
-        final ActivityRecord activity0 = task.getChildAt(0);
+        final ActivityRecord activity0 = task.getBottomMostActivity();
         activity0.finishing = true;
 
         // Add an extra activity on top of the root one and make it relinquish task identity
@@ -747,7 +753,7 @@
     public void testUpdateEffectiveIntent() {
         // Test simple case with a single activity.
         final Task task = getTestTask();
-        final ActivityRecord activity0 = task.getChildAt(0);
+        final ActivityRecord activity0 = task.getBottomMostActivity();
 
         spyOn(task);
         task.updateEffectiveIntent();
@@ -762,7 +768,7 @@
     public void testUpdateEffectiveIntent_rootFinishing() {
         // Test simple case with a single activity.
         final Task task = getTestTask();
-        final ActivityRecord activity0 = task.getChildAt(0);
+        final ActivityRecord activity0 = task.getBottomMostActivity();
         // Mark the bottom-most activity as finishing.
         activity0.finishing = true;
         // Add an extra activity on top of the root one
@@ -782,7 +788,7 @@
     public void testUpdateEffectiveIntent_allFinishing() {
         // Test simple case with a single activity.
         final Task task = getTestTask();
-        final ActivityRecord activity0 = task.getChildAt(0);
+        final ActivityRecord activity0 = task.getBottomMostActivity();
         // Mark the bottom-most activity as finishing.
         activity0.finishing = true;
         // Add an extra activity on top of the root one and make it relinquish task identity
@@ -818,7 +824,7 @@
                 task.getResolvedOverrideConfiguration().windowConfiguration.getAppBounds());
     }
 
-    private byte[] serializeToBytes(Task r) throws IOException, XmlPullParserException {
+    private byte[] serializeToBytes(Task r) throws Exception {
         try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
             final XmlSerializer serializer = Xml.newSerializer();
             serializer.setOutput(os, "UTF-8");
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotCacheTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotCacheTest.java
index f595e05..0274b7d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotCacheTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotCacheTest.java
@@ -18,21 +18,21 @@
 
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
 import static junit.framework.Assert.assertEquals;
 
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.app.ActivityManager.TaskSnapshot;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
 
-import android.app.ActivityManager.TaskSnapshot;
-
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 /**
  * Test class for {@link TaskSnapshotCache}.
@@ -42,6 +42,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class TaskSnapshotCacheTest extends TaskSnapshotPersisterTestBase {
 
     private TaskSnapshotCache mCache;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index 3b11003..6ebaf29 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -33,6 +33,7 @@
 import com.google.android.collect.Sets;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test class for {@link TaskSnapshotController}.
@@ -42,6 +43,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class TaskSnapshotControllerTest extends WindowTestsBase {
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
index b29453a..b5a5790 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
@@ -38,6 +38,7 @@
 import com.android.server.wm.TaskSnapshotPersister.RemoveObsoleteFilesQueueItem;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.io.File;
 import java.util.function.Predicate;
@@ -50,6 +51,7 @@
  */
 @MediumTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBase {
 
     private static final Rect TEST_INSETS = new Rect(10, 20, 30, 40);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index 74db820..817344f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -47,6 +47,7 @@
 import com.android.server.wm.TaskSnapshotSurface.Window;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test class for {@link TaskSnapshotSurface}.
@@ -56,6 +57,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class TaskSnapshotSurfaceTest extends WindowTestsBase {
 
     private TaskSnapshotSurface mSurface;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
index dbf61db..6ad9f74 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -19,6 +19,9 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
@@ -112,6 +115,10 @@
 
     @Test
     public void testDisplayPositionWithPinnedStack() {
+        // Make sure the display is system owned display which capable to move the stack to top.
+        spyOn(mDisplayContent);
+        doReturn(false).when(mDisplayContent).isUntrustedVirtualDisplay();
+
         // The display contains pinned stack that was added in {@link #setUp}.
         final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
         final Task task = createTaskInStack(stack, 0 /* userId */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index aa6c14e..634d2f0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -368,7 +368,7 @@
     }
 
     @Override
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
     }
 
     @Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java
index 64ac547..c359fb1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java
@@ -48,6 +48,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test class to for {@link android.app.WindowConfiguration}.
@@ -57,6 +58,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class WindowConfigurationTests extends WindowTestsBase {
     private Rect mParentBounds;
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 8140045..13cf22d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -56,6 +56,7 @@
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mockito;
 
 import java.util.Comparator;
@@ -68,6 +69,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class WindowContainerTests extends WindowTestsBase {
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java
index 4b666f5..8936aad 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTraversalTests.java
@@ -31,6 +31,7 @@
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.function.Consumer;
 
@@ -42,6 +43,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class WindowContainerTraversalTests extends WindowTestsBase {
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
index 1c9eed2..ce6efdf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
@@ -32,6 +32,7 @@
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test for {@link WindowManagerService.SettingsObserver}.
@@ -40,6 +41,7 @@
  *  atest WmTests:WindowManagerSettingsTests
  */
 @SmallTest
+@RunWith(WindowTestRunner.class)
 public class WindowManagerSettingsTests extends WindowTestsBase {
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index eed5ef5..72baedb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -222,7 +222,8 @@
         final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow");
         final WindowState imeWindow = createWindow(null, TYPE_INPUT_METHOD, "imeWindow");
 
-        // Setting FLAG_NOT_FOCUSABLE prevents the window from being an IME target.
+        // Setting FLAG_NOT_FOCUSABLE without FLAG_ALT_FOCUSABLE_IM prevents the window from being
+        // an IME target.
         appWindow.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
         imeWindow.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
 
@@ -230,7 +231,7 @@
         appWindow.setHasSurface(true);
         imeWindow.setHasSurface(true);
 
-        // Windows with FLAG_NOT_FOCUSABLE can't be IME targets
+        // Windows without flags (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM) can't be IME targets
         assertFalse(appWindow.canBeImeTarget());
         assertFalse(imeWindow.canBeImeTarget());
 
@@ -238,16 +239,10 @@
         appWindow.mAttrs.flags |= (FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM);
         imeWindow.mAttrs.flags |= (FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM);
 
-        // Visible app window with flags FLAG_NOT_FOCUSABLE or FLAG_ALT_FOCUSABLE_IM can't be IME
-        // target while an IME window can never be an IME target regardless of its visibility
-        // or flags.
-        assertFalse(appWindow.canBeImeTarget());
-        assertFalse(imeWindow.canBeImeTarget());
-
-        appWindow.mAttrs.flags &= ~FLAG_ALT_FOCUSABLE_IM;
-        assertFalse(appWindow.canBeImeTarget());
-        appWindow.mAttrs.flags &= ~FLAG_NOT_FOCUSABLE;
+        // Visible app window with flags can be IME target while an IME window can never be an IME
+        // target regardless of its visibility or flags.
         assertTrue(appWindow.canBeImeTarget());
+        assertFalse(imeWindow.canBeImeTarget());
 
         // Make windows invisible
         appWindow.hideLw(false /* doAnimation */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 437b84b..22ba90b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -320,7 +320,7 @@
         synchronized (mWm.mGlobalLock) {
             return new ActivityTestsBase.StackBuilder(
                     dc.mWmService.mAtmService.mRootActivityContainer)
-                    .setDisplay(dc.mActivityDisplay)
+                    .setDisplay(dc)
                     .setWindowingMode(windowingMode)
                     .setActivityType(activityType)
                     .setCreateActivity(false)
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
index 4cdbea0..e6aed49 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
@@ -31,6 +31,7 @@
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Tests for the {@link WindowToken} class.
@@ -40,6 +41,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class WindowTokenTests extends WindowTestsBase {
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
index e3691c6..c183403 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
@@ -125,7 +125,7 @@
     public void trace_dumpsWindowManagerState_whenTracing() throws Exception {
         mWindowTracing.startTrace(mock(PrintWriter.class));
         mWindowTracing.logState("where");
-        verify(mWmMock, times(2)).writeToProtoLocked(any(), eq(WindowTraceLogLevel.TRIM));
+        verify(mWmMock, times(2)).dumpDebugLocked(any(), eq(WindowTraceLogLevel.TRIM));
     }
 
     @Test
@@ -151,7 +151,7 @@
             inv.<ProtoOutputStream>getArgument(0).write(
                     WindowManagerTraceProto.WHERE, "TEST_WM_PROTO");
             return null;
-        }).when(mWmMock).writeToProtoLocked(any(), any());
+        }).when(mWmMock).dumpDebugLocked(any(), any());
         mWindowTracing.logState("TEST_WHERE");
 
         mWindowTracing.stopTrace(mock(PrintWriter.class));
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index 46b261b..8fb283a 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -448,8 +448,11 @@
     /**
      * Parses all of the tokens to strings in the obfuscated usage stats data. This includes
      * deobfuscating each of the package tokens and chooser actions and categories.
+     *
+     * @return {@code true} if any stats were omitted while deobfuscating, {@code false} otherwise.
      */
-    private void deobfuscateUsageStats(PackagesTokenData packagesTokenData) {
+    private boolean deobfuscateUsageStats(PackagesTokenData packagesTokenData) {
+        boolean dataOmitted = false;
         final int usageStatsSize = packageStatsObfuscated.size();
         for (int statsIndex = 0; statsIndex < usageStatsSize; statsIndex++) {
             final int packageToken = packageStatsObfuscated.keyAt(statsIndex);
@@ -457,6 +460,7 @@
             usageStats.mPackageName = packagesTokenData.getPackageString(packageToken);
             if (usageStats.mPackageName == null) {
                 Slog.e(TAG, "Unable to parse usage stats package " + packageToken);
+                dataOmitted = true;
                 continue;
             }
 
@@ -489,14 +493,18 @@
             }
             packageStats.put(usageStats.mPackageName, usageStats);
         }
+        return dataOmitted;
     }
 
     /**
      * Parses all of the tokens to strings in the obfuscated events data. This includes
      * deobfuscating the package token, along with any class, task root package/class tokens, and
      * shortcut or notification channel tokens.
+     *
+     * @return {@code true} if any events were omitted while deobfuscating, {@code false} otherwise.
      */
-    private void deobfuscateEvents(PackagesTokenData packagesTokenData) {
+    private boolean deobfuscateEvents(PackagesTokenData packagesTokenData) {
+        boolean dataOmitted = false;
         for (int i = this.events.size() - 1; i >= 0; i--) {
             final Event event = this.events.get(i);
             final int packageToken = event.mPackageToken;
@@ -504,6 +512,7 @@
             if (event.mPackage == null) {
                 Slog.e(TAG, "Unable to parse event package " + packageToken);
                 this.events.remove(i);
+                dataOmitted = true;
                 continue;
             }
 
@@ -543,6 +552,7 @@
                         Slog.e(TAG, "Unable to parse shortcut " + event.mShortcutIdToken
                                 + " for package " + packageToken);
                         this.events.remove(i);
+                        dataOmitted = true;
                         continue;
                     }
                     break;
@@ -554,21 +564,25 @@
                                 + event.mNotificationChannelIdToken + " for package "
                                 + packageToken);
                         this.events.remove(i);
+                        dataOmitted = true;
                         continue;
                     }
                     break;
             }
         }
+        return dataOmitted;
     }
 
     /**
      * Parses the obfuscated tokenized data held in this interval stats object.
      *
+     * @return {@code true} if any data was omitted while deobfuscating, {@code false} otherwise.
      * @hide
      */
-    public void deobfuscateData(PackagesTokenData packagesTokenData) {
-        deobfuscateUsageStats(packagesTokenData);
-        deobfuscateEvents(packagesTokenData);
+    public boolean deobfuscateData(PackagesTokenData packagesTokenData) {
+        final boolean statsOmitted = deobfuscateUsageStats(packagesTokenData);
+        final boolean eventsOmitted = deobfuscateEvents(packagesTokenData);
+        return statsOmitted || eventsOmitted;
     }
 
     /**
diff --git a/services/usage/java/com/android/server/usage/PackagesTokenData.java b/services/usage/java/com/android/server/usage/PackagesTokenData.java
index 4bf08a4..f19abbb 100644
--- a/services/usage/java/com/android/server/usage/PackagesTokenData.java
+++ b/services/usage/java/com/android/server/usage/PackagesTokenData.java
@@ -162,15 +162,18 @@
      *
      * @param packageName the package to be removed
      * @param timeRemoved the time stamp of when the package was removed
+     * @return the token mapped to the package removed or {@code PackagesTokenData.UNASSIGNED_TOKEN}
+     *         if not mapped
      */
-    public void removePackage(String packageName, long timeRemoved) {
+    public int removePackage(String packageName, long timeRemoved) {
         removedPackagesMap.put(packageName, timeRemoved);
 
         if (!packagesToTokensMap.containsKey(packageName)) {
-            return;
+            return UNASSIGNED_TOKEN;
         }
         final int packageToken = packagesToTokensMap.get(packageName).get(packageName);
         packagesToTokensMap.remove(packageName);
         tokensToPackagesMap.delete(packageToken);
+        return packageToken;
     }
 }
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index 27d7360..ef9a73b 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -29,6 +29,7 @@
 import android.util.TimeUtils;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.IndentingPrintWriter;
 
 import libcore.io.IoUtils;
@@ -52,6 +53,7 @@
 import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 
 /**
@@ -122,6 +124,7 @@
     private int mCurrentVersion;
     private boolean mFirstUpdate;
     private boolean mNewUpdate;
+    private boolean mUpgradePerformed;
 
     // The obfuscated packages to tokens mappings file
     private final File mPackageMappingsFile;
@@ -226,14 +229,14 @@
             }
 
             try {
-                IntervalStats stats = new IntervalStats();
                 for (int i = start; i < fileCount - 1; i++) {
+                    final IntervalStats stats = new IntervalStats();
                     readLocked(files.valueAt(i), stats);
                     if (!checkinAction.checkin(stats)) {
                         return false;
                     }
                 }
-            } catch (IOException e) {
+            } catch (Exception e) {
                 Slog.e(TAG, "Failed to check-in", e);
                 return false;
             }
@@ -325,6 +328,13 @@
         return mNewUpdate;
     }
 
+    /**
+     * Was an upgrade performed when this database was initialized?
+     */
+    boolean wasUpgradePerformed() {
+        return mUpgradePerformed;
+    }
+
     private void checkVersionAndBuildLocked() {
         int version;
         String buildFingerprint;
@@ -397,6 +407,8 @@
         if (mUpdateBreadcrumb.exists()) {
             // Files should be up to date with current version. Clear the version update breadcrumb
             mUpdateBreadcrumb.delete();
+            // update mUpgradePerformed after breadcrumb is deleted to indicate a successful upgrade
+            mUpgradePerformed = true;
         }
 
         if (mBackupsDir.exists() && !KEEP_BACKUP_DIR) {
@@ -545,12 +557,127 @@
         }
     }
 
-    void onPackageRemoved(String packageName, long timeRemoved) {
+    /**
+     * Returns the token mapped to the package removed or {@code PackagesTokenData.UNASSIGNED_TOKEN}
+     * if not mapped.
+     */
+    int onPackageRemoved(String packageName, long timeRemoved) {
         synchronized (mLock) {
-            mPackagesTokenData.removePackage(packageName, timeRemoved);
+            final int tokenRemoved = mPackagesTokenData.removePackage(packageName, timeRemoved);
+            try {
+                writeMappingsLocked();
+            } catch (Exception e) {
+                Slog.w(TAG, "Unable to update package mappings on disk after removing token "
+                        + tokenRemoved);
+            }
+            return tokenRemoved;
         }
     }
 
+    /**
+     * Reads all the usage stats data on disk and rewrites it with any data related to uninstalled
+     * packages omitted. Returns {@code true} on success, {@code false} otherwise.
+     */
+    boolean pruneUninstalledPackagesData() {
+        synchronized (mLock) {
+            for (int i = 0; i < mIntervalDirs.length; i++) {
+                final File[] files = mIntervalDirs[i].listFiles();
+                if (files == null) {
+                    continue;
+                }
+                for (int j = 0; j < files.length; j++) {
+                    try {
+                        final IntervalStats stats = new IntervalStats();
+                        final AtomicFile atomicFile = new AtomicFile(files[j]);
+                        if (!readLocked(atomicFile, stats, mCurrentVersion, mPackagesTokenData)) {
+                            continue; // no data was omitted when read so no need to rewrite
+                        }
+                        // Any data related to packages that have been removed would have failed
+                        // the deobfuscation step on read so the IntervalStats object here only
+                        // contains data for packages that are currently installed - all we need
+                        // to do here is write the data back to disk.
+                        writeLocked(atomicFile, stats, mCurrentVersion, mPackagesTokenData);
+                    } catch (Exception e) {
+                        Slog.e(TAG, "Failed to prune data from: " + files[j].toString());
+                        return false;
+                    }
+                }
+            }
+
+            try {
+                writeMappingsLocked();
+            } catch (IOException e) {
+                Slog.e(TAG, "Failed to write package mappings after pruning data.");
+                return false;
+            }
+            return true;
+        }
+    }
+
+    /**
+     * Iterates through all the files on disk and prunes any data that belongs to packages that have
+     * been uninstalled (packages that are not in the given list).
+     * Note: this should only be called once, when there has been a database upgrade.
+     *
+     * @param installedPackages map of installed packages (package_name:package_install_time)
+     */
+    void prunePackagesDataOnUpgrade(HashMap<String, Long> installedPackages) {
+        if (ArrayUtils.isEmpty(installedPackages)) {
+            return;
+        }
+        synchronized (mLock) {
+            for (int i = 0; i < mIntervalDirs.length; i++) {
+                final File[] files = mIntervalDirs[i].listFiles();
+                if (files == null) {
+                    continue;
+                }
+                for (int j = 0; j < files.length; j++) {
+                    try {
+                        final IntervalStats stats = new IntervalStats();
+                        final AtomicFile atomicFile = new AtomicFile(files[j]);
+                        readLocked(atomicFile, stats, mCurrentVersion, mPackagesTokenData);
+                        if (!pruneStats(installedPackages, stats)) {
+                            continue; // no stats were pruned so no need to rewrite
+                        }
+                        writeLocked(atomicFile, stats, mCurrentVersion, mPackagesTokenData);
+                    } catch (Exception e) {
+                        Slog.e(TAG, "Failed to prune data from: " + files[j].toString());
+                    }
+                }
+            }
+        }
+    }
+
+    private boolean pruneStats(HashMap<String, Long> installedPackages, IntervalStats stats) {
+        boolean dataPruned = false;
+
+        // prune old package usage stats
+        for (int i = stats.packageStats.size() - 1; i >= 0; i--) {
+            final UsageStats usageStats = stats.packageStats.valueAt(i);
+            final Long timeInstalled = installedPackages.get(usageStats.mPackageName);
+            if (timeInstalled == null || timeInstalled > usageStats.mEndTimeStamp) {
+                stats.packageStats.removeAt(i);
+                dataPruned = true;
+            }
+        }
+        if (dataPruned) {
+            // ensure old stats don't linger around during the obfuscation step on write
+            stats.packageStatsObfuscated.clear();
+        }
+
+        // prune old events
+        for (int i = stats.events.size() - 1; i >= 0; i--) {
+            final UsageEvents.Event event = stats.events.get(i);
+            final Long timeInstalled = installedPackages.get(event.mPackage);
+            if (timeInstalled == null || timeInstalled > event.mTimeStamp) {
+                stats.events.remove(i);
+                dataPruned = true;
+            }
+        }
+
+        return dataPruned;
+    }
+
     public void onTimeChanged(long timeDiffMillis) {
         synchronized (mLock) {
             StringBuilder logBuilder = new StringBuilder();
@@ -617,7 +744,7 @@
                 IntervalStats stats = new IntervalStats();
                 readLocked(f, stats);
                 return stats;
-            } catch (IOException e) {
+            } catch (Exception e) {
                 Slog.e(TAG, "Failed to read usage stats file", e);
             }
         }
@@ -645,7 +772,6 @@
         }
 
         // filter out events
-        final int eventsSize = stats.events.size();
         for (int i = stats.events.size() - 1; i >= 0; i--) {
             final UsageEvents.Event event = stats.events.get(i);
             final Long timeRemoved = removedPackagesMap.get(event.mPackage);
@@ -722,10 +848,10 @@
                 }
             }
 
-            final IntervalStats stats = new IntervalStats();
             final ArrayList<T> results = new ArrayList<>();
             for (int i = startIndex; i <= endIndex; i++) {
                 final AtomicFile f = intervalStats.valueAt(i);
+                final IntervalStats stats = new IntervalStats();
 
                 if (DEBUG) {
                     Slog.d(TAG, "Reading stat file " + f.getBaseFile().getAbsolutePath());
@@ -736,7 +862,7 @@
                     if (beginTime < stats.endTime) {
                         combiner.combine(stats, false, results);
                     }
-                } catch (IOException e) {
+                } catch (Exception e) {
                     Slog.e(TAG, "Failed to read usage stats file", e);
                     // We continue so that we return results that are not
                     // corrupt.
@@ -883,7 +1009,8 @@
         }
     }
 
-    private void writeLocked(AtomicFile file, IntervalStats stats) throws IOException {
+    private void writeLocked(AtomicFile file, IntervalStats stats)
+            throws IOException, RuntimeException {
         if (mCurrentVersion <= 3) {
             Slog.wtf(TAG, "Attempting to write UsageStats as XML with version " + mCurrentVersion);
             return;
@@ -892,7 +1019,7 @@
     }
 
     private static void writeLocked(AtomicFile file, IntervalStats stats, int version,
-            PackagesTokenData packagesTokenData) throws IOException {
+            PackagesTokenData packagesTokenData) throws IOException, RuntimeException {
         FileOutputStream fos = file.startWrite();
         try {
             writeLocked(fos, stats, version, packagesTokenData);
@@ -905,7 +1032,7 @@
     }
 
     private static void writeLocked(OutputStream out, IntervalStats stats, int version,
-            PackagesTokenData packagesTokenData) throws IOException {
+            PackagesTokenData packagesTokenData) throws RuntimeException {
         switch (version) {
             case 1:
             case 2:
@@ -915,7 +1042,7 @@
             case 4:
                 try {
                     UsageStatsProto.write(out, stats);
-                } catch (IOException | IllegalArgumentException e) {
+                } catch (Exception e) {
                     Slog.e(TAG, "Unable to write interval stats to proto.", e);
                 }
                 break;
@@ -923,7 +1050,7 @@
                 stats.obfuscateData(packagesTokenData);
                 try {
                     UsageStatsProtoV2.write(out, stats);
-                } catch (IOException | IllegalArgumentException e) {
+                } catch (Exception e) {
                     Slog.e(TAG, "Unable to write interval stats to proto.", e);
                 }
                 break;
@@ -934,7 +1061,13 @@
         }
     }
 
-    private void readLocked(AtomicFile file, IntervalStats statsOut) throws IOException {
+    /**
+     * Note: the data read from the given file will add to the IntervalStats object passed into this
+     * method. It is up to the caller to ensure that this is the desired behavior - if not, the
+     * caller should ensure that the data in the reused object is being cleared.
+     */
+    private void readLocked(AtomicFile file, IntervalStats statsOut)
+            throws IOException, RuntimeException {
         if (mCurrentVersion <= 3) {
             Slog.wtf(TAG, "Reading UsageStats as XML; current database version: "
                     + mCurrentVersion);
@@ -942,13 +1075,21 @@
         readLocked(file, statsOut, mCurrentVersion, mPackagesTokenData);
     }
 
-    private static void readLocked(AtomicFile file, IntervalStats statsOut, int version,
-            PackagesTokenData packagesTokenData) throws IOException {
+    /**
+     * Returns {@code true} if any stats were omitted while reading, {@code false} otherwise.
+     * <p/>
+     * Note: the data read from the given file will add to the IntervalStats object passed into this
+     * method. It is up to the caller to ensure that this is the desired behavior - if not, the
+     * caller should ensure that the data in the reused object is being cleared.
+     */
+    private static boolean readLocked(AtomicFile file, IntervalStats statsOut, int version,
+            PackagesTokenData packagesTokenData) throws IOException, RuntimeException {
+        boolean dataOmitted = false;
         try {
             FileInputStream in = file.openRead();
             try {
                 statsOut.beginTime = parseBeginTime(file);
-                readLocked(in, statsOut, version, packagesTokenData);
+                dataOmitted = readLocked(in, statsOut, version, packagesTokenData);
                 statsOut.lastTimeSaved = file.getLastModifiedTime();
             } finally {
                 try {
@@ -961,10 +1102,19 @@
             Slog.e(TAG, "UsageStatsDatabase", e);
             throw e;
         }
+        return dataOmitted;
     }
 
-    private static void readLocked(InputStream in, IntervalStats statsOut, int version,
-            PackagesTokenData packagesTokenData) throws IOException {
+    /**
+     * Returns {@code true} if any stats were omitted while reading, {@code false} otherwise.
+     * <p/>
+     * Note: the data read from the given file will add to the IntervalStats object passed into this
+     * method. It is up to the caller to ensure that this is the desired behavior - if not, the
+     * caller should ensure that the data in the reused object is being cleared.
+     */
+    private static boolean readLocked(InputStream in, IntervalStats statsOut, int version,
+            PackagesTokenData packagesTokenData) throws RuntimeException {
+        boolean dataOmitted = false;
         switch (version) {
             case 1:
             case 2:
@@ -979,24 +1129,24 @@
             case 4:
                 try {
                     UsageStatsProto.read(in, statsOut);
-                } catch (IOException e) {
+                } catch (Exception e) {
                     Slog.e(TAG, "Unable to read interval stats from proto.", e);
                 }
                 break;
             case 5:
                 try {
                     UsageStatsProtoV2.read(in, statsOut);
-                } catch (IOException e) {
+                } catch (Exception e) {
                     Slog.e(TAG, "Unable to read interval stats from proto.", e);
                 }
-                statsOut.deobfuscateData(packagesTokenData);
+                dataOmitted = statsOut.deobfuscateData(packagesTokenData);
                 break;
             default:
                 throw new RuntimeException(
                         "Unhandled UsageStatsDatabase version: " + Integer.toString(version)
                                 + " on read.");
         }
-
+        return dataOmitted;
     }
 
     /**
@@ -1010,7 +1160,7 @@
 
         try (FileInputStream in = new AtomicFile(mPackageMappingsFile).openRead()) {
             UsageStatsProtoV2.readObfuscatedData(in, mPackagesTokenData);
-        } catch (IOException e) {
+        } catch (Exception e) {
             Slog.e(TAG, "Failed to read the obfuscated packages mapping file.", e);
             return;
         }
@@ -1039,7 +1189,7 @@
             UsageStatsProtoV2.writeObfuscatedData(fos, mPackagesTokenData);
             file.finishWrite(fos);
             fos = null;
-        } catch (IOException | IllegalArgumentException e) {
+        } catch (Exception e) {
             Slog.e(TAG, "Unable to write obfuscated data to proto.", e);
         } finally {
             file.failWrite(fos);
@@ -1279,8 +1429,8 @@
         try {
             stats.beginTime = in.readLong();
             readLocked(in, stats, version, mPackagesTokenData);
-        } catch (IOException ioe) {
-            Slog.d(TAG, "DeSerializing IntervalStats Failed", ioe);
+        } catch (Exception e) {
+            Slog.d(TAG, "DeSerializing IntervalStats Failed", e);
             stats = null;
         }
         return stats;
diff --git a/services/usage/java/com/android/server/usage/UsageStatsIdleService.java b/services/usage/java/com/android/server/usage/UsageStatsIdleService.java
new file mode 100644
index 0000000..4468871
--- /dev/null
+++ b/services/usage/java/com/android/server/usage/UsageStatsIdleService.java
@@ -0,0 +1,92 @@
+/*
+ * 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.usage;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.app.usage.UsageStatsManagerInternal;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.PersistableBundle;
+
+import com.android.server.LocalServices;
+
+/**
+ * JobService used to do any work for UsageStats while the device is idle.
+ */
+public class UsageStatsIdleService extends JobService {
+
+    /**
+     * Base job ID for the pruning job - must be unique within the system server uid.
+     */
+    private static final int PRUNE_JOB_ID = 546357475;
+
+    private static final String USER_ID_KEY = "user_id";
+
+    static void scheduleJob(Context context, int userId) {
+        final int userJobId = PRUNE_JOB_ID + userId; // unique job id per user
+        final ComponentName component = new ComponentName(context.getPackageName(),
+                UsageStatsIdleService.class.getName());
+        final PersistableBundle bundle = new PersistableBundle();
+        bundle.putInt(USER_ID_KEY, userId);
+        final JobInfo pruneJob = new JobInfo.Builder(userJobId, component)
+                .setRequiresDeviceIdle(true)
+                .setExtras(bundle)
+                .setPersisted(true)
+                .build();
+
+        final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
+        final JobInfo pendingPruneJob = jobScheduler.getPendingJob(userJobId);
+        // only schedule a new prune job if one doesn't exist already for this user
+        if (!pruneJob.equals(pendingPruneJob)) {
+            jobScheduler.cancel(userJobId); // cancel any previously scheduled prune job
+            jobScheduler.schedule(pruneJob);
+        }
+
+    }
+
+    static void cancelJob(Context context, int userId) {
+        final int userJobId = PRUNE_JOB_ID + userId; // unique job id per user
+        final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
+        jobScheduler.cancel(userJobId);
+    }
+
+    @Override
+    public boolean onStartJob(JobParameters params) {
+        final PersistableBundle bundle = params.getExtras();
+        final int userId = bundle.getInt(USER_ID_KEY, -1);
+        if (userId == -1) {
+            return false;
+        }
+
+        AsyncTask.execute(() -> {
+            final UsageStatsManagerInternal usageStatsManagerInternal = LocalServices.getService(
+                    UsageStatsManagerInternal.class);
+            final boolean pruned = usageStatsManagerInternal.pruneUninstalledPackagesData(userId);
+            jobFinished(params, !pruned); // reschedule if data was not pruned
+        });
+        return true;
+    }
+
+    @Override
+    public boolean onStopJob(JobParameters params) {
+        // Since the pruning job isn't a heavy job, we don't want to cancel it's execution midway.
+        return false;
+    }
+}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsProto.java b/services/usage/java/com/android/server/usage/UsageStatsProto.java
index 87e077e..932784d 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsProto.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsProto.java
@@ -410,7 +410,7 @@
             final IntervalStats stats, final ConfigurationStats configStats, boolean isActive)
             throws IllegalArgumentException {
         final long token = proto.start(fieldId);
-        configStats.mConfiguration.writeToProto(proto, IntervalStatsProto.Configuration.CONFIG);
+        configStats.mConfiguration.dumpDebug(proto, IntervalStatsProto.Configuration.CONFIG);
         proto.write(IntervalStatsProto.Configuration.LAST_TIME_ACTIVE_MS,
                 configStats.mLastTimeActive - stats.beginTime);
         proto.write(IntervalStatsProto.Configuration.TOTAL_TIME_ACTIVE_MS,
@@ -460,7 +460,7 @@
         switch (event.mEventType) {
             case UsageEvents.Event.CONFIGURATION_CHANGE:
                 if (event.mConfiguration != null) {
-                    event.mConfiguration.writeToProto(proto, IntervalStatsProto.Event.CONFIG);
+                    event.mConfiguration.dumpDebug(proto, IntervalStatsProto.Event.CONFIG);
                 }
                 break;
             case UsageEvents.Event.SHORTCUT_INVOCATION:
diff --git a/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java b/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java
index b68e04f..fe5da92 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java
@@ -355,7 +355,7 @@
     private static void writeConfigStats(ProtoOutputStream proto, final long statsBeginTime,
             final ConfigurationStats configStats, boolean isActive)
             throws IllegalArgumentException {
-        configStats.mConfiguration.writeToProto(proto,
+        configStats.mConfiguration.dumpDebug(proto,
                 IntervalStatsObfuscatedProto.Configuration.CONFIG);
         proto.write(IntervalStatsObfuscatedProto.Configuration.LAST_TIME_ACTIVE_MS,
                 configStats.mLastTimeActive - statsBeginTime);
@@ -385,7 +385,7 @@
         switch (event.mEventType) {
             case UsageEvents.Event.CONFIGURATION_CHANGE:
                 if (event.mConfiguration != null) {
-                    event.mConfiguration.writeToProto(proto, EventObfuscatedProto.CONFIG);
+                    event.mConfiguration.dumpDebug(proto, EventObfuscatedProto.CONFIG);
                 }
                 break;
             case UsageEvents.Event.STANDBY_BUCKET_CHANGED:
@@ -749,7 +749,7 @@
         switch (event.mEventType) {
             case UsageEvents.Event.CONFIGURATION_CHANGE:
                 if (event.mConfiguration != null) {
-                    event.mConfiguration.writeToProto(proto, PendingEventProto.CONFIG);
+                    event.mConfiguration.dumpDebug(proto, PendingEventProto.CONFIG);
                 }
                 break;
             case UsageEvents.Event.STANDBY_BUCKET_CHANGED:
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index ba4a448..c900f38 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -52,6 +52,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.ParceledListSlice;
@@ -99,6 +100,7 @@
 import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
@@ -318,6 +320,8 @@
     }
 
     private void onUserUnlocked(int userId) {
+        // fetch the installed packages outside the lock so it doesn't block package manager.
+        final HashMap<String, Long> installedPackages = getInstalledPackages(userId);
         synchronized (mLock) {
             // Create a user unlocked event to report
             final Event unlockEvent = new Event(USER_UNLOCKED, SystemClock.elapsedRealtime());
@@ -334,9 +338,10 @@
             }
             boolean needToFlush = !pendingEvents.isEmpty();
 
+            initializeUserUsageStatsServiceLocked(userId, System.currentTimeMillis(),
+                    installedPackages);
             mUserUnlockedStates.put(userId, true);
-            final UserUsageStatsService userService = getUserDataAndInitializeIfNeededLocked(
-                    userId, System.currentTimeMillis());
+            final UserUsageStatsService userService = getUserUsageStatsServiceLocked(userId);
             if (userService == null) {
                 Slog.i(TAG, "Attempted to unlock stopped or removed user " + userId);
                 return;
@@ -361,6 +366,29 @@
         }
     }
 
+    /**
+     * Fetches a map (package_name:install_time) of installed packages for the given user. This
+     * map contains all installed packages, including those packages which have been uninstalled
+     * with the DONT_DELETE_DATA flag.
+     * This is a helper method which should only be called when the given user's usage stats service
+     * is initialized; it performs a heavy query to package manager so do not call it otherwise.
+     * <br/>
+     * Note: DO NOT call this while holding the usage stats lock ({@code mLock}).
+     */
+    private HashMap<String, Long> getInstalledPackages(int userId) {
+        if (mPackageManager == null) {
+            return null;
+        }
+        final List<PackageInfo> installedPackages = mPackageManager.getInstalledPackagesAsUser(
+                PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
+        final HashMap<String, Long> packagesMap = new HashMap<>();
+        for (int i = installedPackages.size() - 1; i >= 0; i--) {
+            final PackageInfo packageInfo = installedPackages.get(i);
+            packagesMap.put(packageInfo.packageName, packageInfo.firstInstallTime);
+        }
+        return packagesMap;
+    }
+
     private DevicePolicyManagerInternal getDpmInternal() {
         if (mDpmInternal == null) {
             mDpmInternal = LocalServices.getService(DevicePolicyManagerInternal.class);
@@ -450,31 +478,42 @@
         }
     }
 
-    private UserUsageStatsService getUserDataAndInitializeIfNeededLocked(int userId,
-            long currentTimeMillis) {
-        UserUsageStatsService service = mUserState.get(userId);
+    /**
+     * This should the be only way to fetch the usage stats service for a specific user.
+     */
+    private UserUsageStatsService getUserUsageStatsServiceLocked(int userId) {
+        final UserUsageStatsService service = mUserState.get(userId);
         if (service == null) {
-            final File usageStatsDir = new File(Environment.getDataSystemCeDirectory(userId),
-                    "usagestats");
-            service = new UserUsageStatsService(getContext(), userId, usageStatsDir, this);
-            if (mUserUnlockedStates.get(userId)) {
-                try {
-                    service.init(currentTimeMillis);
-                    mUserState.put(userId, service);
-                } catch (Exception e) {
-                    if (mUserManager.isUserUnlocked(userId)) {
-                        throw e; // rethrow exception - user is unlocked
-                    } else {
-                        Slog.w(TAG, "Attempted to initialize service for "
-                                + "stopped or removed user " + userId);
-                        return null;
-                    }
-                }
-            }
+            Slog.wtf(TAG, "Failed to fetch usage stats service for user " + userId + ". "
+                    + "The user might not have been initialized yet.");
         }
         return service;
     }
 
+    /**
+     * Initializes the given user's usage stats service - this should ideally only be called once,
+     * when the user is initially unlocked.
+     */
+    private void initializeUserUsageStatsServiceLocked(int userId,
+            long currentTimeMillis, HashMap<String, Long> installedPackages) {
+        final File usageStatsDir = new File(Environment.getDataSystemCeDirectory(userId),
+                "usagestats");
+        final UserUsageStatsService service = new UserUsageStatsService(getContext(), userId,
+                usageStatsDir, this);
+        try {
+            service.init(currentTimeMillis, installedPackages);
+            mUserState.put(userId, service);
+        } catch (Exception e) {
+            if (mUserManager.isUserUnlocked(userId)) {
+                Slog.w(TAG, "Failed to initialized unlocked user " + userId);
+                throw e; // rethrow the exception - user is unlocked
+            } else {
+                Slog.w(TAG, "Attempted to initialize service for stopped or removed user "
+                        + userId);
+            }
+        }
+    }
+
     private void migrateStatsToSystemCeIfNeededLocked(int userId) {
         final File usageStatsDir = new File(Environment.getDataSystemCeDirectory(userId),
                 "usagestats");
@@ -614,18 +653,20 @@
         }
         Arrays.sort(pendingEventsFiles);
 
-        for (int i = 0; i < pendingEventsFiles.length; i++) {
+        final int numFiles = pendingEventsFiles.length;
+        for (int i = 0; i < numFiles; i++) {
             final AtomicFile af = new AtomicFile(pendingEventsFiles[i]);
+            final LinkedList<Event> tmpEvents = new LinkedList<>();
             try {
                 try (FileInputStream in = af.openRead()) {
-                    UsageStatsProtoV2.readPendingEvents(in, pendingEvents);
+                    UsageStatsProtoV2.readPendingEvents(in, tmpEvents);
                 }
-            } catch (IOException e) {
-                // Even if one file read fails, exit here to keep all events in order on disk -
-                // they will be read and processed the next time user is unlocked.
+                // only add to the pending events if the read was successful
+                pendingEvents.addAll(tmpEvents);
+            } catch (Exception e) {
+                // Most likely trying to read a corrupted file - log the failure and continue
+                // reading the other pending event files.
                 Slog.e(TAG, "Could not read " + pendingEventsFiles[i] + " for user " + userId);
-                pendingEvents.clear();
-                return;
             }
         }
     }
@@ -652,7 +693,7 @@
             af.finishWrite(fos);
             fos = null;
             pendingEvents.clear();
-        } catch (IOException | IllegalArgumentException e) {
+        } catch (Exception e) {
             Slog.e(TAG, "Failed to write " + pendingEventsFile.getAbsolutePath()
                     + " for user " + userId);
         } finally {
@@ -694,7 +735,6 @@
                 return;
             }
 
-            final long timeNow = System.currentTimeMillis();
             final long elapsedRealtime = SystemClock.elapsedRealtime();
 
             if (event.mPackage != null
@@ -789,8 +829,7 @@
                     break;
             }
 
-            final UserUsageStatsService service =
-                    getUserDataAndInitializeIfNeededLocked(userId, timeNow);
+            final UserUsageStatsService service = getUserUsageStatsServiceLocked(userId);
             if (service == null) {
                 return; // user was stopped or removed
             }
@@ -841,15 +880,18 @@
             mAppStandby.onUserRemoved(userId);
             mAppTimeLimit.onUserRemoved(userId);
         }
+        // Cancel any scheduled jobs for this user since the user is being removed.
+        UsageStatsIdleService.cancelJob(getContext(), userId);
     }
 
     /**
      * Called by the Handler for message MSG_PACKAGE_REMOVED.
      */
     private void onPackageRemoved(int userId, String packageName) {
+        final int tokenRemoved;
         synchronized (mLock) {
             final long timeRemoved = System.currentTimeMillis();
-            if (!mUserUnlockedStates.get(userId, false)) {
+            if (!mUserUnlockedStates.get(userId)) {
                 // If user is not unlocked and a package is removed for them, we will handle it
                 // when the user service is initialized and package manager is queried.
                 return;
@@ -859,7 +901,30 @@
                 return;
             }
 
-            userService.onPackageRemoved(packageName, timeRemoved);
+            tokenRemoved = userService.onPackageRemoved(packageName, timeRemoved);
+        }
+
+        // Schedule a job to prune any data related to this package.
+        if (tokenRemoved != PackagesTokenData.UNASSIGNED_TOKEN) {
+            UsageStatsIdleService.scheduleJob(getContext(), userId);
+        }
+    }
+
+    /**
+     * Called by the Binder stub.
+     */
+    private boolean pruneUninstalledPackagesData(int userId) {
+        synchronized (mLock) {
+            if (!mUserUnlockedStates.get(userId)) {
+                return false; // user is no longer unlocked
+            }
+
+            final UserUsageStatsService userService = mUserState.get(userId);
+            if (userService == null) {
+                return false; // user was stopped or removed
+            }
+
+            return userService.pruneUninstalledPackagesData();
         }
     }
 
@@ -874,8 +939,7 @@
                 return null;
             }
 
-            final UserUsageStatsService service =
-                    getUserDataAndInitializeIfNeededLocked(userId, System.currentTimeMillis());
+            final UserUsageStatsService service = getUserUsageStatsServiceLocked(userId);
             if (service == null) {
                 return null; // user was stopped or removed
             }
@@ -909,8 +973,7 @@
                 return null;
             }
 
-            final UserUsageStatsService service =
-                    getUserDataAndInitializeIfNeededLocked(userId, System.currentTimeMillis());
+            final UserUsageStatsService service = getUserUsageStatsServiceLocked(userId);
             if (service == null) {
                 return null; // user was stopped or removed
             }
@@ -929,8 +992,7 @@
                 return null;
             }
 
-            final UserUsageStatsService service =
-                    getUserDataAndInitializeIfNeededLocked(userId, System.currentTimeMillis());
+            final UserUsageStatsService service = getUserUsageStatsServiceLocked(userId);
             if (service == null) {
                 return null; // user was stopped or removed
             }
@@ -949,8 +1011,7 @@
                 return null;
             }
 
-            final UserUsageStatsService service =
-                    getUserDataAndInitializeIfNeededLocked(userId, System.currentTimeMillis());
+            final UserUsageStatsService service = getUserUsageStatsServiceLocked(userId);
             if (service == null) {
                 return null; // user was stopped or removed
             }
@@ -969,8 +1030,7 @@
                 return null;
             }
 
-            final UserUsageStatsService service =
-                    getUserDataAndInitializeIfNeededLocked(userId, System.currentTimeMillis());
+            final UserUsageStatsService service = getUserUsageStatsServiceLocked(userId);
             if (service == null) {
                 return null; // user was stopped or removed
             }
@@ -2025,8 +2085,7 @@
 
                 // Check to ensure that only user 0's data is b/r for now
                 if (user == UserHandle.USER_SYSTEM) {
-                    final UserUsageStatsService userStats = getUserDataAndInitializeIfNeededLocked(
-                            user, System.currentTimeMillis());
+                    final UserUsageStatsService userStats = getUserUsageStatsServiceLocked(user);
                     if (userStats == null) {
                         return null; // user was stopped or removed
                     }
@@ -2046,8 +2105,7 @@
                 }
 
                 if (user == UserHandle.USER_SYSTEM) {
-                    final UserUsageStatsService userStats = getUserDataAndInitializeIfNeededLocked(
-                            user, System.currentTimeMillis());
+                    final UserUsageStatsService userStats = getUserUsageStatsServiceLocked(user);
                     if (userStats == null) {
                         return; // user was stopped or removed
                     }
@@ -2108,6 +2166,11 @@
         public AppUsageLimitData getAppUsageLimit(String packageName, UserHandle user) {
             return mAppTimeLimit.getAppUsageLimit(packageName, user);
         }
+
+        @Override
+        public boolean pruneUninstalledPackagesData(int userId) {
+            return UsageStatsService.this.pruneUninstalledPackagesData(userId);
+        }
     }
 
     private class MyPackageMonitor extends PackageMonitor {
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index c6a5fcf..179b649 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -34,10 +34,7 @@
 import android.app.usage.UsageStats;
 import android.app.usage.UsageStatsManager;
 import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManagerInternal;
 import android.content.res.Configuration;
-import android.os.Process;
 import android.os.SystemClock;
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
@@ -46,8 +43,8 @@
 import android.util.Slog;
 import android.util.SparseIntArray;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.LocalServices;
 import com.android.server.usage.UsageStatsDatabase.StatCombiner;
 
 import java.io.File;
@@ -55,7 +52,7 @@
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashSet;
+import java.util.HashMap;
 import java.util.List;
 
 /**
@@ -112,9 +109,12 @@
         mSystemTimeSnapshot = System.currentTimeMillis();
     }
 
-    void init(final long currentTimeMillis) {
-        readPackageMappingsLocked();
+    void init(final long currentTimeMillis, HashMap<String, Long> installedPackages) {
+        readPackageMappingsLocked(installedPackages);
         mDatabase.init(currentTimeMillis);
+        if (mDatabase.wasUpgradePerformed()) {
+            mDatabase.prunePackagesDataOnUpgrade(installedPackages);
+        }
 
         int nullCount = 0;
         for (int i = 0; i < mCurrentStats.length; i++) {
@@ -170,52 +170,53 @@
         persistActiveStats();
     }
 
-    void onPackageRemoved(String packageName, long timeRemoved) {
-        mDatabase.onPackageRemoved(packageName, timeRemoved);
+    int onPackageRemoved(String packageName, long timeRemoved) {
+        return mDatabase.onPackageRemoved(packageName, timeRemoved);
     }
 
-    private void readPackageMappingsLocked() {
+    private void readPackageMappingsLocked(HashMap<String, Long> installedPackages) {
         mDatabase.readMappingsLocked();
-        cleanUpPackageMappingsLocked();
+        updatePackageMappingsLocked(installedPackages);
     }
 
     /**
-     * Queries Package Manager for a list of installed packages and removes those packages from
-     * mPackagesTokenData which are not installed any more.
+     * Queries Job Scheduler for any pending data prune jobs and if any exist, it updates the
+     * package mappings in memory by removing those tokens.
      * This will only happen once per device boot, when the user is unlocked for the first time.
+     *
+     * @param installedPackages map of installed packages (package_name:package_install_time)
      */
-    private void cleanUpPackageMappingsLocked() {
-        final long timeNow = System.currentTimeMillis();
-        /*
-         Note (b/142501248): PackageManagerInternal#getInstalledApplications is not lightweight.
-         Once its implementation is updated, or it's replaced with a better alternative, update
-         the call here to use it. For now, using the heavy #getInstalledApplications is okay since
-         this clean-up is only performed once every boot.
-         */
-        final PackageManagerInternal packageManagerInternal =
-                LocalServices.getService(PackageManagerInternal.class);
-        if (packageManagerInternal == null) {
+    private void updatePackageMappingsLocked(HashMap<String, Long> installedPackages) {
+        if (ArrayUtils.isEmpty(installedPackages)) {
             return;
         }
-        final List<ApplicationInfo> installedPackages =
-                packageManagerInternal.getInstalledApplications(0, mUserId, Process.SYSTEM_UID);
-        // convert the package list to a set for easy look-ups
-        final HashSet<String> packagesSet = new HashSet<>(installedPackages.size());
-        for (int i = installedPackages.size() - 1; i >= 0; i--) {
-            packagesSet.add(installedPackages.get(i).packageName);
-        }
-        final List<String> removedPackages = new ArrayList<>();
+
+        final long timeNow = System.currentTimeMillis();
+        final ArrayList<String> removedPackages = new ArrayList<>();
         // populate list of packages that are found in the mappings but not in the installed list
         for (int i = mDatabase.mPackagesTokenData.packagesToTokensMap.size() - 1; i >= 0; i--) {
-            if (!packagesSet.contains(mDatabase.mPackagesTokenData.packagesToTokensMap.keyAt(i))) {
-                removedPackages.add(mDatabase.mPackagesTokenData.packagesToTokensMap.keyAt(i));
+            final String packageName = mDatabase.mPackagesTokenData.packagesToTokensMap.keyAt(i);
+            if (!installedPackages.containsKey(packageName)) {
+                removedPackages.add(packageName);
             }
         }
+        if (removedPackages.isEmpty()) {
+            return;
+        }
 
-        // remove packages in the mappings that are no longer installed
+        // remove packages in the mappings that are no longer installed and persist to disk
         for (int i = removedPackages.size() - 1; i >= 0; i--) {
             mDatabase.mPackagesTokenData.removePackage(removedPackages.get(i), timeNow);
         }
+        try {
+            mDatabase.writeMappingsLocked();
+        } catch (Exception e) {
+            Slog.w(TAG, "Unable to write updated package mappings file on service initialization.");
+        }
+    }
+
+    boolean pruneUninstalledPackagesData() {
+        return mDatabase.pruneUninstalledPackagesData();
     }
 
     private void onTimeChanged(long oldTime, long newTime) {
diff --git a/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java b/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java
index 59f4d56d..8263e0a 100644
--- a/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java
+++ b/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java
@@ -439,7 +439,7 @@
             final ProtoOutputStream protoOutputStream =
                     new ProtoOutputStream(INTENT_PROTO_CHUNK_SIZE);
             // Write this data out as the top-most IntentProto (i.e. it is not a sub-object).
-            intent.writeToProto(protoOutputStream);
+            intent.dumpDebug(protoOutputStream);
             final byte[] bytes = protoOutputStream.getBytes();
 
             p.writeByteArray(bytes);
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 3ecf8d7..86ad795 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -291,7 +291,6 @@
          */
         public static final int DIRECTION_OUTGOING = 1;
 
-
         /** Call can currently be put on hold or unheld. */
         public static final int CAPABILITY_HOLD = 0x00000001;
 
@@ -571,6 +570,7 @@
         private final Bundle mIntentExtras;
         private final long mCreationTimeMillis;
         private final @CallDirection int mCallDirection;
+        private final @Connection.VerificationStatus int mCallerNumberVerificationStatus;
 
         /**
          * Whether the supplied capabilities  supports the specified capability.
@@ -880,6 +880,15 @@
             return mCallDirection;
         }
 
+        /**
+         * Gets the verification status for the phone number of an incoming call as identified in
+         * ATIS-1000082.
+         * @return the verification status.
+         */
+        public @Connection.VerificationStatus int getCallerNumberVerificationStatus() {
+            return mCallerNumberVerificationStatus;
+        }
+
         @Override
         public boolean equals(Object o) {
             if (o instanceof Details) {
@@ -901,7 +910,9 @@
                         areBundlesEqual(mExtras, d.mExtras) &&
                         areBundlesEqual(mIntentExtras, d.mIntentExtras) &&
                         Objects.equals(mCreationTimeMillis, d.mCreationTimeMillis) &&
-                        Objects.equals(mCallDirection, d.mCallDirection);
+                        Objects.equals(mCallDirection, d.mCallDirection) &&
+                        Objects.equals(mCallerNumberVerificationStatus,
+                                d.mCallerNumberVerificationStatus);
             }
             return false;
         }
@@ -923,7 +934,8 @@
                             mExtras,
                             mIntentExtras,
                             mCreationTimeMillis,
-                            mCallDirection);
+                            mCallDirection,
+                            mCallerNumberVerificationStatus);
         }
 
         /** {@hide} */
@@ -944,7 +956,8 @@
                 Bundle extras,
                 Bundle intentExtras,
                 long creationTimeMillis,
-                int callDirection) {
+                int callDirection,
+                int callerNumberVerificationStatus) {
             mTelecomCallId = telecomCallId;
             mHandle = handle;
             mHandlePresentation = handlePresentation;
@@ -962,6 +975,7 @@
             mIntentExtras = intentExtras;
             mCreationTimeMillis = creationTimeMillis;
             mCallDirection = callDirection;
+            mCallerNumberVerificationStatus = callerNumberVerificationStatus;
         }
 
         /** {@hide} */
@@ -983,7 +997,8 @@
                     parcelableCall.getExtras(),
                     parcelableCall.getIntentExtras(),
                     parcelableCall.getCreationTimeMillis(),
-                    parcelableCall.getCallDirection());
+                    parcelableCall.getCallDirection(),
+                    parcelableCall.getCallerNumberVerificationStatus());
         }
 
         @Override
@@ -1512,7 +1527,6 @@
      */
     @SystemApi
     @TestApi
-    //@RequiresPermission(android.Manifest.permission.BACKGROUND_CALL_AUDIO)
     public void enterBackgroundAudioProcessing() {
         if (mState != STATE_ACTIVE && mState != STATE_RINGING) {
             throw new IllegalStateException("Call must be active or ringing");
@@ -1534,7 +1548,6 @@
      */
     @SystemApi
     @TestApi
-    //@RequiresPermission(android.Manifest.permission.BACKGROUND_CALL_AUDIO)
     public void exitBackgroundAudioProcessing(boolean shouldRing) {
         if (mState != STATE_AUDIO_PROCESSING) {
             throw new IllegalStateException("Call must in the audio processing state");
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index b91787c..f8722f4 100644
--- a/telecomm/java/android/telecom/CallScreeningService.java
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -144,7 +144,7 @@
         private final boolean mShouldSilenceCall;
         private final boolean mShouldSkipCallLog;
         private final boolean mShouldSkipNotification;
-        private final boolean mShouldScreenCallFurther;
+        private final boolean mShouldScreenCallViaAudioProcessing;
 
         private CallResponse(
                 boolean shouldDisallowCall,
@@ -152,13 +152,13 @@
                 boolean shouldSilenceCall,
                 boolean shouldSkipCallLog,
                 boolean shouldSkipNotification,
-                boolean shouldScreenCallFurther) {
+                boolean shouldScreenCallViaAudioProcessing) {
             if (!shouldDisallowCall
                     && (shouldRejectCall || shouldSkipCallLog || shouldSkipNotification)) {
                 throw new IllegalStateException("Invalid response state for allowed call.");
             }
 
-            if (shouldDisallowCall && shouldScreenCallFurther) {
+            if (shouldDisallowCall && shouldScreenCallViaAudioProcessing) {
                 throw new IllegalStateException("Invalid response state for allowed call.");
             }
 
@@ -167,7 +167,7 @@
             mShouldSkipCallLog = shouldSkipCallLog;
             mShouldSkipNotification = shouldSkipNotification;
             mShouldSilenceCall = shouldSilenceCall;
-            mShouldScreenCallFurther = shouldScreenCallFurther;
+            mShouldScreenCallViaAudioProcessing = shouldScreenCallViaAudioProcessing;
         }
 
         /*
@@ -211,8 +211,8 @@
          * for further screening of the call.
          * @hide
          */
-        public boolean getShouldScreenCallFurther() {
-            return mShouldScreenCallFurther;
+        public boolean getShouldScreenCallViaAudioProcessing() {
+            return mShouldScreenCallViaAudioProcessing;
         }
 
         public static class Builder {
@@ -221,7 +221,7 @@
             private boolean mShouldSilenceCall;
             private boolean mShouldSkipCallLog;
             private boolean mShouldSkipNotification;
-            private boolean mShouldScreenCallFurther;
+            private boolean mShouldScreenCallViaAudioProcessing;
 
             /**
              * Sets whether the incoming call should be blocked.
@@ -285,13 +285,14 @@
              * This request will only be honored if the {@link CallScreeningService} shares the same
              * uid as the default dialer app. Otherwise, the call will go through as usual.
              *
-             * @param shouldScreenCallFurther Whether to request further call screening.
+             * @param shouldScreenCallViaAudioProcessing Whether to request further call screening.
              * @hide
              */
             @SystemApi
             @TestApi
-            public Builder setShouldScreenCallFurther(boolean shouldScreenCallFurther) {
-                mShouldScreenCallFurther = shouldScreenCallFurther;
+            public @NonNull Builder setShouldScreenCallViaAudioProcessing(
+                    boolean shouldScreenCallViaAudioProcessing) {
+                mShouldScreenCallViaAudioProcessing = shouldScreenCallViaAudioProcessing;
                 return this;
             }
 
@@ -302,7 +303,7 @@
                         mShouldSilenceCall,
                         mShouldSkipCallLog,
                         mShouldSkipNotification,
-                        mShouldScreenCallFurther);
+                        mShouldScreenCallViaAudioProcessing);
             }
        }
     }
@@ -380,7 +381,7 @@
                         new ComponentName(getPackageName(), getClass().getName()));
             } else if (response.getSilenceCall()) {
                 mCallScreeningAdapter.silenceCall(callDetails.getTelecomCallId());
-            } else if (response.getShouldScreenCallFurther()) {
+            } else if (response.getShouldScreenCallViaAudioProcessing()) {
                 mCallScreeningAdapter.screenCallFurther(callDetails.getTelecomCallId());
             } else {
                 mCallScreeningAdapter.allowCall(callDetails.getTelecomCallId());
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 4c22ba9..c063279 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -16,6 +16,7 @@
 
 package android.telecom;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
@@ -35,9 +36,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.SystemClock;
-import android.telephony.Annotation.RilRadioTechnology;
-import android.telephony.ServiceState;
-import android.telephony.TelephonyManager;
+import android.telephony.ims.ImsStreamMediaProfile;
 import android.util.ArraySet;
 import android.view.Surface;
 
@@ -50,6 +49,8 @@
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.nio.channels.Channels;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -153,6 +154,32 @@
     public static final int STATE_PULLING_CALL = 7;
 
     /**
+     * Indicates that the network could not perform verification.
+     */
+    public static final int VERIFICATION_STATUS_NOT_VERIFIED = 0;
+
+    /**
+     * Indicates that verification by the network passed.  This indicates there is a high likelihood
+     * that the call originated from a valid source.
+     */
+    public static final int VERIFICATION_STATUS_PASSED = 1;
+
+    /**
+     * Indicates that verification by the network failed.  This indicates there is a high likelihood
+     * that the call did not originate from a valid source.
+     */
+    public static final int VERIFICATION_STATUS_FAILED = 2;
+
+    /**@hide*/
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "VERIFICATION_STATUS_", value = {
+            VERIFICATION_STATUS_NOT_VERIFIED,
+            VERIFICATION_STATUS_PASSED,
+            VERIFICATION_STATUS_FAILED
+    })
+    public @interface VerificationStatus {}
+
+    /**
      * Connection can currently be put on hold or unheld. This is distinct from
      * {@link #CAPABILITY_SUPPORT_HOLD} in that although a connection may support 'hold' most times,
      * it does not at the moment support the function. This can be true while the call is in the
@@ -475,6 +502,52 @@
     //**********************************************************************************************
 
     /**
+     * Define IMS Audio Codec
+     */
+    // Current audio codec is NONE
+    public static final int AUDIO_CODEC_NONE = ImsStreamMediaProfile.AUDIO_QUALITY_NONE; // 0
+    // Current audio codec is AMR
+    public static final int AUDIO_CODEC_AMR = ImsStreamMediaProfile.AUDIO_QUALITY_AMR; // 1
+    // Current audio codec is AMR_WB
+    public static final int AUDIO_CODEC_AMR_WB = ImsStreamMediaProfile.AUDIO_QUALITY_AMR_WB; // 2
+    // Current audio codec is QCELP13K
+    public static final int AUDIO_CODEC_QCELP13K = ImsStreamMediaProfile.AUDIO_QUALITY_QCELP13K; //3
+    // Current audio codec is EVRC
+    public static final int AUDIO_CODEC_EVRC = ImsStreamMediaProfile.AUDIO_QUALITY_EVRC; // 4
+    // Current audio codec is EVRC_B
+    public static final int AUDIO_CODEC_EVRC_B = ImsStreamMediaProfile.AUDIO_QUALITY_EVRC_B; // 5
+    // Current audio codec is EVRC_WB
+    public static final int AUDIO_CODEC_EVRC_WB = ImsStreamMediaProfile.AUDIO_QUALITY_EVRC_WB; // 6
+    // Current audio codec is EVRC_NW
+    public static final int AUDIO_CODEC_EVRC_NW = ImsStreamMediaProfile.AUDIO_QUALITY_EVRC_NW; // 7
+    // Current audio codec is GSM_EFR
+    public static final int AUDIO_CODEC_GSM_EFR = ImsStreamMediaProfile.AUDIO_QUALITY_GSM_EFR; // 8
+    // Current audio codec is GSM_FR
+    public static final int AUDIO_CODEC_GSM_FR = ImsStreamMediaProfile.AUDIO_QUALITY_GSM_FR; // 9
+    // Current audio codec is GSM_HR
+    public static final int AUDIO_CODEC_GSM_HR = ImsStreamMediaProfile.AUDIO_QUALITY_GSM_HR; // 10
+    // Current audio codec is G711U
+    public static final int AUDIO_CODEC_G711U = ImsStreamMediaProfile.AUDIO_QUALITY_G711U; // 11
+    // Current audio codec is G723
+    public static final int AUDIO_CODEC_G723 = ImsStreamMediaProfile.AUDIO_QUALITY_G723; // 12
+    // Current audio codec is G711A
+    public static final int AUDIO_CODEC_G711A = ImsStreamMediaProfile.AUDIO_QUALITY_G711A; // 13
+    // Current audio codec is G722
+    public static final int AUDIO_CODEC_G722 = ImsStreamMediaProfile.AUDIO_QUALITY_G722; // 14
+    // Current audio codec is G711AB
+    public static final int AUDIO_CODEC_G711AB = ImsStreamMediaProfile.AUDIO_QUALITY_G711AB; // 15
+    // Current audio codec is G729
+    public static final int AUDIO_CODEC_G729 = ImsStreamMediaProfile.AUDIO_QUALITY_G729; // 16
+    // Current audio codec is EVS_NB
+    public static final int AUDIO_CODEC_EVS_NB = ImsStreamMediaProfile.AUDIO_QUALITY_EVS_NB; // 17
+    // Current audio codec is EVS_WB
+    public static final int AUDIO_CODEC_EVS_WB = ImsStreamMediaProfile.AUDIO_QUALITY_EVS_WB; // 18
+    // Current audio codec is EVS_SWB
+    public static final int AUDIO_CODEC_EVS_SWB = ImsStreamMediaProfile.AUDIO_QUALITY_EVS_SWB; // 19
+    // Current audio codec is EVS_FB
+    public static final int AUDIO_CODEC_EVS_FB = ImsStreamMediaProfile.AUDIO_QUALITY_EVS_FB; // 20
+
+    /**
      * Connection extra key used to store the last forwarded number associated with the current
      * connection.  Used to communicate to the user interface that the connection was forwarded via
      * the specified number.
@@ -567,6 +640,13 @@
             "android.telecom.extra.IS_RTT_AUDIO_PRESENT";
 
     /**
+     * The audio codec in use for the current {@link Connection}, if known. Valid values include
+     * {@link #AUDIO_CODEC_AMR_WB} and {@link #AUDIO_CODEC_EVS_WB}.
+     */
+    public static final String EXTRA_AUDIO_CODEC =
+            "android.telecom.extra.AUDIO_CODEC";
+
+    /**
      * Connection event used to inform Telecom that it should play the on hold tone.  This is used
      * to play a tone when the peer puts the current call on hold.  Sent to Telecom via
      * {@link #sendConnectionEvent(String, Bundle)}.
@@ -1803,6 +1883,12 @@
     private Set<String> mPreviousExtraKeys;
 
     /**
+     * The verification status for an incoming call's phone number.
+     */
+    private @VerificationStatus int mCallerNumberVerificationStatus;
+
+
+    /**
      * Create a new Connection.
      */
     public Connection() {}
@@ -3304,4 +3390,26 @@
     public void setCallDirection(@Call.Details.CallDirection int callDirection) {
         mCallDirection = callDirection;
     }
+
+    /**
+     * Gets the verification status for the phone number of an incoming call as identified in
+     * ATIS-1000082.
+     * @return the verification status.
+     */
+    public @VerificationStatus int getCallerNumberVerificationStatus() {
+        return mCallerNumberVerificationStatus;
+    }
+
+    /**
+     * Sets the verification status for the phone number of an incoming call as identified in
+     * ATIS-1000082.
+     * <p>
+     * This property can only be set at the time of creation of a {@link Connection} being returned
+     * by
+     * {@link ConnectionService#onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)}.
+     */
+    public void setCallerNumberVerificationStatus(
+            @VerificationStatus int callerNumberVerificationStatus) {
+        mCallerNumberVerificationStatus = callerNumberVerificationStatus;
+    }
 }
diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java
index b428530..221f8f1 100644
--- a/telecomm/java/android/telecom/ConnectionRequest.java
+++ b/telecomm/java/android/telecom/ConnectionRequest.java
@@ -16,6 +16,10 @@
 
 package android.telecom;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -32,6 +36,7 @@
      * Builder class for {@link ConnectionRequest}
      * @hide
      */
+    @TestApi // For convenience in CTS tests
     public static final class Builder {
         private PhoneAccountHandle mAccountHandle;
         private Uri mAddress;
@@ -48,7 +53,7 @@
          * Sets the phone account handle for the resulting {@link ConnectionRequest}
          * @param accountHandle The accountHandle which should be used to place the call.
          */
-        public Builder setAccountHandle(PhoneAccountHandle accountHandle) {
+        public @NonNull Builder setAccountHandle(@NonNull PhoneAccountHandle accountHandle) {
             this.mAccountHandle = accountHandle;
             return this;
         }
@@ -58,7 +63,7 @@
          * @param address The address(e.g., phone number) to which the {@link Connection} is to
          *                connect.
          */
-        public Builder setAddress(Uri address) {
+        public @NonNull Builder setAddress(@NonNull Uri address) {
             this.mAddress = address;
             return this;
         }
@@ -67,7 +72,7 @@
          * Sets the extras bundle for the resulting {@link ConnectionRequest}
          * @param extras Application-specific extra data.
          */
-        public Builder setExtras(Bundle extras) {
+        public @NonNull Builder setExtras(@NonNull Bundle extras) {
             this.mExtras = extras;
             return this;
         }
@@ -76,7 +81,7 @@
          * Sets the video state for the resulting {@link ConnectionRequest}
          * @param videoState Determines the video state for the connection.
          */
-        public Builder setVideoState(int videoState) {
+        public @NonNull Builder setVideoState(int videoState) {
             this.mVideoState = videoState;
             return this;
         }
@@ -85,7 +90,7 @@
          * Sets the Telecom call ID for the resulting {@link ConnectionRequest}
          * @param telecomCallId The telecom call ID.
          */
-        public Builder setTelecomCallId(String telecomCallId) {
+        public @NonNull Builder setTelecomCallId(@NonNull String telecomCallId) {
             this.mTelecomCallId = telecomCallId;
             return this;
         }
@@ -97,7 +102,7 @@
          *                                 its own incoming call UI for an incoming call.  When
          *                                 {@code false}, Telecom shows the incoming call UI.
          */
-        public Builder setShouldShowIncomingCallUi(boolean shouldShowIncomingCallUi) {
+        public @NonNull Builder setShouldShowIncomingCallUi(boolean shouldShowIncomingCallUi) {
             this.mShouldShowIncomingCallUi = shouldShowIncomingCallUi;
             return this;
         }
@@ -107,7 +112,8 @@
          * resulting {@link ConnectionRequest}
          * @param rttPipeFromInCall The data pipe to read from.
          */
-        public Builder setRttPipeFromInCall(ParcelFileDescriptor rttPipeFromInCall) {
+        public @NonNull Builder setRttPipeFromInCall(
+                @NonNull ParcelFileDescriptor rttPipeFromInCall) {
             this.mRttPipeFromInCall = rttPipeFromInCall;
             return this;
         }
@@ -117,12 +123,16 @@
          * resulting {@link ConnectionRequest}
          * @param rttPipeToInCall The data pipe to write to.
          */
-        public Builder setRttPipeToInCall(ParcelFileDescriptor rttPipeToInCall) {
+        public @NonNull Builder setRttPipeToInCall(@NonNull ParcelFileDescriptor rttPipeToInCall) {
             this.mRttPipeToInCall = rttPipeToInCall;
             return this;
         }
 
-        public ConnectionRequest build() {
+        /**
+         * Build the {@link ConnectionRequest}
+         * @return Result of the builder
+         */
+        public @NonNull ConnectionRequest build() {
             return new ConnectionRequest(
                     mAccountHandle,
                     mAddress,
@@ -261,7 +271,9 @@
      * @return The Telecom ID.
      * @hide
      */
-    public String getTelecomCallId() {
+    @SystemApi
+    @TestApi
+    public @Nullable String getTelecomCallId() {
         return mTelecomCallId;
     }
 
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 812b805..3a0494e 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -1621,7 +1621,8 @@
                         connection.getStatusHints(),
                         connection.getDisconnectCause(),
                         createIdList(connection.getConferenceables()),
-                        connection.getExtras()));
+                        connection.getExtras(),
+                        connection.getCallerNumberVerificationStatus()));
 
         if (isIncoming && request.shouldShowIncomingCallUi() && isSelfManaged) {
             // Tell ConnectionService to show its incoming call UX.
@@ -2156,7 +2157,8 @@
                     emptyList,
                     connection.getExtras(),
                     conferenceId,
-                    connection.getCallDirection());
+                    connection.getCallDirection(),
+                    Connection.VERIFICATION_STATUS_NOT_VERIFIED);
             mAdapter.addExistingConnection(id, parcelableConnection);
         }
     }
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index fdc3243..a234bb0 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -16,7 +16,6 @@
 
 package android.telecom;
 
-import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.net.Uri;
 import android.os.Build;
@@ -66,6 +65,7 @@
     private final Bundle mExtras;
     private final long mCreationTimeMillis;
     private final int mCallDirection;
+    private final int mCallerNumberVerificationStatus;
 
     public ParcelableCall(
             String id,
@@ -94,7 +94,8 @@
             Bundle intentExtras,
             Bundle extras,
             long creationTimeMillis,
-            int callDirection) {
+            int callDirection,
+            int callerNumberVerificationStatus) {
         mId = id;
         mState = state;
         mDisconnectCause = disconnectCause;
@@ -122,6 +123,7 @@
         mExtras = extras;
         mCreationTimeMillis = creationTimeMillis;
         mCallDirection = callDirection;
+        mCallerNumberVerificationStatus = callerNumberVerificationStatus;
     }
 
     /** The unique ID of the call. */
@@ -322,6 +324,15 @@
         return mCallDirection;
     }
 
+    /**
+     * Gets the verification status for the phone number of an incoming call as identified in
+     * ATIS-1000082.
+     * @return the verification status.
+     */
+    public @Connection.VerificationStatus int getCallerNumberVerificationStatus() {
+        return mCallerNumberVerificationStatus;
+    }
+
     /** Responsible for creating ParcelableCall objects for deserialized Parcels. */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public static final @android.annotation.NonNull Parcelable.Creator<ParcelableCall> CREATOR =
@@ -360,6 +371,7 @@
             ParcelableRttCall rttCall = source.readParcelable(classLoader);
             long creationTimeMillis = source.readLong();
             int callDirection = source.readInt();
+            int callerNumberVerificationStatus = source.readInt();
             return new ParcelableCall(
                     id,
                     state,
@@ -387,7 +399,8 @@
                     intentExtras,
                     extras,
                     creationTimeMillis,
-                    callDirection);
+                    callDirection,
+                    callerNumberVerificationStatus);
         }
 
         @Override
@@ -433,6 +446,7 @@
         destination.writeParcelable(mRttCall, 0);
         destination.writeLong(mCreationTimeMillis);
         destination.writeInt(mCallDirection);
+        destination.writeInt(mCallerNumberVerificationStatus);
     }
 
     @Override
diff --git a/telecomm/java/android/telecom/ParcelableConnection.java b/telecomm/java/android/telecom/ParcelableConnection.java
index 4734af6..2b9ce9b 100644
--- a/telecomm/java/android/telecom/ParcelableConnection.java
+++ b/telecomm/java/android/telecom/ParcelableConnection.java
@@ -54,6 +54,7 @@
     private final Bundle mExtras;
     private String mParentCallId;
     private @Call.Details.CallDirection int mCallDirection;
+    private @Connection.VerificationStatus int mCallerNumberVerificationStatus;
 
     /** @hide */
     public ParcelableConnection(
@@ -77,12 +78,13 @@
             List<String> conferenceableConnectionIds,
             Bundle extras,
             String parentCallId,
-            @Call.Details.CallDirection int callDirection) {
+            @Call.Details.CallDirection int callDirection,
+            @Connection.VerificationStatus int callerNumberVerificationStatus) {
         this(phoneAccount, state, capabilities, properties, supportedAudioRoutes, address,
                 addressPresentation, callerDisplayName, callerDisplayNamePresentation,
                 videoProvider, videoState, ringbackRequested, isVoipAudioMode, connectTimeMillis,
                 connectElapsedTimeMillis, statusHints, disconnectCause, conferenceableConnectionIds,
-                extras);
+                extras, callerNumberVerificationStatus);
         mParentCallId = parentCallId;
         mCallDirection = callDirection;
     }
@@ -107,7 +109,8 @@
             StatusHints statusHints,
             DisconnectCause disconnectCause,
             List<String> conferenceableConnectionIds,
-            Bundle extras) {
+            Bundle extras,
+            @Connection.VerificationStatus int callerNumberVerificationStatus) {
         mPhoneAccount = phoneAccount;
         mState = state;
         mConnectionCapabilities = capabilities;
@@ -129,6 +132,7 @@
         mExtras = extras;
         mParentCallId = null;
         mCallDirection = Call.Details.DIRECTION_UNKNOWN;
+        mCallerNumberVerificationStatus = callerNumberVerificationStatus;
     }
 
     public PhoneAccountHandle getPhoneAccount() {
@@ -227,6 +231,10 @@
         return mCallDirection;
     }
 
+    public @Connection.VerificationStatus int getCallerNumberVerificationStatus() {
+        return mCallerNumberVerificationStatus;
+    }
+
     @Override
     public String toString() {
         return new StringBuilder()
@@ -276,6 +284,7 @@
             String parentCallId = source.readString();
             long connectElapsedTimeMillis = source.readLong();
             int callDirection = source.readInt();
+            int callerNumberVerificationStatus = source.readInt();
 
             return new ParcelableConnection(
                     phoneAccount,
@@ -298,7 +307,8 @@
                     conferenceableConnectionIds,
                     extras,
                     parentCallId,
-                    callDirection);
+                    callDirection,
+                    callerNumberVerificationStatus);
         }
 
         @Override
@@ -338,5 +348,6 @@
         destination.writeString(mParentCallId);
         destination.writeLong(mConnectElapsedTimeMillis);
         destination.writeInt(mCallDirection);
+        destination.writeInt(mCallerNumberVerificationStatus);
     }
 }
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 4016943..39d741c 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1029,12 +1029,16 @@
      * by the user.
      *
      * @param includeDisabledAccounts When {@code true}, disabled phone accounts will be included,
-     *                                when {@code false}, only
+     *                                when {@code false}, only enabled phone accounts will be
+     *                                included.
      * @return A list of {@code PhoneAccountHandle} objects.
      * @hide
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 119305590)
-    public List<PhoneAccountHandle> getCallCapablePhoneAccounts(boolean includeDisabledAccounts) {
+    @SystemApi
+    @TestApi
+    @RequiresPermission(READ_PRIVILEGED_PHONE_STATE)
+    public @NonNull List<PhoneAccountHandle> getCallCapablePhoneAccounts(
+            boolean includeDisabledAccounts) {
         try {
             if (isServiceConnected()) {
                 return getTelecomService().getCallCapablePhoneAccounts(
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index de3a816..204c37e 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -314,8 +314,6 @@
 
     void addOrRemoveTestCallCompanionApp(String packageName, boolean isAdded);
 
-    void setTestAutoModeApp(String packageName);
-
     /**
      * @see TelecomServiceImpl#setSystemDialer
      */
diff --git a/telephony/java/com/android/internal/telephony/EncodeException.java b/telephony/common/com/android/internal/telephony/EncodeException.java
similarity index 100%
rename from telephony/java/com/android/internal/telephony/EncodeException.java
rename to telephony/common/com/android/internal/telephony/EncodeException.java
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
new file mode 100644
index 0000000..86630b0
--- /dev/null
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -0,0 +1,709 @@
+/*
+ * 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.internal.telephony;
+
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import android.Manifest;
+import android.annotation.Nullable;
+import android.app.AppOpsManager;
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.telephony.Rlog;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.util.StatsLog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Supplier;
+
+/** Utility class for Telephony permission enforcement. */
+public final class TelephonyPermissions {
+    private static final String LOG_TAG = "TelephonyPermissions";
+
+    private static final boolean DBG = false;
+
+    private static final Supplier<ITelephony> TELEPHONY_SUPPLIER = () ->
+            ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
+
+    /**
+     * Whether to disable the new device identifier access restrictions.
+     */
+    private static final String PROPERTY_DEVICE_IDENTIFIER_ACCESS_RESTRICTIONS_DISABLED =
+            "device_identifier_access_restrictions_disabled";
+
+    // Contains a mapping of packages that did not meet the new requirements to access device
+    // identifiers and the methods they were attempting to invoke; used to prevent duplicate
+    // reporting of packages / methods.
+    private static final Map<String, Set<String>> sReportedDeviceIDPackages;
+    static {
+        sReportedDeviceIDPackages = new HashMap<>();
+    }
+
+    private TelephonyPermissions() {}
+
+    /**
+     * Check whether the caller (or self, if not processing an IPC) can read phone state.
+     *
+     * <p>This method behaves in one of the following ways:
+     * <ul>
+     *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the
+     *       READ_PHONE_STATE runtime permission, or carrier privileges on the given subId.
+     *   <li>throw SecurityException: if the caller didn't declare any of these permissions, or, for
+     *       apps which support runtime permissions, if the caller does not currently have any of
+     *       these permissions.
+     *   <li>return false: if the caller lacks all of these permissions and doesn't support runtime
+     *       permissions. This implies that the user revoked the ability to read phone state
+     *       manually (via AppOps). In this case we can't throw as it would break app compatibility,
+     *       so we return false to indicate that the calling function should return dummy data.
+     * </ul>
+     *
+     * <p>Note: for simplicity, this method always returns false for callers using legacy
+     * permissions and who have had READ_PHONE_STATE revoked, even if they are carrier-privileged.
+     * Such apps should migrate to runtime permissions or stop requiring READ_PHONE_STATE on P+
+     * devices.
+     *
+     * @param subId the subId of the relevant subscription; used to check carrier privileges. May be
+     *              {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} to skip this check for cases
+     *              where it isn't relevant (hidden APIs, or APIs which are otherwise okay to leave
+     *              inaccesible to carrier-privileged apps).
+     */
+    public static boolean checkCallingOrSelfReadPhoneState(
+            Context context, int subId, String callingPackage, @Nullable String callingFeatureId,
+            String message) {
+        return checkReadPhoneState(context, subId, Binder.getCallingPid(), Binder.getCallingUid(),
+                callingPackage, callingFeatureId, message);
+    }
+
+    /** Identical to checkCallingOrSelfReadPhoneState but never throws SecurityException */
+    public static boolean checkCallingOrSelfReadPhoneStateNoThrow(
+            Context context, int subId, String callingPackage, @Nullable String callingFeatureId,
+            String message) {
+        try {
+            return checkCallingOrSelfReadPhoneState(context, subId, callingPackage,
+                    callingFeatureId, message);
+        } catch (SecurityException se) {
+            return false;
+        }
+    }
+
+    /**
+     * Check whether the app with the given pid/uid can read phone state.
+     *
+     * <p>This method behaves in one of the following ways:
+     * <ul>
+     *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the
+     *       READ_PHONE_STATE runtime permission, or carrier privileges on the given subId.
+     *   <li>throw SecurityException: if the caller didn't declare any of these permissions, or, for
+     *       apps which support runtime permissions, if the caller does not currently have any of
+     *       these permissions.
+     *   <li>return false: if the caller lacks all of these permissions and doesn't support runtime
+     *       permissions. This implies that the user revoked the ability to read phone state
+     *       manually (via AppOps). In this case we can't throw as it would break app compatibility,
+     *       so we return false to indicate that the calling function should return dummy data.
+     * </ul>
+     *
+     * <p>Note: for simplicity, this method always returns false for callers using legacy
+     * permissions and who have had READ_PHONE_STATE revoked, even if they are carrier-privileged.
+     * Such apps should migrate to runtime permissions or stop requiring READ_PHONE_STATE on P+
+     * devices.
+     */
+    public static boolean checkReadPhoneState(
+            Context context, int subId, int pid, int uid, String callingPackage,
+            @Nullable  String callingFeatureId, String message) {
+        return checkReadPhoneState(
+                context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage, callingFeatureId,
+                message);
+    }
+
+    /**
+     * Check whether the calling packages has carrier privileges for the passing subscription.
+     * @return {@code true} if the caller has carrier privileges, {@false} otherwise.
+     */
+    public static boolean checkCarrierPrivilegeForSubId(int subId) {
+        if (SubscriptionManager.isValidSubscriptionId(subId)
+                && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, Binder.getCallingUid())
+                == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Check whether the app with the given pid/uid can read phone state.
+     *
+     * <p>This method behaves in one of the following ways:
+     * <ul>
+     *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the
+     *       READ_PHONE_STATE runtime permission, or carrier privileges on the given subId.
+     *   <li>throw SecurityException: if the caller didn't declare any of these permissions, or, for
+     *       apps which support runtime permissions, if the caller does not currently have any of
+     *       these permissions.
+     *   <li>return false: if the caller lacks all of these permissions and doesn't support runtime
+     *       permissions. This implies that the user revoked the ability to read phone state
+     *       manually (via AppOps). In this case we can't throw as it would break app compatibility,
+     *       so we return false to indicate that the calling function should return dummy data.
+     * </ul>
+     *
+     * <p>Note: for simplicity, this method always returns false for callers using legacy
+     * permissions and who have had READ_PHONE_STATE revoked, even if they are carrier-privileged.
+     * Such apps should migrate to runtime permissions or stop requiring READ_PHONE_STATE on P+
+     * devices.
+     */
+    @VisibleForTesting
+    public static boolean checkReadPhoneState(
+            Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
+            String callingPackage, @Nullable String callingFeatureId, String message) {
+        try {
+            context.enforcePermission(
+                    android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message);
+
+            // SKIP checking for run-time permission since caller has PRIVILEGED permission
+            return true;
+        } catch (SecurityException privilegedPhoneStateException) {
+            try {
+                context.enforcePermission(
+                        android.Manifest.permission.READ_PHONE_STATE, pid, uid, message);
+            } catch (SecurityException phoneStateException) {
+                // If we don't have the runtime permission, but do have carrier privileges, that
+                // suffices for reading phone state.
+                if (SubscriptionManager.isValidSubscriptionId(subId)) {
+                    enforceCarrierPrivilege(telephonySupplier, subId, uid, message);
+                    return true;
+                }
+                throw phoneStateException;
+            }
+        }
+
+        // We have READ_PHONE_STATE permission, so return true as long as the AppOps bit hasn't been
+        // revoked.
+        AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+        return appOps.noteOp(AppOpsManager.OPSTR_READ_PHONE_STATE, uid, callingPackage,
+                callingFeatureId, null) == AppOpsManager.MODE_ALLOWED;
+    }
+
+    /**
+     * Check whether the app with the given pid/uid can read phone state, or has carrier
+     * privileges on any active subscription.
+     *
+     * <p>If the app does not have carrier privilege, this method will return {@code false} instead
+     * of throwing a SecurityException. Therefore, the callers cannot tell the difference
+     * between M+ apps which declare the runtime permission but do not have it, and pre-M apps
+     * which declare the static permission but had access revoked via AppOps. Apps in the former
+     * category expect SecurityExceptions; apps in the latter don't. So this method is suitable for
+     * use only if the behavior in both scenarios is meant to be identical.
+     *
+     * @return {@code true} if the app can read phone state or has carrier privilege;
+     *         {@code false} otherwise.
+     */
+    public static boolean checkReadPhoneStateOnAnyActiveSub(Context context, int pid, int uid,
+            String callingPackage, @Nullable String callingFeatureId, String message) {
+        return checkReadPhoneStateOnAnyActiveSub(context, TELEPHONY_SUPPLIER, pid, uid,
+                callingPackage, callingFeatureId, message);
+    }
+
+    /**
+     * Check whether the app with the given pid/uid can read phone state, or has carrier
+     * privileges on any active subscription.
+     *
+     * <p>If the app does not have carrier privilege, this method will return {@code false} instead
+     * of throwing a SecurityException. Therefore, the callers cannot tell the difference
+     * between M+ apps which declare the runtime permission but do not have it, and pre-M apps
+     * which declare the static permission but had access revoked via AppOps. Apps in the former
+     * category expect SecurityExceptions; apps in the latter don't. So this method is suitable for
+     * use only if the behavior in both scenarios is meant to be identical.
+     *
+     * @return {@code true} if the app can read phone state or has carrier privilege;
+     *         {@code false} otherwise.
+     */
+    @VisibleForTesting
+    public static boolean checkReadPhoneStateOnAnyActiveSub(
+            Context context, Supplier<ITelephony> telephonySupplier, int pid, int uid,
+            String callingPackage, @Nullable String callingFeatureId, String message) {
+        try {
+            context.enforcePermission(
+                    android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message);
+
+            // SKIP checking for run-time permission since caller has PRIVILEGED permission
+            return true;
+        } catch (SecurityException privilegedPhoneStateException) {
+            try {
+                context.enforcePermission(
+                        android.Manifest.permission.READ_PHONE_STATE, pid, uid, message);
+            } catch (SecurityException phoneStateException) {
+                // If we don't have the runtime permission, but do have carrier privileges, that
+                // suffices for reading phone state.
+                return checkCarrierPrivilegeForAnySubId(context, telephonySupplier, uid);
+            }
+        }
+
+        // We have READ_PHONE_STATE permission, so return true as long as the AppOps bit hasn't been
+        // revoked.
+        AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+        return appOps.noteOp(AppOpsManager.OPSTR_READ_PHONE_STATE, uid, callingPackage,
+                callingFeatureId, null) == AppOpsManager.MODE_ALLOWED;
+    }
+
+    /**
+     * Check whether the caller (or self, if not processing an IPC) can read device identifiers.
+     *
+     * <p>This method behaves in one of the following ways:
+     * <ul>
+     *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the calling
+     *       package passes a DevicePolicyManager Device Owner / Profile Owner device identifier
+     *       access check, or the calling package has carrier privileges on any active subscription.
+    *   <li>throw SecurityException: if the caller does not meet any of the requirements and is
+     *       targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission
+     *       or carrier privileges of any active subscription.
+     *   <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
+     *       permission. In this case the caller would expect to have access to the device
+     *       identifiers so false is returned instead of throwing a SecurityException to indicate
+     *       the calling function should return dummy data.
+     * </ul>
+     */
+    public static boolean checkCallingOrSelfReadDeviceIdentifiers(Context context,
+            String callingPackage, @Nullable String callingFeatureId, String message) {
+        return checkCallingOrSelfReadDeviceIdentifiers(context,
+                SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage, callingFeatureId,
+                message);
+    }
+
+    /**
+     * Check whether the caller (or self, if not processing an IPC) can read device identifiers.
+     *
+     * <p>This method behaves in one of the following ways:
+     * <ul>
+     *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the calling
+     *       package passes a DevicePolicyManager Device Owner / Profile Owner device identifier
+     *       access check, or the calling package has carrier privileges on any active subscription.
+     *   <li>throw SecurityException: if the caller does not meet any of the requirements and is
+     *       targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission
+     *       or carrier privileges of any active subscription.
+     *   <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
+     *       permission or carrier privileges. In this case the caller would expect to have access
+     *       to the device identifiers so false is returned instead of throwing a SecurityException
+     *       to indicate the calling function should return dummy data.
+     * </ul>
+     */
+    public static boolean checkCallingOrSelfReadDeviceIdentifiers(Context context, int subId,
+            String callingPackage, @Nullable String callingFeatureId, String message) {
+        return checkPrivilegedReadPermissionOrCarrierPrivilegePermission(
+                context, subId, callingPackage, callingFeatureId, message, true);
+    }
+
+    /**
+     * Check whether the caller (or self, if not processing an IPC) can read subscriber identifiers.
+     *
+     * <p>This method behaves in one of the following ways:
+     * <ul>
+     *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the calling
+     *       package passes a DevicePolicyManager Device Owner / Profile Owner device identifier
+     *       access check, or the calling package has carrier privileges on specified subscription.
+     *   <li>throw SecurityException: if the caller does not meet any of the requirements and is
+     *       targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission.
+     *   <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
+     *       permission. In this case the caller would expect to have access to the device
+     *       identifiers so false is returned instead of throwing a SecurityException to indicate
+     *       the calling function should return dummy data.
+     * </ul>
+     */
+    public static boolean checkCallingOrSelfReadSubscriberIdentifiers(Context context, int subId,
+            String callingPackage, @Nullable String callingFeatureId, String message) {
+        return checkPrivilegedReadPermissionOrCarrierPrivilegePermission(
+                context, subId, callingPackage, callingFeatureId, message, false);
+    }
+
+    /**
+     * Checks whether the app with the given pid/uid can read device identifiers.
+     *
+     * <p>This method behaves in one of the following ways:
+     * <ul>
+     *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the calling
+     *       package passes a DevicePolicyManager Device Owner / Profile Owner device identifier
+     *       access check; or the calling package has carrier privileges on the specified
+     *       subscription; or allowCarrierPrivilegeOnAnySub is true and has carrier privilege on
+     *       any active subscription.
+     *   <li>throw SecurityException: if the caller does not meet any of the requirements and is
+     *       targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission.
+     *   <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
+     *       permission. In this case the caller would expect to have access to the device
+     *       identifiers so false is returned instead of throwing a SecurityException to indicate
+     *       the calling function should return dummy data.
+     * </ul>
+     */
+    private static boolean checkPrivilegedReadPermissionOrCarrierPrivilegePermission(
+            Context context, int subId, String callingPackage, @Nullable String callingFeatureId,
+            String message, boolean allowCarrierPrivilegeOnAnySub) {
+        int uid = Binder.getCallingUid();
+        int pid = Binder.getCallingPid();
+        // Allow system and root access to the device identifiers.
+        final int appId = UserHandle.getAppId(uid);
+        if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID) {
+            return true;
+        }
+        // Allow access to packages that have the READ_PRIVILEGED_PHONE_STATE permission.
+        if (context.checkPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid,
+                uid) == PackageManager.PERMISSION_GRANTED) {
+            return true;
+        }
+
+        // If the calling package has carrier privileges for specified sub, then allow access.
+        if (checkCarrierPrivilegeForSubId(subId)) return true;
+
+        // If the calling package has carrier privileges for any subscription
+        // and allowCarrierPrivilegeOnAnySub is set true, then allow access.
+        if (allowCarrierPrivilegeOnAnySub && checkCarrierPrivilegeForAnySubId(
+                context, TELEPHONY_SUPPLIER, uid)) {
+            return true;
+        }
+
+        // if the calling package is not null then perform the DevicePolicyManager device /
+        // profile owner and Appop checks.
+        if (callingPackage != null) {
+            // Allow access to an app that has been granted the READ_DEVICE_IDENTIFIERS app op.
+            long token = Binder.clearCallingIdentity();
+            AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(
+                    Context.APP_OPS_SERVICE);
+            try {
+                if (appOpsManager.noteOpNoThrow(AppOpsManager.OPSTR_READ_DEVICE_IDENTIFIERS, uid,
+                        callingPackage, callingFeatureId, null) == AppOpsManager.MODE_ALLOWED) {
+                    return true;
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+            // Allow access to a device / profile owner app.
+            DevicePolicyManager devicePolicyManager =
+                    (DevicePolicyManager) context.getSystemService(
+                            Context.DEVICE_POLICY_SERVICE);
+            if (devicePolicyManager != null && devicePolicyManager.checkDeviceIdentifierAccess(
+                    callingPackage, pid, uid)) {
+                return true;
+            }
+        }
+        return reportAccessDeniedToReadIdentifiers(context, subId, pid, uid, callingPackage,
+                message);
+    }
+
+    /**
+     * Reports a failure when the app with the given pid/uid cannot access the requested identifier.
+     *
+     * @returns false if the caller is targeting pre-Q and does have the READ_PHONE_STATE
+     * permission or carrier privileges.
+     * @throws SecurityException if the caller does not meet any of the requirements for the
+     *                           requested identifier and is targeting Q or is targeting pre-Q
+     *                           and does not have the READ_PHONE_STATE permission or carrier
+     *                           privileges.
+     */
+    private static boolean reportAccessDeniedToReadIdentifiers(Context context, int subId, int pid,
+            int uid, String callingPackage, String message) {
+        boolean isPreinstalled = false;
+        ApplicationInfo callingPackageInfo = null;
+        try {
+            callingPackageInfo = context.getPackageManager().getApplicationInfoAsUser(
+                    callingPackage, 0, UserHandle.getUserHandleForUid(uid));
+            if (callingPackageInfo != null) {
+                if (callingPackageInfo.isSystemApp()) {
+                    isPreinstalled = true;
+                }
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            // If the application info for the calling package could not be found then assume the
+            // calling app is a non-preinstalled app to detect any issues with the check
+            Log.e(LOG_TAG, "Exception caught obtaining package info for package " + callingPackage,
+                    e);
+        }
+        // The current package should only be reported in StatsLog if it has not previously been
+        // reported for the currently invoked device identifier method.
+        boolean packageReported = sReportedDeviceIDPackages.containsKey(callingPackage);
+        if (!packageReported || !sReportedDeviceIDPackages.get(callingPackage).contains(
+                message)) {
+            Set invokedMethods;
+            if (!packageReported) {
+                invokedMethods = new HashSet<String>();
+                sReportedDeviceIDPackages.put(callingPackage, invokedMethods);
+            } else {
+                invokedMethods = sReportedDeviceIDPackages.get(callingPackage);
+            }
+            invokedMethods.add(message);
+            StatsLog.write(StatsLog.DEVICE_IDENTIFIER_ACCESS_DENIED, callingPackage, message,
+                    isPreinstalled, false);
+        }
+        Log.w(LOG_TAG, "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message
+                + ":isPreinstalled=" + isPreinstalled);
+        // if the target SDK is pre-Q then check if the calling package would have previously
+        // had access to device identifiers.
+        if (callingPackageInfo != null && (
+                callingPackageInfo.targetSdkVersion < Build.VERSION_CODES.Q)) {
+            if (context.checkPermission(
+                    android.Manifest.permission.READ_PHONE_STATE,
+                    pid,
+                    uid) == PackageManager.PERMISSION_GRANTED) {
+                return false;
+            }
+            if (checkCarrierPrivilegeForSubId(subId)) {
+                return false;
+            }
+        }
+        throw new SecurityException(message + ": The user " + uid
+                + " does not meet the requirements to access device identifiers.");
+    }
+
+    /**
+     * Check whether the app with the given pid/uid can read the call log.
+     * @return {@code true} if the specified app has the read call log permission and AppOpp granted
+     *      to it, {@code false} otherwise.
+     */
+    public static boolean checkReadCallLog(
+            Context context, int subId, int pid, int uid, String callingPackage,
+            @Nullable String callingPackageName) {
+        return checkReadCallLog(
+                context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage, callingPackageName);
+    }
+
+    /**
+     * Check whether the app with the given pid/uid can read the call log.
+     * @return {@code true} if the specified app has the read call log permission and AppOpp granted
+     *      to it, {@code false} otherwise.
+     */
+    @VisibleForTesting
+    public static boolean checkReadCallLog(
+            Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
+            String callingPackage, @Nullable String callingFeatureId) {
+
+        if (context.checkPermission(Manifest.permission.READ_CALL_LOG, pid, uid)
+                != PERMISSION_GRANTED) {
+            // If we don't have the runtime permission, but do have carrier privileges, that
+            // suffices for being able to see the call phone numbers.
+            if (SubscriptionManager.isValidSubscriptionId(subId)) {
+                enforceCarrierPrivilege(telephonySupplier, subId, uid, "readCallLog");
+                return true;
+            }
+            return false;
+        }
+
+        // We have READ_CALL_LOG permission, so return true as long as the AppOps bit hasn't been
+        // revoked.
+        AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+        return appOps.noteOp(AppOpsManager.OPSTR_READ_CALL_LOG, uid, callingPackage,
+                callingFeatureId, null) == AppOpsManager.MODE_ALLOWED;
+    }
+
+    /**
+     * Returns whether the caller can read phone numbers.
+     *
+     * <p>Besides apps with the ability to read phone state per {@link #checkReadPhoneState}, the
+     * default SMS app and apps with READ_SMS or READ_PHONE_NUMBERS can also read phone numbers.
+     */
+    public static boolean checkCallingOrSelfReadPhoneNumber(
+            Context context, int subId, String callingPackage, @Nullable String callingFeatureId,
+            String message) {
+        return checkReadPhoneNumber(
+                context, TELEPHONY_SUPPLIER, subId, Binder.getCallingPid(), Binder.getCallingUid(),
+                callingPackage, callingFeatureId, message);
+    }
+
+    /**
+     * Returns whether the caller can read phone numbers.
+     *
+     * <p>Besides apps with the ability to read phone state per {@link #checkReadPhoneState}, the
+     * default SMS app and apps with READ_SMS or READ_PHONE_NUMBERS can also read phone numbers.
+     */
+    @VisibleForTesting
+    public static boolean checkReadPhoneNumber(
+            Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
+            String callingPackage, @Nullable String callingFeatureId, String message) {
+        // Default SMS app can always read it.
+        AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+        if (appOps.noteOp(AppOpsManager.OPSTR_WRITE_SMS, uid, callingPackage, callingFeatureId,
+                null) == AppOpsManager.MODE_ALLOWED) {
+            return true;
+        }
+
+        // NOTE(b/73308711): If an app has one of the following AppOps bits explicitly revoked, they
+        // will be denied access, even if they have another permission and AppOps bit if needed.
+
+        // First, check if we can read the phone state.
+        try {
+            return checkReadPhoneState(
+                    context, telephonySupplier, subId, pid, uid, callingPackage, callingFeatureId,
+                    message);
+        } catch (SecurityException readPhoneStateSecurityException) {
+        }
+        // Can be read with READ_SMS too.
+        try {
+            context.enforcePermission(android.Manifest.permission.READ_SMS, pid, uid, message);
+            return appOps.noteOp(AppOpsManager.OPSTR_READ_SMS, uid, callingPackage,
+                    callingFeatureId, null) == AppOpsManager.MODE_ALLOWED;
+
+        } catch (SecurityException readSmsSecurityException) {
+        }
+        // Can be read with READ_PHONE_NUMBERS too.
+        try {
+            context.enforcePermission(android.Manifest.permission.READ_PHONE_NUMBERS, pid, uid,
+                    message);
+            return appOps.noteOp(AppOpsManager.OPSTR_READ_PHONE_NUMBERS, uid, callingPackage,
+                    callingFeatureId, null) == AppOpsManager.MODE_ALLOWED;
+
+        } catch (SecurityException readPhoneNumberSecurityException) {
+        }
+
+        throw new SecurityException(message + ": Neither user " + uid
+                + " nor current process has " + android.Manifest.permission.READ_PHONE_STATE
+                + ", " + android.Manifest.permission.READ_SMS + ", or "
+                + android.Manifest.permission.READ_PHONE_NUMBERS);
+    }
+
+    /**
+     * Ensure the caller (or self, if not processing an IPC) has MODIFY_PHONE_STATE (and is thus a
+     * privileged app) or carrier privileges.
+     *
+     * @throws SecurityException if the caller does not have the required permission/privileges
+     */
+    public static void enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
+            Context context, int subId, String message) {
+        if (context.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+                == PERMISSION_GRANTED) {
+            return;
+        }
+
+        if (DBG) Rlog.d(LOG_TAG, "No modify permission, check carrier privilege next.");
+        enforceCallingOrSelfCarrierPrivilege(subId, message);
+    }
+
+    /**
+     * Ensure the caller (or self, if not processing an IPC) has
+     * {@link android.Manifest.permission#READ_PHONE_STATE} or carrier privileges.
+     *
+     * @throws SecurityException if the caller does not have the required permission/privileges
+     */
+    public static void enforeceCallingOrSelfReadPhoneStatePermissionOrCarrierPrivilege(
+            Context context, int subId, String message) {
+        if (context.checkCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE)
+                == PERMISSION_GRANTED) {
+            return;
+        }
+
+        if (DBG) {
+            Rlog.d(LOG_TAG, "No READ_PHONE_STATE permission, check carrier privilege next.");
+        }
+
+        enforceCallingOrSelfCarrierPrivilege(subId, message);
+    }
+
+    /**
+     * Ensure the caller (or self, if not processing an IPC) has
+     * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} or carrier privileges.
+     *
+     * @throws SecurityException if the caller does not have the required permission/privileges
+     */
+    public static void enforeceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
+            Context context, int subId, String message) {
+        if (context.checkCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+                == PERMISSION_GRANTED) {
+            return;
+        }
+
+        if (DBG) {
+            Rlog.d(LOG_TAG, "No READ_PRIVILEDED_PHONE_STATE permission, "
+                    + "check carrier privilege next.");
+        }
+
+        enforceCallingOrSelfCarrierPrivilege(subId, message);
+    }
+
+    /**
+     * Make sure the caller (or self, if not processing an IPC) has carrier privileges.
+     *
+     * @throws SecurityException if the caller does not have the required privileges
+     */
+    public static void enforceCallingOrSelfCarrierPrivilege(int subId, String message) {
+        // NOTE: It's critical that we explicitly pass the calling UID here rather than call
+        // TelephonyManager#hasCarrierPrivileges directly, as the latter only works when called from
+        // the phone process. When called from another process, it will check whether that process
+        // has carrier privileges instead.
+        enforceCarrierPrivilege(subId, Binder.getCallingUid(), message);
+    }
+
+    private static void enforceCarrierPrivilege(int subId, int uid, String message) {
+        enforceCarrierPrivilege(TELEPHONY_SUPPLIER, subId, uid, message);
+    }
+
+    private static void enforceCarrierPrivilege(
+            Supplier<ITelephony> telephonySupplier, int subId, int uid, String message) {
+        if (getCarrierPrivilegeStatus(telephonySupplier, subId, uid)
+                != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+            if (DBG) Rlog.e(LOG_TAG, "No Carrier Privilege.");
+            throw new SecurityException(message);
+        }
+    }
+
+    /** Returns whether the provided uid has carrier privileges for any active subscription ID. */
+    private static boolean checkCarrierPrivilegeForAnySubId(
+            Context context, Supplier<ITelephony> telephonySupplier, int uid) {
+        SubscriptionManager sm = (SubscriptionManager) context.getSystemService(
+                Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+        int[] activeSubIds = sm.getActiveSubscriptionIdList(/* visibleOnly */ false);
+        for (int activeSubId : activeSubIds) {
+            if (getCarrierPrivilegeStatus(telephonySupplier, activeSubId, uid)
+                    == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static int getCarrierPrivilegeStatus(
+            Supplier<ITelephony> telephonySupplier, int subId, int uid) {
+        ITelephony telephony = telephonySupplier.get();
+        try {
+            if (telephony != null) {
+                return telephony.getCarrierPrivilegeStatusForUid(subId, uid);
+            }
+        } catch (RemoteException e) {
+            // Fallback below.
+        }
+        Rlog.e(LOG_TAG, "Phone process is down, cannot check carrier privileges");
+        return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
+    }
+
+    /**
+     * Throws if the caller is not of a shell (or root) UID.
+     *
+     * @param callingUid pass Binder.callingUid().
+     */
+    public static void enforceShellOnly(int callingUid, String message) {
+        if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
+            return; // okay
+        }
+
+        throw new SecurityException(message + ": Only shell user can call it");
+    }
+}
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
deleted file mode 100644
index add0316..0000000
--- a/telephony/java/android/provider/Telephony.java
+++ /dev/null
@@ -1,4856 +0,0 @@
-/*
- * Copyright (C) 2006 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.provider;
-
-import android.Manifest;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SystemApi;
-import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.database.sqlite.SqliteWrapper;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Parcel;
-import android.telephony.Rlog;
-import android.telephony.ServiceState;
-import android.telephony.SmsMessage;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-import android.util.Patterns;
-
-import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.SmsApplication;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * The Telephony provider contains data related to phone operation, specifically SMS and MMS
- * messages, access to the APN list, including the MMSC to use, and the service state.
- *
- * <p class="note"><strong>Note:</strong> These APIs are not available on all Android-powered
- * devices. If your app depends on telephony features such as for managing SMS messages, include
- * a <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code <uses-feature>}
- * </a> element in your manifest that declares the {@code "android.hardware.telephony"} hardware
- * feature. Alternatively, you can check for telephony availability at runtime using either
- * {@link android.content.pm.PackageManager#hasSystemFeature
- * hasSystemFeature(PackageManager.FEATURE_TELEPHONY)} or {@link
- * android.telephony.TelephonyManager#getPhoneType}.</p>
- *
- * <h3>Creating an SMS app</h3>
- *
- * <p>Only the default SMS app (selected by the user in system settings) is able to write to the
- * SMS Provider (the tables defined within the {@code Telephony} class) and only the default SMS
- * app receives the {@link android.provider.Telephony.Sms.Intents#SMS_DELIVER_ACTION} broadcast
- * when the user receives an SMS or the {@link
- * android.provider.Telephony.Sms.Intents#WAP_PUSH_DELIVER_ACTION} broadcast when the user
- * receives an MMS.</p>
- *
- * <p>Any app that wants to behave as the user's default SMS app must handle the following intents:
- * <ul>
- * <li>In a broadcast receiver, include an intent filter for {@link Sms.Intents#SMS_DELIVER_ACTION}
- * (<code>"android.provider.Telephony.SMS_DELIVER"</code>). The broadcast receiver must also
- * require the {@link android.Manifest.permission#BROADCAST_SMS} permission.
- * <p>This allows your app to directly receive incoming SMS messages.</p></li>
- * <li>In a broadcast receiver, include an intent filter for {@link
- * Sms.Intents#WAP_PUSH_DELIVER_ACTION}} ({@code "android.provider.Telephony.WAP_PUSH_DELIVER"})
- * with the MIME type <code>"application/vnd.wap.mms-message"</code>.
- * The broadcast receiver must also require the {@link
- * android.Manifest.permission#BROADCAST_WAP_PUSH} permission.
- * <p>This allows your app to directly receive incoming MMS messages.</p></li>
- * <li>In your activity that delivers new messages, include an intent filter for
- * {@link android.content.Intent#ACTION_SENDTO} (<code>"android.intent.action.SENDTO"
- * </code>) with schemas, <code>sms:</code>, <code>smsto:</code>, <code>mms:</code>, and
- * <code>mmsto:</code>.
- * <p>This allows your app to receive intents from other apps that want to deliver a
- * message.</p></li>
- * <li>In a service, include an intent filter for {@link
- * android.telephony.TelephonyManager#ACTION_RESPOND_VIA_MESSAGE}
- * (<code>"android.intent.action.RESPOND_VIA_MESSAGE"</code>) with schemas,
- * <code>sms:</code>, <code>smsto:</code>, <code>mms:</code>, and <code>mmsto:</code>.
- * This service must also require the {@link
- * android.Manifest.permission#SEND_RESPOND_VIA_MESSAGE} permission.
- * <p>This allows users to respond to incoming phone calls with an immediate text message
- * using your app.</p></li>
- * </ul>
- *
- * <p>Other apps that are not selected as the default SMS app can only <em>read</em> the SMS
- * Provider, but may also be notified when a new SMS arrives by listening for the {@link
- * Sms.Intents#SMS_RECEIVED_ACTION}
- * broadcast, which is a non-abortable broadcast that may be delivered to multiple apps. This
- * broadcast is intended for apps that&mdash;while not selected as the default SMS app&mdash;need to
- * read special incoming messages such as to perform phone number verification.</p>
- *
- * <p>For more information about building SMS apps, read the blog post, <a
- * href="http://android-developers.blogspot.com/2013/10/getting-your-sms-apps-ready-for-kitkat.html"
- * >Getting Your SMS Apps Ready for KitKat</a>.</p>
- *
- */
-public final class Telephony {
-    private static final String TAG = "Telephony";
-
-    /**
-     * Not instantiable.
-     * @hide
-     */
-    private Telephony() {
-    }
-
-    /**
-     * Base columns for tables that contain text-based SMSs.
-     */
-    public interface TextBasedSmsColumns {
-
-        /** Message type: all messages. */
-        public static final int MESSAGE_TYPE_ALL    = 0;
-
-        /** Message type: inbox. */
-        public static final int MESSAGE_TYPE_INBOX  = 1;
-
-        /** Message type: sent messages. */
-        public static final int MESSAGE_TYPE_SENT   = 2;
-
-        /** Message type: drafts. */
-        public static final int MESSAGE_TYPE_DRAFT  = 3;
-
-        /** Message type: outbox. */
-        public static final int MESSAGE_TYPE_OUTBOX = 4;
-
-        /** Message type: failed outgoing message. */
-        public static final int MESSAGE_TYPE_FAILED = 5;
-
-        /** Message type: queued to send later. */
-        public static final int MESSAGE_TYPE_QUEUED = 6;
-
-        /**
-         * The type of message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String TYPE = "type";
-
-        /**
-         * The thread ID of the message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String THREAD_ID = "thread_id";
-
-        /**
-         * The address of the other party.
-         * <P>Type: TEXT</P>
-         */
-        public static final String ADDRESS = "address";
-
-        /**
-         * The date the message was received.
-         * <P>Type: INTEGER (long)</P>
-         */
-        public static final String DATE = "date";
-
-        /**
-         * The date the message was sent.
-         * <P>Type: INTEGER (long)</P>
-         */
-        public static final String DATE_SENT = "date_sent";
-
-        /**
-         * Has the message been read?
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String READ = "read";
-
-        /**
-         * Has the message been seen by the user? The "seen" flag determines
-         * whether we need to show a notification.
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String SEEN = "seen";
-
-        /**
-         * {@code TP-Status} value for the message, or -1 if no status has been received.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String STATUS = "status";
-
-        /** TP-Status: no status received. */
-        public static final int STATUS_NONE = -1;
-        /** TP-Status: complete. */
-        public static final int STATUS_COMPLETE = 0;
-        /** TP-Status: pending. */
-        public static final int STATUS_PENDING = 32;
-        /** TP-Status: failed. */
-        public static final int STATUS_FAILED = 64;
-
-        /**
-         * The subject of the message, if present.
-         * <P>Type: TEXT</P>
-         */
-        public static final String SUBJECT = "subject";
-
-        /**
-         * The body of the message.
-         * <P>Type: TEXT</P>
-         */
-        public static final String BODY = "body";
-
-        /**
-         * The ID of the sender of the conversation, if present.
-         * <P>Type: INTEGER (reference to item in {@code content://contacts/people})</P>
-         */
-        public static final String PERSON = "person";
-
-        /**
-         * The protocol identifier code.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String PROTOCOL = "protocol";
-
-        /**
-         * Is the {@code TP-Reply-Path} flag set?
-         * <P>Type: BOOLEAN</P>
-         */
-        public static final String REPLY_PATH_PRESENT = "reply_path_present";
-
-        /**
-         * The service center (SC) through which to send the message, if present.
-         * <P>Type: TEXT</P>
-         */
-        public static final String SERVICE_CENTER = "service_center";
-
-        /**
-         * Is the message locked?
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String LOCKED = "locked";
-
-        /**
-         * The subscription to which the message belongs to. Its value will be
-         * < 0 if the sub id cannot be determined.
-         * <p>Type: INTEGER (long) </p>
-         */
-        public static final String SUBSCRIPTION_ID = "sub_id";
-
-        /**
-         * The MTU size of the mobile interface to which the APN connected
-         * @hide
-         */
-        public static final String MTU = "mtu";
-
-        /**
-         * Error code associated with sending or receiving this message
-         * <P>Type: INTEGER</P>
-         */
-        public static final String ERROR_CODE = "error_code";
-
-        /**
-         * The identity of the sender of a sent message. It is
-         * usually the package name of the app which sends the message.
-         * <p class="note"><strong>Note:</strong>
-         * This column is read-only. It is set by the provider and can not be changed by apps.
-         * <p>Type: TEXT</p>
-         */
-        public static final String CREATOR = "creator";
-    }
-
-    /**
-     * Columns in sms_changes table.
-     * @hide
-     */
-    public interface TextBasedSmsChangesColumns {
-        /**
-         * The {@code content://} style URL for this table.
-         * @hide
-         */
-        public static final Uri CONTENT_URI = Uri.parse("content://sms-changes");
-
-        /**
-         * Primary key.
-         * <P>Type: INTEGER (long)</P>
-         * @hide
-         */
-        public static final String ID = "_id";
-
-        /**
-         * Triggers on sms table create a row in this table for each update/delete.
-         * This column is the "_id" of the row from sms table that was updated/deleted.
-         * <P>Type: INTEGER (long)</P>
-         * @hide
-         */
-        public static final String ORIG_ROW_ID = "orig_rowid";
-
-        /**
-         * Triggers on sms table create a row in this table for each update/delete.
-         * This column is the "sub_id" of the row from sms table that was updated/deleted.
-         * @hide
-         * <P>Type: INTEGER (long)</P>
-         */
-        public static final String SUB_ID = "sub_id";
-
-        /**
-         * The type of operation that created this row.
-         *    {@link #TYPE_UPDATE} = update op
-         *    {@link #TYPE_DELETE} = delete op
-         * @hide
-         * <P>Type: INTEGER (long)</P>
-         */
-        public static final String TYPE = "type";
-
-        /**
-         * One of the possible values for the above column "type". Indicates it is an update op.
-         * @hide
-         */
-        public static final int TYPE_UPDATE = 0;
-
-        /**
-         * One of the possible values for the above column "type". Indicates it is a delete op.
-         * @hide
-         */
-        public static final int TYPE_DELETE = 1;
-
-        /**
-         * This column contains a non-null value only if the operation on sms table is an update op
-         * and the column "read" is changed by the update op.
-         * <P>Type: INTEGER (boolean)</P>
-         * @hide
-         */
-        public static final String NEW_READ_STATUS = "new_read_status";
-    }
-
-    /**
-     * Contains all text-based SMS messages.
-     */
-    public static final class Sms implements BaseColumns, TextBasedSmsColumns {
-
-        /**
-         * Not instantiable.
-         * @hide
-         */
-        private Sms() {
-        }
-
-        /**
-         * Used to determine the currently configured default SMS package.
-         * @param context context of the requesting application
-         * @return package name for the default SMS package or null
-         */
-        public static String getDefaultSmsPackage(Context context) {
-            ComponentName component = SmsApplication.getDefaultSmsApplication(context, false);
-            if (component != null) {
-                return component.getPackageName();
-            }
-            return null;
-        }
-
-        /**
-         * Return cursor for table query.
-         * @hide
-         */
-        public static Cursor query(ContentResolver cr, String[] projection) {
-            return cr.query(CONTENT_URI, projection, null, null, DEFAULT_SORT_ORDER);
-        }
-
-        /**
-         * Return cursor for table query.
-         * @hide
-         */
-        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-        public static Cursor query(ContentResolver cr, String[] projection,
-                String where, String orderBy) {
-            return cr.query(CONTENT_URI, projection, where,
-                    null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
-        }
-
-        /**
-         * The {@code content://} style URL for this table.
-         */
-        public static final Uri CONTENT_URI = Uri.parse("content://sms");
-
-        /**
-         * The default sort order for this table.
-         */
-        public static final String DEFAULT_SORT_ORDER = "date DESC";
-
-        /**
-         * Add an SMS to the given URI.
-         *
-         * @param resolver the content resolver to use
-         * @param uri the URI to add the message to
-         * @param address the address of the sender
-         * @param body the body of the message
-         * @param subject the pseudo-subject of the message
-         * @param date the timestamp for the message
-         * @param read true if the message has been read, false if not
-         * @param deliveryReport true if a delivery report was requested, false if not
-         * @return the URI for the new message
-         * @hide
-         */
-        @UnsupportedAppUsage
-        public static Uri addMessageToUri(ContentResolver resolver,
-                Uri uri, String address, String body, String subject,
-                Long date, boolean read, boolean deliveryReport) {
-            return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
-                    resolver, uri, address, body, subject, date, read, deliveryReport, -1L);
-        }
-
-        /**
-         * Add an SMS to the given URI.
-         *
-         * @param resolver the content resolver to use
-         * @param uri the URI to add the message to
-         * @param address the address of the sender
-         * @param body the body of the message
-         * @param subject the psuedo-subject of the message
-         * @param date the timestamp for the message
-         * @param read true if the message has been read, false if not
-         * @param deliveryReport true if a delivery report was requested, false if not
-         * @param subId the subscription which the message belongs to
-         * @return the URI for the new message
-         * @hide
-         */
-        @UnsupportedAppUsage
-        public static Uri addMessageToUri(int subId, ContentResolver resolver,
-                Uri uri, String address, String body, String subject,
-                Long date, boolean read, boolean deliveryReport) {
-            return addMessageToUri(subId, resolver, uri, address, body, subject,
-                    date, read, deliveryReport, -1L);
-        }
-
-        /**
-         * Add an SMS to the given URI with the specified thread ID.
-         *
-         * @param resolver the content resolver to use
-         * @param uri the URI to add the message to
-         * @param address the address of the sender
-         * @param body the body of the message
-         * @param subject the pseudo-subject of the message
-         * @param date the timestamp for the message
-         * @param read true if the message has been read, false if not
-         * @param deliveryReport true if a delivery report was requested, false if not
-         * @param threadId the thread_id of the message
-         * @return the URI for the new message
-         * @hide
-         */
-        @UnsupportedAppUsage
-        public static Uri addMessageToUri(ContentResolver resolver,
-                Uri uri, String address, String body, String subject,
-                Long date, boolean read, boolean deliveryReport, long threadId) {
-            return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
-                    resolver, uri, address, body, subject,
-                    date, read, deliveryReport, threadId);
-        }
-
-        /**
-         * Add an SMS to the given URI with thread_id specified.
-         *
-         * @param resolver the content resolver to use
-         * @param uri the URI to add the message to
-         * @param address the address of the sender
-         * @param body the body of the message
-         * @param subject the psuedo-subject of the message
-         * @param date the timestamp for the message
-         * @param read true if the message has been read, false if not
-         * @param deliveryReport true if a delivery report was requested, false if not
-         * @param threadId the thread_id of the message
-         * @param subId the subscription which the message belongs to
-         * @return the URI for the new message
-         * @hide
-         */
-        @UnsupportedAppUsage
-        public static Uri addMessageToUri(int subId, ContentResolver resolver,
-                Uri uri, String address, String body, String subject,
-                Long date, boolean read, boolean deliveryReport, long threadId) {
-            ContentValues values = new ContentValues(8);
-            Rlog.v(TAG,"Telephony addMessageToUri sub id: " + subId);
-
-            values.put(SUBSCRIPTION_ID, subId);
-            values.put(ADDRESS, address);
-            if (date != null) {
-                values.put(DATE, date);
-            }
-            values.put(READ, read ? Integer.valueOf(1) : Integer.valueOf(0));
-            values.put(SUBJECT, subject);
-            values.put(BODY, body);
-            if (deliveryReport) {
-                values.put(STATUS, STATUS_PENDING);
-            }
-            if (threadId != -1L) {
-                values.put(THREAD_ID, threadId);
-            }
-            return resolver.insert(uri, values);
-        }
-
-        /**
-         * Move a message to the given folder.
-         *
-         * @param context the context to use
-         * @param uri the message to move
-         * @param folder the folder to move to
-         * @return true if the operation succeeded
-         * @hide
-         */
-        @UnsupportedAppUsage
-        public static boolean moveMessageToFolder(Context context,
-                Uri uri, int folder, int error) {
-            if (uri == null) {
-                return false;
-            }
-
-            boolean markAsUnread = false;
-            boolean markAsRead = false;
-            switch(folder) {
-            case MESSAGE_TYPE_INBOX:
-            case MESSAGE_TYPE_DRAFT:
-                break;
-            case MESSAGE_TYPE_OUTBOX:
-            case MESSAGE_TYPE_SENT:
-                markAsRead = true;
-                break;
-            case MESSAGE_TYPE_FAILED:
-            case MESSAGE_TYPE_QUEUED:
-                markAsUnread = true;
-                break;
-            default:
-                return false;
-            }
-
-            ContentValues values = new ContentValues(3);
-
-            values.put(TYPE, folder);
-            if (markAsUnread) {
-                values.put(READ, 0);
-            } else if (markAsRead) {
-                values.put(READ, 1);
-            }
-            values.put(ERROR_CODE, error);
-
-            return 1 == SqliteWrapper.update(context, context.getContentResolver(),
-                            uri, values, null, null);
-        }
-
-        /**
-         * Returns true iff the folder (message type) identifies an
-         * outgoing message.
-         * @hide
-         */
-        @UnsupportedAppUsage
-        public static boolean isOutgoingFolder(int messageType) {
-            return  (messageType == MESSAGE_TYPE_FAILED)
-                    || (messageType == MESSAGE_TYPE_OUTBOX)
-                    || (messageType == MESSAGE_TYPE_SENT)
-                    || (messageType == MESSAGE_TYPE_QUEUED);
-        }
-
-        /**
-         * Contains all text-based SMS messages in the SMS app inbox.
-         */
-        public static final class Inbox implements BaseColumns, TextBasedSmsColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Inbox() {
-            }
-
-            /**
-             * The {@code content://} style URL for this table.
-             */
-            public static final Uri CONTENT_URI = Uri.parse("content://sms/inbox");
-
-            /**
-             * The default sort order for this table.
-             */
-            public static final String DEFAULT_SORT_ORDER = "date DESC";
-
-            /**
-             * Add an SMS to the Draft box.
-             *
-             * @param resolver the content resolver to use
-             * @param address the address of the sender
-             * @param body the body of the message
-             * @param subject the pseudo-subject of the message
-             * @param date the timestamp for the message
-             * @param read true if the message has been read, false if not
-             * @return the URI for the new message
-             * @hide
-             */
-            @UnsupportedAppUsage
-            public static Uri addMessage(ContentResolver resolver,
-                    String address, String body, String subject, Long date,
-                    boolean read) {
-                return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
-                        resolver, CONTENT_URI, address, body, subject, date, read, false);
-            }
-
-            /**
-             * Add an SMS to the Draft box.
-             *
-             * @param resolver the content resolver to use
-             * @param address the address of the sender
-             * @param body the body of the message
-             * @param subject the psuedo-subject of the message
-             * @param date the timestamp for the message
-             * @param read true if the message has been read, false if not
-             * @param subId the subscription which the message belongs to
-             * @return the URI for the new message
-             * @hide
-             */
-            @UnsupportedAppUsage
-            public static Uri addMessage(int subId, ContentResolver resolver,
-                    String address, String body, String subject, Long date, boolean read) {
-                return addMessageToUri(subId, resolver, CONTENT_URI, address, body,
-                        subject, date, read, false);
-            }
-        }
-
-        /**
-         * Contains all sent text-based SMS messages in the SMS app.
-         */
-        public static final class Sent implements BaseColumns, TextBasedSmsColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Sent() {
-            }
-
-            /**
-             * The {@code content://} style URL for this table.
-             */
-            public static final Uri CONTENT_URI = Uri.parse("content://sms/sent");
-
-            /**
-             * The default sort order for this table.
-             */
-            public static final String DEFAULT_SORT_ORDER = "date DESC";
-
-            /**
-             * Add an SMS to the Draft box.
-             *
-             * @param resolver the content resolver to use
-             * @param address the address of the sender
-             * @param body the body of the message
-             * @param subject the pseudo-subject of the message
-             * @param date the timestamp for the message
-             * @return the URI for the new message
-             * @hide
-             */
-            @UnsupportedAppUsage
-            public static Uri addMessage(ContentResolver resolver,
-                    String address, String body, String subject, Long date) {
-                return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
-                        resolver, CONTENT_URI, address, body, subject, date, true, false);
-            }
-
-            /**
-             * Add an SMS to the Draft box.
-             *
-             * @param resolver the content resolver to use
-             * @param address the address of the sender
-             * @param body the body of the message
-             * @param subject the psuedo-subject of the message
-             * @param date the timestamp for the message
-             * @param subId the subscription which the message belongs to
-             * @return the URI for the new message
-             * @hide
-             */
-            @UnsupportedAppUsage
-            public static Uri addMessage(int subId, ContentResolver resolver,
-                    String address, String body, String subject, Long date) {
-                return addMessageToUri(subId, resolver, CONTENT_URI, address, body,
-                        subject, date, true, false);
-            }
-        }
-
-        /**
-         * Contains all draft text-based SMS messages in the SMS app.
-         */
-        public static final class Draft implements BaseColumns, TextBasedSmsColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Draft() {
-            }
-
-            /**
-             * The {@code content://} style URL for this table.
-             */
-            public static final Uri CONTENT_URI = Uri.parse("content://sms/draft");
-
-           /**
-            * @hide
-            */
-            @UnsupportedAppUsage
-            public static Uri addMessage(ContentResolver resolver,
-                    String address, String body, String subject, Long date) {
-                return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
-                        resolver, CONTENT_URI, address, body, subject, date, true, false);
-            }
-
-            /**
-             * Add an SMS to the Draft box.
-             *
-             * @param resolver the content resolver to use
-             * @param address the address of the sender
-             * @param body the body of the message
-             * @param subject the psuedo-subject of the message
-             * @param date the timestamp for the message
-             * @param subId the subscription which the message belongs to
-             * @return the URI for the new message
-             * @hide
-             */
-            @UnsupportedAppUsage
-            public static Uri addMessage(int subId, ContentResolver resolver,
-                    String address, String body, String subject, Long date) {
-                return addMessageToUri(subId, resolver, CONTENT_URI, address, body,
-                        subject, date, true, false);
-            }
-
-            /**
-             * The default sort order for this table.
-             */
-            public static final String DEFAULT_SORT_ORDER = "date DESC";
-        }
-
-        /**
-         * Contains all pending outgoing text-based SMS messages.
-         */
-        public static final class Outbox implements BaseColumns, TextBasedSmsColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Outbox() {
-            }
-
-            /**
-             * The {@code content://} style URL for this table.
-             */
-            public static final Uri CONTENT_URI = Uri.parse("content://sms/outbox");
-
-            /**
-             * The default sort order for this table.
-             */
-            public static final String DEFAULT_SORT_ORDER = "date DESC";
-
-            /**
-             * Add an SMS to the outbox.
-             *
-             * @param resolver the content resolver to use
-             * @param address the address of the sender
-             * @param body the body of the message
-             * @param subject the pseudo-subject of the message
-             * @param date the timestamp for the message
-             * @param deliveryReport whether a delivery report was requested for the message
-             * @return the URI for the new message
-             * @hide
-             */
-            @UnsupportedAppUsage
-            public static Uri addMessage(ContentResolver resolver,
-                    String address, String body, String subject, Long date,
-                    boolean deliveryReport, long threadId) {
-                return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
-                        resolver, CONTENT_URI, address, body, subject, date,
-                        true, deliveryReport, threadId);
-            }
-
-            /**
-             * Add an SMS to the Out box.
-             *
-             * @param resolver the content resolver to use
-             * @param address the address of the sender
-             * @param body the body of the message
-             * @param subject the psuedo-subject of the message
-             * @param date the timestamp for the message
-             * @param deliveryReport whether a delivery report was requested for the message
-             * @param subId the subscription which the message belongs to
-             * @return the URI for the new message
-             * @hide
-             */
-            public static Uri addMessage(int subId, ContentResolver resolver,
-                    String address, String body, String subject, Long date,
-                    boolean deliveryReport, long threadId) {
-                return addMessageToUri(subId, resolver, CONTENT_URI, address, body,
-                        subject, date, true, deliveryReport, threadId);
-            }
-        }
-
-        /**
-         * Contains a view of SMS conversations (also referred to as threads). This is similar to
-         * {@link Threads}, but only includes SMS messages and columns relevant to SMS
-         * conversations.
-         * <p>
-         * Note that this view ignores any information about MMS messages, it is a
-         * view of conversations as if MMS messages did not exist at all. This means that all
-         * relevant information, such as snippets and message count, will ignore any MMS messages
-         * that might be in the same thread through other views and present only data based on the
-         * SMS messages in that thread.
-         */
-        public static final class Conversations
-                implements BaseColumns, TextBasedSmsColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Conversations() {
-            }
-
-            /**
-             * The {@code content://} style URL for this table.
-             */
-            public static final Uri CONTENT_URI = Uri.parse("content://sms/conversations");
-
-            /**
-             * The default sort order for this table.
-             */
-            public static final String DEFAULT_SORT_ORDER = "date DESC";
-
-            /**
-             * The first 45 characters of the body of the most recent message.
-             * <P>Type: TEXT</P>
-             */
-            public static final String SNIPPET = "snippet";
-
-            /**
-             * The number of messages in the conversation.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String MESSAGE_COUNT = "msg_count";
-        }
-
-        /**
-         * Contains constants for SMS related Intents that are broadcast.
-         */
-        public static final class Intents {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Intents() {
-            }
-
-            /**
-             * Set by BroadcastReceiver to indicate that the message was handled
-             * successfully.
-             */
-            public static final int RESULT_SMS_HANDLED = 1;
-
-            /**
-             * Set by BroadcastReceiver to indicate a generic error while
-             * processing the message.
-             */
-            public static final int RESULT_SMS_GENERIC_ERROR = 2;
-
-            /**
-             * Set as a "result" extra in the {@link #SMS_REJECTED_ACTION} intent to indicate
-             * insufficient memory to store the message.
-             */
-            public static final int RESULT_SMS_OUT_OF_MEMORY = 3;
-
-            /**
-             * Set as a "result" extra in the {@link #SMS_REJECTED_ACTION} intent to indicate that
-             * the message, while possibly valid, is of a format or encoding that is not supported.
-             */
-            public static final int RESULT_SMS_UNSUPPORTED = 4;
-
-            /**
-             * Set as a "result" extra in the {@link #SMS_REJECTED_ACTION} intent to indicate a
-             * duplicate incoming message.
-             */
-            public static final int RESULT_SMS_DUPLICATED = 5;
-
-            /**
-             * Set as a "result" extra in the {@link #SMS_REJECTED_ACTION} intent to indicate a
-             * dispatch failure.
-             */
-            public static final int RESULT_SMS_DISPATCH_FAILURE = 6;
-
-            /**
-             * Set as a "result" extra in the {@link #SMS_REJECTED_ACTION} intent to indicate a null
-             * PDU was received.
-             */
-            public static final int RESULT_SMS_NULL_PDU = 7;
-
-            /**
-             * Set as a "result" extra in the {@link #SMS_REJECTED_ACTION} intent to indicate a null
-             * message was encountered.
-             */
-            public static final int RESULT_SMS_NULL_MESSAGE = 8;
-
-            /**
-             * Set as a "result" extra in the {@link #SMS_REJECTED_ACTION} intent to indicate an sms
-             * was received while the phone was in encrypted state.
-             */
-            public static final int RESULT_SMS_RECEIVED_WHILE_ENCRYPTED = 9;
-
-            /**
-             * Set as a "result" extra in the {@link #SMS_REJECTED_ACTION} intent to indicate a
-             * telephony database error.
-             */
-            public static final int RESULT_SMS_DATABASE_ERROR = 10;
-
-            /**
-             * Set as a "result" extra in the {@link #SMS_REJECTED_ACTION} intent to indicate an
-             * invalid uri.
-             */
-            public static final int RESULT_SMS_INVALID_URI = 11;
-
-            /**
-             * Activity action: Ask the user to change the default
-             * SMS application. This will show a dialog that asks the
-             * user whether they want to replace the current default
-             * SMS application with the one specified in
-             * {@link #EXTRA_PACKAGE_NAME}.
-             * <p>
-             * This is no longer supported since Q, please use
-             * {@link android.app.role.RoleManager#createRequestRoleIntent(String)} with
-             * {@link android.app.role.RoleManager#ROLE_SMS} instead.
-             */
-            @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-            public static final String ACTION_CHANGE_DEFAULT =
-                    "android.provider.Telephony.ACTION_CHANGE_DEFAULT";
-
-            /**
-             * The PackageName string passed in as an
-             * extra for {@link #ACTION_CHANGE_DEFAULT}
-             *
-             * @see #ACTION_CHANGE_DEFAULT
-             * <p>
-             * This is no longer supported since Q, please use
-             * {@link android.app.role.RoleManager#createRequestRoleIntent(String)} with
-             * {@link android.app.role.RoleManager#ROLE_SMS} instead.
-             */
-            public static final String EXTRA_PACKAGE_NAME = "package";
-
-            /**
-             * Broadcast Action: A new text-based SMS message has been received
-             * by the device. This intent will only be delivered to the default
-             * sms app. That app is responsible for writing the message and notifying
-             * the user. The intent will have the following extra values:</p>
-             *
-             * <ul>
-             *   <li><em>"pdus"</em> - An Object[] of byte[]s containing the PDUs
-             *   that make up the message.</li>
-             *   <li><em>"format"</em> - A String describing the format of the PDUs. It can
-             *   be either "3gpp" or "3gpp2".</li>
-             *   <li><em>"subscription"</em> - An optional long value of the subscription id which
-             *   received the message.</li>
-             *   <li><em>"slot"</em> - An optional int value of the SIM slot containing the
-             *   subscription.</li>
-             *   <li><em>"phone"</em> - An optional int value of the phone id associated with the
-             *   subscription.</li>
-             *   <li><em>"errorCode"</em> - An optional int error code associated with receiving
-             *   the message.</li>
-             * </ul>
-             *
-             * <p>The extra values can be extracted using
-             * {@link #getMessagesFromIntent(Intent)}.</p>
-             *
-             * <p>If a BroadcastReceiver encounters an error while processing
-             * this intent it should set the result code appropriately.</p>
-             *
-             * <p class="note"><strong>Note:</strong>
-             * The broadcast receiver that filters for this intent must declare
-             * {@link android.Manifest.permission#BROADCAST_SMS} as a required permission in
-             * the <a href="{@docRoot}guide/topics/manifest/receiver-element.html">{@code
-             * <receiver>}</a> tag.
-             *
-             * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String SMS_DELIVER_ACTION =
-                    "android.provider.Telephony.SMS_DELIVER";
-
-            /**
-             * Broadcast Action: A new text-based SMS message has been received
-             * by the device. This intent will be delivered to all registered
-             * receivers as a notification. These apps are not expected to write the
-             * message or notify the user. The intent will have the following extra
-             * values:</p>
-             *
-             * <ul>
-             *   <li><em>"pdus"</em> - An Object[] of byte[]s containing the PDUs
-             *   that make up the message.</li>
-             * </ul>
-             *
-             * <p>The extra values can be extracted using
-             * {@link #getMessagesFromIntent(Intent)}.</p>
-             *
-             * <p>If a BroadcastReceiver encounters an error while processing
-             * this intent it should set the result code appropriately.</p>
-             *
-             * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String SMS_RECEIVED_ACTION =
-                    "android.provider.Telephony.SMS_RECEIVED";
-
-            /**
-             * Broadcast Action: A new data based SMS message has been received
-             * by the device. This intent will be delivered to all registered
-             * receivers as a notification. The intent will have the following extra
-             * values:</p>
-             *
-             * <ul>
-             *   <li><em>"pdus"</em> - An Object[] of byte[]s containing the PDUs
-             *   that make up the message.</li>
-             * </ul>
-             *
-             * <p>The extra values can be extracted using
-             * {@link #getMessagesFromIntent(Intent)}.</p>
-             *
-             * <p>If a BroadcastReceiver encounters an error while processing
-             * this intent it should set the result code appropriately.</p>
-             *
-             * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String DATA_SMS_RECEIVED_ACTION =
-                    "android.intent.action.DATA_SMS_RECEIVED";
-
-            /**
-             * Broadcast Action: A new WAP PUSH message has been received by the
-             * device. This intent will only be delivered to the default
-             * sms app. That app is responsible for writing the message and notifying
-             * the user. The intent will have the following extra values:</p>
-             *
-             * <ul>
-             *   <li><em>"transactionId"</em> - (Integer) The WAP transaction ID</li>
-             *   <li><em>"pduType"</em> - (Integer) The WAP PDU type</li>
-             *   <li><em>"header"</em> - (byte[]) The header of the message</li>
-             *   <li><em>"data"</em> - (byte[]) The data payload of the message</li>
-             *   <li><em>"contentTypeParameters" </em>
-             *   -(HashMap&lt;String,String&gt;) Any parameters associated with the content type
-             *   (decoded from the WSP Content-Type header)</li>
-             *   <li><em>"subscription"</em> - An optional long value of the subscription id which
-             *   received the message.</li>
-             *   <li><em>"slot"</em> - An optional int value of the SIM slot containing the
-             *   subscription.</li>
-             *   <li><em>"phone"</em> - An optional int value of the phone id associated with the
-             *   subscription.</li>
-             * </ul>
-             *
-             * <p>If a BroadcastReceiver encounters an error while processing
-             * this intent it should set the result code appropriately.</p>
-             *
-             * <p>The contentTypeParameters extra value is map of content parameters keyed by
-             * their names.</p>
-             *
-             * <p>If any unassigned well-known parameters are encountered, the key of the map will
-             * be 'unassigned/0x...', where '...' is the hex value of the unassigned parameter.  If
-             * a parameter has No-Value the value in the map will be null.</p>
-             *
-             * <p>Requires {@link android.Manifest.permission#RECEIVE_MMS} or
-             * {@link android.Manifest.permission#RECEIVE_WAP_PUSH} (depending on WAP PUSH type) to
-             * receive.</p>
-             *
-             * <p class="note"><strong>Note:</strong>
-             * The broadcast receiver that filters for this intent must declare
-             * {@link android.Manifest.permission#BROADCAST_WAP_PUSH} as a required permission in
-             * the <a href="{@docRoot}guide/topics/manifest/receiver-element.html">{@code
-             * <receiver>}</a> tag.
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String WAP_PUSH_DELIVER_ACTION =
-                    "android.provider.Telephony.WAP_PUSH_DELIVER";
-
-            /**
-             * Broadcast Action: A new WAP PUSH message has been received by the
-             * device. This intent will be delivered to all registered
-             * receivers as a notification. These apps are not expected to write the
-             * message or notify the user. The intent will have the following extra
-             * values:</p>
-             *
-             * <ul>
-             *   <li><em>"transactionId"</em> - (Integer) The WAP transaction ID</li>
-             *   <li><em>"pduType"</em> - (Integer) The WAP PDU type</li>
-             *   <li><em>"header"</em> - (byte[]) The header of the message</li>
-             *   <li><em>"data"</em> - (byte[]) The data payload of the message</li>
-             *   <li><em>"contentTypeParameters"</em>
-             *   - (HashMap&lt;String,String&gt;) Any parameters associated with the content type
-             *   (decoded from the WSP Content-Type header)</li>
-             * </ul>
-             *
-             * <p>If a BroadcastReceiver encounters an error while processing
-             * this intent it should set the result code appropriately.</p>
-             *
-             * <p>The contentTypeParameters extra value is map of content parameters keyed by
-             * their names.</p>
-             *
-             * <p>If any unassigned well-known parameters are encountered, the key of the map will
-             * be 'unassigned/0x...', where '...' is the hex value of the unassigned parameter.  If
-             * a parameter has No-Value the value in the map will be null.</p>
-             *
-             * <p>Requires {@link android.Manifest.permission#RECEIVE_MMS} or
-             * {@link android.Manifest.permission#RECEIVE_WAP_PUSH} (depending on WAP PUSH type) to
-             * receive.</p>
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String WAP_PUSH_RECEIVED_ACTION =
-                    "android.provider.Telephony.WAP_PUSH_RECEIVED";
-
-            /**
-             * Broadcast Action: A new Cell Broadcast message has been received
-             * by the device. The intent will have the following extra
-             * values:</p>
-             *
-             * <ul>
-             *   <li><em>"message"</em> - An SmsCbMessage object containing the broadcast message
-             *   data. This is not an emergency alert, so ETWS and CMAS data will be null.</li>
-             * </ul>
-             *
-             * <p>The extra values can be extracted using
-             * {@link #getMessagesFromIntent(Intent)}.</p>
-             *
-             * <p>If a BroadcastReceiver encounters an error while processing
-             * this intent it should set the result code appropriately.</p>
-             *
-             * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String SMS_CB_RECEIVED_ACTION =
-                    "android.provider.Telephony.SMS_CB_RECEIVED";
-
-            /**
-             * Action: A SMS based carrier provision intent. Used to identify default
-             * carrier provisioning app on the device.
-             * @hide
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            @TestApi
-            public static final String SMS_CARRIER_PROVISION_ACTION =
-                    "android.provider.Telephony.SMS_CARRIER_PROVISION";
-
-            /**
-             * Broadcast Action: A new Emergency Broadcast message has been received
-             * by the device. The intent will have the following extra
-             * values:</p>
-             *
-             * <ul>
-             *   <li><em>"message"</em> - An {@link android.telephony.SmsCbMessage} object
-             *   containing the broadcast message data, including ETWS or CMAS warning notification
-             *   info if present.</li>
-             * </ul>
-             *
-             * <p>The extra values can be extracted using
-             * {@link #getMessagesFromIntent(Intent)}.</p>
-             *
-             * <p>If a BroadcastReceiver encounters an error while processing
-             * this intent it should set the result code appropriately.</p>
-             *
-             * <p>Requires {@link android.Manifest.permission#RECEIVE_EMERGENCY_BROADCAST} to
-             * receive.</p>
-             * @hide
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            @SystemApi
-            public static final String ACTION_SMS_EMERGENCY_CB_RECEIVED =
-                    "android.provider.action.SMS_EMERGENCY_CB_RECEIVED";
-
-            /**
-             * Broadcast Action: A new CDMA SMS has been received containing Service Category
-             * Program Data (updates the list of enabled broadcast channels). The intent will
-             * have the following extra values:</p>
-             *
-             * <ul>
-             *   <li><em>"operations"</em> - An array of CdmaSmsCbProgramData objects containing
-             *   the service category operations (add/delete/clear) to perform.</li>
-             * </ul>
-             *
-             * <p>The extra values can be extracted using
-             * {@link #getMessagesFromIntent(Intent)}.</p>
-             *
-             * <p>If a BroadcastReceiver encounters an error while processing
-             * this intent it should set the result code appropriately.</p>
-             *
-             * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION =
-                    "android.provider.Telephony.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED";
-
-            /**
-             * Broadcast Action: The SIM storage for SMS messages is full.  If
-             * space is not freed, messages targeted for the SIM (class 2) may
-             * not be saved.
-             *
-             * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String SIM_FULL_ACTION =
-                    "android.provider.Telephony.SIM_FULL";
-
-            /**
-             * Broadcast Action: An incoming SMS has been rejected by the
-             * telephony framework.  This intent is sent in lieu of any
-             * of the RECEIVED_ACTION intents.  The intent will have the
-             * following extra value:</p>
-             *
-             * <ul>
-             *   <li><em>"result"</em> - An int result code, e.g. {@link #RESULT_SMS_OUT_OF_MEMORY}
-             *   indicating the error returned to the network.</li>
-             * </ul>
-             *
-             * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String SMS_REJECTED_ACTION =
-                "android.provider.Telephony.SMS_REJECTED";
-
-            /**
-             * Broadcast Action: An incoming MMS has been downloaded. The intent is sent to all
-             * users, except for secondary users where SMS has been disabled and to managed
-             * profiles.
-             * @hide
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String MMS_DOWNLOADED_ACTION =
-                "android.provider.Telephony.MMS_DOWNLOADED";
-
-            /**
-             * Broadcast Action: A debug code has been entered in the dialer. This intent is
-             * broadcast by the system and OEM telephony apps may need to receive these broadcasts.
-             * These "secret codes" are used to activate developer menus by dialing certain codes.
-             * And they are of the form {@code *#*#<code>#*#*}. The intent will have the data
-             * URI: {@code android_secret_code://<code>}. It is possible that a manifest
-             * receiver would be woken up even if it is not currently running.
-             *
-             * <p>Requires {@code android.Manifest.permission#CONTROL_INCALL_EXPERIENCE} to
-             * send and receive.</p>
-             * @deprecated it is no longer supported, use {@link
-             * TelephonyManager#ACTION_SECRET_CODE} instead
-             */
-            @Deprecated
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String SECRET_CODE_ACTION =
-                    "android.provider.Telephony.SECRET_CODE";
-
-            /**
-             * Broadcast action: When the default SMS package changes,
-             * the previous default SMS package and the new default SMS
-             * package are sent this broadcast to notify them of the change.
-             * A boolean is specified in {@link #EXTRA_IS_DEFAULT_SMS_APP} to
-             * indicate whether the package is the new default SMS package.
-            */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String ACTION_DEFAULT_SMS_PACKAGE_CHANGED =
-                            "android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED";
-
-            /**
-             * The IsDefaultSmsApp boolean passed as an
-             * extra for {@link #ACTION_DEFAULT_SMS_PACKAGE_CHANGED} to indicate whether the
-             * SMS app is becoming the default SMS app or is no longer the default.
-             *
-             * @see #ACTION_DEFAULT_SMS_PACKAGE_CHANGED
-             */
-            public static final String EXTRA_IS_DEFAULT_SMS_APP =
-                    "android.provider.extra.IS_DEFAULT_SMS_APP";
-
-            /**
-             * Broadcast action: When a change is made to the SmsProvider or
-             * MmsProvider by a process other than the default SMS application,
-             * this intent is broadcast to the default SMS application so it can
-             * re-sync or update the change. The uri that was used to call the provider
-             * can be retrieved from the intent with getData(). The actual affected uris
-             * (which would depend on the selection specified) are not included.
-            */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String ACTION_EXTERNAL_PROVIDER_CHANGE =
-                          "android.provider.action.EXTERNAL_PROVIDER_CHANGE";
-
-            /**
-             * Same as {@link #ACTION_DEFAULT_SMS_PACKAGE_CHANGED} but it's implicit (e.g. sent to
-             * all apps) and requires
-             * {@link android.Manifest.permission#MONITOR_DEFAULT_SMS_PACKAGE} to receive.
-             *
-             * @hide
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL =
-                    "android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL";
-
-            /**
-             * Broadcast action: When SMS-MMS db is being created. If file-based encryption is
-             * supported, this broadcast indicates creation of the db in credential-encrypted
-             * storage. A boolean is specified in {@link #EXTRA_IS_INITIAL_CREATE} to indicate if
-             * this is the initial create of the db. Requires
-             * {@link android.Manifest.permission#READ_SMS} to receive.
-             *
-             * @see #EXTRA_IS_INITIAL_CREATE
-             *
-             * @hide
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String ACTION_SMS_MMS_DB_CREATED =
-                    "android.provider.action.SMS_MMS_DB_CREATED";
-
-            /**
-             * Boolean flag passed as an extra with {@link #ACTION_SMS_MMS_DB_CREATED} to indicate
-             * whether the DB creation is the initial creation on the device, that is it is after a
-             * factory-data reset or a new device. Any subsequent creations of the DB (which
-             * happens only in error scenarios) will have this flag set to false.
-             *
-             * @see #ACTION_SMS_MMS_DB_CREATED
-             *
-             * @hide
-             */
-            public static final String EXTRA_IS_INITIAL_CREATE =
-                    "android.provider.extra.IS_INITIAL_CREATE";
-
-            /**
-             * Broadcast intent action indicating that the telephony provider SMS MMS database is
-             * corrupted. A boolean is specified in {@link #EXTRA_IS_CORRUPTED} to indicate if the
-             * database is corrupted. Requires the
-             * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE permission.
-             *
-             * @hide
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-            public static final String ACTION_SMS_MMS_DB_LOST =
-                    "android.provider.action.SMS_MMS_DB_LOST";
-
-            /**
-             * Boolean flag passed as an extra with {@link #ACTION_SMS_MMS_DB_LOST} to indicate
-             * whether the DB got corrupted or not.
-             *
-             * @see #ACTION_SMS_MMS_DB_LOST
-             *
-             * @hide
-             */
-            public static final String EXTRA_IS_CORRUPTED =
-                    "android.provider.extra.IS_CORRUPTED";
-
-            /**
-             * Read the PDUs out of an {@link #SMS_RECEIVED_ACTION} or a
-             * {@link #DATA_SMS_RECEIVED_ACTION} intent.
-             *
-             * @param intent the intent to read from
-             * @return an array of SmsMessages for the PDUs
-             */
-            public static SmsMessage[] getMessagesFromIntent(Intent intent) {
-                Object[] messages;
-                try {
-                    messages = (Object[]) intent.getSerializableExtra("pdus");
-                }
-                catch (ClassCastException e) {
-                    Rlog.e(TAG, "getMessagesFromIntent: " + e);
-                    return null;
-                }
-
-                if (messages == null) {
-                    Rlog.e(TAG, "pdus does not exist in the intent");
-                    return null;
-                }
-
-                String format = intent.getStringExtra("format");
-                int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
-                        SubscriptionManager.getDefaultSmsSubscriptionId());
-
-                Rlog.v(TAG, " getMessagesFromIntent sub_id : " + subId);
-
-                int pduCount = messages.length;
-                SmsMessage[] msgs = new SmsMessage[pduCount];
-
-                for (int i = 0; i < pduCount; i++) {
-                    byte[] pdu = (byte[]) messages[i];
-                    msgs[i] = SmsMessage.createFromPdu(pdu, format);
-                    if (msgs[i] != null) msgs[i].setSubId(subId);
-                }
-                return msgs;
-            }
-        }
-    }
-
-    /**
-     * Base column for the table that contain Carrier Public key.
-     * @hide
-     */
-    @SystemApi
-    public interface CarrierColumns extends BaseColumns {
-
-        /**
-         * Mobile Country Code (MCC).
-         * <P> Type: TEXT </P>
-         */
-        public static final String MCC = "mcc";
-
-        /**
-         * Mobile Network Code (MNC).
-         * <P> Type: TEXT </P>
-         */
-        public static final String MNC = "mnc";
-
-        /**
-         * KeyType whether the key is being used for WLAN or ePDG.
-         * <P> Type: INTEGER </P>
-         */
-        public static final String KEY_TYPE = "key_type";
-
-        /**
-         * MVNO type:
-         * {@code SPN (Service Provider Name), IMSI, GID (Group Identifier Level 1)}.
-         * <P> Type: TEXT </P>
-         */
-        public static final String MVNO_TYPE = "mvno_type";
-
-        /**
-         * MVNO data.
-         * Use the following examples.
-         * <ul>
-         *     <li>SPN: A MOBILE, BEN NL, ...</li>
-         *     <li>IMSI: 302720x94, 2060188, ...</li>
-         *     <li>GID: 4E, 33, ...</li>
-         * </ul>
-         * <P> Type: TEXT </P>
-         */
-        public static final String MVNO_MATCH_DATA = "mvno_match_data";
-
-        /**
-         * The carrier public key that is used for the IMSI encryption.
-         * <P> Type: TEXT </P>
-         */
-        public static final String PUBLIC_KEY = "public_key";
-
-        /**
-         * The key identifier Attribute value pair that helps a server locate
-         * the private key to decrypt the permanent identity.
-         * <P> Type: TEXT </P>
-         */
-        public static final String KEY_IDENTIFIER = "key_identifier";
-
-        /**
-         * Date-Time in UTC when the key will expire.
-         * <P> Type: INTEGER (long) </P>
-         */
-        public static final String EXPIRATION_TIME = "expiration_time";
-
-        /**
-         * Timestamp when this table was last modified, in milliseconds since
-         * January 1, 1970 00:00:00.0 UTC.
-         * <P> Type: INTEGER (long) </P>
-         */
-        public static final String LAST_MODIFIED = "last_modified";
-
-        /**
-         * The {@code content://} style URL for this table.
-         */
-        @NonNull
-        public static final Uri CONTENT_URI = Uri.parse("content://carrier_information/carrier");
-    }
-
-    /**
-     * Base columns for tables that contain MMSs.
-     */
-    public interface BaseMmsColumns extends BaseColumns {
-
-        /** Message box: all messages. */
-        public static final int MESSAGE_BOX_ALL    = 0;
-        /** Message box: inbox. */
-        public static final int MESSAGE_BOX_INBOX  = 1;
-        /** Message box: sent messages. */
-        public static final int MESSAGE_BOX_SENT   = 2;
-        /** Message box: drafts. */
-        public static final int MESSAGE_BOX_DRAFTS = 3;
-        /** Message box: outbox. */
-        public static final int MESSAGE_BOX_OUTBOX = 4;
-        /** Message box: failed. */
-        public static final int MESSAGE_BOX_FAILED = 5;
-
-        /**
-         * The thread ID of the message.
-         * <P>Type: INTEGER (long)</P>
-         */
-        public static final String THREAD_ID = "thread_id";
-
-        /**
-         * The date the message was received.
-         * <P>Type: INTEGER (long)</P>
-         */
-        public static final String DATE = "date";
-
-        /**
-         * The date the message was sent.
-         * <P>Type: INTEGER (long)</P>
-         */
-        public static final String DATE_SENT = "date_sent";
-
-        /**
-         * The box which the message belongs to, e.g. {@link #MESSAGE_BOX_INBOX}.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String MESSAGE_BOX = "msg_box";
-
-        /**
-         * Has the message been read?
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String READ = "read";
-
-        /**
-         * Has the message been seen by the user? The "seen" flag determines
-         * whether we need to show a new message notification.
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String SEEN = "seen";
-
-        /**
-         * Does the message have only a text part (can also have a subject) with
-         * no picture, slideshow, sound, etc. parts?
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String TEXT_ONLY = "text_only";
-
-        /**
-         * The {@code Message-ID} of the message.
-         * <P>Type: TEXT</P>
-         */
-        public static final String MESSAGE_ID = "m_id";
-
-        /**
-         * The subject of the message, if present.
-         * <P>Type: TEXT</P>
-         */
-        public static final String SUBJECT = "sub";
-
-        /**
-         * The character set of the subject, if present.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String SUBJECT_CHARSET = "sub_cs";
-
-        /**
-         * The {@code Content-Type} of the message.
-         * <P>Type: TEXT</P>
-         */
-        public static final String CONTENT_TYPE = "ct_t";
-
-        /**
-         * The {@code Content-Location} of the message.
-         * <P>Type: TEXT</P>
-         */
-        public static final String CONTENT_LOCATION = "ct_l";
-
-        /**
-         * The expiry time of the message.
-         * <P>Type: INTEGER (long)</P>
-         */
-        public static final String EXPIRY = "exp";
-
-        /**
-         * The class of the message.
-         * <P>Type: TEXT</P>
-         */
-        public static final String MESSAGE_CLASS = "m_cls";
-
-        /**
-         * The type of the message defined by MMS spec.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String MESSAGE_TYPE = "m_type";
-
-        /**
-         * The version of the specification that this message conforms to.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String MMS_VERSION = "v";
-
-        /**
-         * The size of the message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String MESSAGE_SIZE = "m_size";
-
-        /**
-         * The priority of the message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String PRIORITY = "pri";
-
-        /**
-         * The {@code read-report} of the message.
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String READ_REPORT = "rr";
-
-        /**
-         * Is read report allowed?
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String REPORT_ALLOWED = "rpt_a";
-
-        /**
-         * The {@code response-status} of the message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String RESPONSE_STATUS = "resp_st";
-
-        /**
-         * The {@code status} of the message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String STATUS = "st";
-
-        /**
-         * The {@code transaction-id} of the message.
-         * <P>Type: TEXT</P>
-         */
-        public static final String TRANSACTION_ID = "tr_id";
-
-        /**
-         * The {@code retrieve-status} of the message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String RETRIEVE_STATUS = "retr_st";
-
-        /**
-         * The {@code retrieve-text} of the message.
-         * <P>Type: TEXT</P>
-         */
-        public static final String RETRIEVE_TEXT = "retr_txt";
-
-        /**
-         * The character set of the retrieve-text.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String RETRIEVE_TEXT_CHARSET = "retr_txt_cs";
-
-        /**
-         * The {@code read-status} of the message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String READ_STATUS = "read_status";
-
-        /**
-         * The {@code content-class} of the message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String CONTENT_CLASS = "ct_cls";
-
-        /**
-         * The {@code delivery-report} of the message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String DELIVERY_REPORT = "d_rpt";
-
-        /**
-         * The {@code delivery-time-token} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String DELIVERY_TIME_TOKEN = "d_tm_tok";
-
-        /**
-         * The {@code delivery-time} of the message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String DELIVERY_TIME = "d_tm";
-
-        /**
-         * The {@code response-text} of the message.
-         * <P>Type: TEXT</P>
-         */
-        public static final String RESPONSE_TEXT = "resp_txt";
-
-        /**
-         * The {@code sender-visibility} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String SENDER_VISIBILITY = "s_vis";
-
-        /**
-         * The {@code reply-charging} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String REPLY_CHARGING = "r_chg";
-
-        /**
-         * The {@code reply-charging-deadline-token} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String REPLY_CHARGING_DEADLINE_TOKEN = "r_chg_dl_tok";
-
-        /**
-         * The {@code reply-charging-deadline} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String REPLY_CHARGING_DEADLINE = "r_chg_dl";
-
-        /**
-         * The {@code reply-charging-id} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String REPLY_CHARGING_ID = "r_chg_id";
-
-        /**
-         * The {@code reply-charging-size} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String REPLY_CHARGING_SIZE = "r_chg_sz";
-
-        /**
-         * The {@code previously-sent-by} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String PREVIOUSLY_SENT_BY = "p_s_by";
-
-        /**
-         * The {@code previously-sent-date} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String PREVIOUSLY_SENT_DATE = "p_s_d";
-
-        /**
-         * The {@code store} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String STORE = "store";
-
-        /**
-         * The {@code mm-state} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String MM_STATE = "mm_st";
-
-        /**
-         * The {@code mm-flags-token} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String MM_FLAGS_TOKEN = "mm_flg_tok";
-
-        /**
-         * The {@code mm-flags} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String MM_FLAGS = "mm_flg";
-
-        /**
-         * The {@code store-status} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String STORE_STATUS = "store_st";
-
-        /**
-         * The {@code store-status-text} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String STORE_STATUS_TEXT = "store_st_txt";
-
-        /**
-         * The {@code stored} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String STORED = "stored";
-
-        /**
-         * The {@code totals} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String TOTALS = "totals";
-
-        /**
-         * The {@code mbox-totals} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String MBOX_TOTALS = "mb_t";
-
-        /**
-         * The {@code mbox-totals-token} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String MBOX_TOTALS_TOKEN = "mb_t_tok";
-
-        /**
-         * The {@code quotas} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String QUOTAS = "qt";
-
-        /**
-         * The {@code mbox-quotas} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String MBOX_QUOTAS = "mb_qt";
-
-        /**
-         * The {@code mbox-quotas-token} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String MBOX_QUOTAS_TOKEN = "mb_qt_tok";
-
-        /**
-         * The {@code message-count} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String MESSAGE_COUNT = "m_cnt";
-
-        /**
-         * The {@code start} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String START = "start";
-
-        /**
-         * The {@code distribution-indicator} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String DISTRIBUTION_INDICATOR = "d_ind";
-
-        /**
-         * The {@code element-descriptor} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String ELEMENT_DESCRIPTOR = "e_des";
-
-        /**
-         * The {@code limit} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String LIMIT = "limit";
-
-        /**
-         * The {@code recommended-retrieval-mode} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String RECOMMENDED_RETRIEVAL_MODE = "r_r_mod";
-
-        /**
-         * The {@code recommended-retrieval-mode-text} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String RECOMMENDED_RETRIEVAL_MODE_TEXT = "r_r_mod_txt";
-
-        /**
-         * The {@code status-text} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String STATUS_TEXT = "st_txt";
-
-        /**
-         * The {@code applic-id} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String APPLIC_ID = "apl_id";
-
-        /**
-         * The {@code reply-applic-id} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String REPLY_APPLIC_ID = "r_apl_id";
-
-        /**
-         * The {@code aux-applic-id} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String AUX_APPLIC_ID = "aux_apl_id";
-
-        /**
-         * The {@code drm-content} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String DRM_CONTENT = "drm_c";
-
-        /**
-         * The {@code adaptation-allowed} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String ADAPTATION_ALLOWED = "adp_a";
-
-        /**
-         * The {@code replace-id} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String REPLACE_ID = "repl_id";
-
-        /**
-         * The {@code cancel-id} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String CANCEL_ID = "cl_id";
-
-        /**
-         * The {@code cancel-status} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String CANCEL_STATUS = "cl_st";
-
-        /**
-         * Is the message locked?
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String LOCKED = "locked";
-
-        /**
-         * The subscription to which the message belongs to. Its value will be
-         * < 0 if the sub id cannot be determined.
-         * <p>Type: INTEGER (long)</p>
-         */
-        public static final String SUBSCRIPTION_ID = "sub_id";
-
-        /**
-         * The identity of the sender of a sent message. It is
-         * usually the package name of the app which sends the message.
-         * <p class="note"><strong>Note:</strong>
-         * This column is read-only. It is set by the provider and can not be changed by apps.
-         * <p>Type: TEXT</p>
-         */
-        public static final String CREATOR = "creator";
-    }
-
-    /**
-     * Columns for the "canonical_addresses" table used by MMS and SMS.
-     */
-    public interface CanonicalAddressesColumns extends BaseColumns {
-        /**
-         * An address used in MMS or SMS.  Email addresses are
-         * converted to lower case and are compared by string
-         * equality.  Other addresses are compared using
-         * PHONE_NUMBERS_EQUAL.
-         * <P>Type: TEXT</P>
-         */
-        public static final String ADDRESS = "address";
-    }
-
-    /**
-     * Columns for the "threads" table used by MMS and SMS.
-     */
-    public interface ThreadsColumns extends BaseColumns {
-
-        /**
-         * The date at which the thread was created.
-         * <P>Type: INTEGER (long)</P>
-         */
-        public static final String DATE = "date";
-
-        /**
-         * A string encoding of the recipient IDs of the recipients of
-         * the message, in numerical order and separated by spaces.
-         * <P>Type: TEXT</P>
-         */
-        public static final String RECIPIENT_IDS = "recipient_ids";
-
-        /**
-         * The message count of the thread.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String MESSAGE_COUNT = "message_count";
-
-        /**
-         * Indicates whether all messages of the thread have been read.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String READ = "read";
-
-        /**
-         * The snippet of the latest message in the thread.
-         * <P>Type: TEXT</P>
-         */
-        public static final String SNIPPET = "snippet";
-
-        /**
-         * The charset of the snippet.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String SNIPPET_CHARSET = "snippet_cs";
-
-        /**
-         * Type of the thread, either {@link Threads#COMMON_THREAD} or
-         * {@link Threads#BROADCAST_THREAD}.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String TYPE = "type";
-
-        /**
-         * Indicates whether there is a transmission error in the thread.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String ERROR = "error";
-
-        /**
-         * Indicates whether this thread contains any attachments.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String HAS_ATTACHMENT = "has_attachment";
-
-        /**
-         * If the thread is archived
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String ARCHIVED = "archived";
-    }
-
-    /**
-     * Helper functions for the "threads" table used by MMS and SMS.
-     *
-     * Thread IDs are determined by the participants in a conversation and can be used to match
-     * both SMS and MMS messages.
-     *
-     * To avoid issues where applications might cache a thread ID, the thread ID of a deleted thread
-     * must not be reused to point at a new thread.
-     */
-    public static final class Threads implements ThreadsColumns {
-
-        @UnsupportedAppUsage
-        private static final String[] ID_PROJECTION = { BaseColumns._ID };
-
-        /**
-         * Private {@code content://} style URL for this table. Used by
-         * {@link #getOrCreateThreadId(android.content.Context, java.util.Set)}.
-         */
-        @UnsupportedAppUsage
-        private static final Uri THREAD_ID_CONTENT_URI = Uri.parse(
-                "content://mms-sms/threadID");
-
-        /**
-         * The {@code content://} style URL for this table, by conversation.
-         */
-        public static final Uri CONTENT_URI = Uri.withAppendedPath(
-                MmsSms.CONTENT_URI, "conversations");
-
-        /**
-         * The {@code content://} style URL for this table, for obsolete threads.
-         */
-        public static final Uri OBSOLETE_THREADS_URI = Uri.withAppendedPath(
-                CONTENT_URI, "obsolete");
-
-        /** Thread type: common thread. */
-        public static final int COMMON_THREAD    = 0;
-
-        /** Thread type: broadcast thread. */
-        public static final int BROADCAST_THREAD = 1;
-
-        /**
-         * Not instantiable.
-         * @hide
-         */
-        private Threads() {
-        }
-
-        /**
-         * This is a single-recipient version of {@code getOrCreateThreadId}.
-         * It's convenient for use with SMS messages.
-         * @param context the context object to use.
-         * @param recipient the recipient to send to.
-         */
-        public static long getOrCreateThreadId(Context context, String recipient) {
-            Set<String> recipients = new HashSet<String>();
-
-            recipients.add(recipient);
-            return getOrCreateThreadId(context, recipients);
-        }
-
-        /**
-         * Given a set of recipients return its thread ID.
-         * <p>
-         * If a thread exists containing the provided participants, return its thread ID. Otherwise,
-         * this will create a new thread containing the provided participants and return its ID.
-         */
-        public static long getOrCreateThreadId(
-                Context context, Set<String> recipients) {
-            Uri.Builder uriBuilder = THREAD_ID_CONTENT_URI.buildUpon();
-
-            for (String recipient : recipients) {
-                if (Mms.isEmailAddress(recipient)) {
-                    recipient = Mms.extractAddrSpec(recipient);
-                }
-
-                uriBuilder.appendQueryParameter("recipient", recipient);
-            }
-
-            Uri uri = uriBuilder.build();
-            //if (DEBUG) Rlog.v(TAG, "getOrCreateThreadId uri: " + uri);
-
-            Cursor cursor = SqliteWrapper.query(context, context.getContentResolver(),
-                    uri, ID_PROJECTION, null, null, null);
-            if (cursor != null) {
-                try {
-                    if (cursor.moveToFirst()) {
-                        return cursor.getLong(0);
-                    } else {
-                        Rlog.e(TAG, "getOrCreateThreadId returned no rows!");
-                    }
-                } finally {
-                    cursor.close();
-                }
-            }
-
-            Rlog.e(TAG, "getOrCreateThreadId failed with " + recipients.size() + " recipients");
-            throw new IllegalArgumentException("Unable to find or allocate a thread ID.");
-        }
-    }
-
-    /**
-     * Columns for the "rcs_*" tables used by {@link android.telephony.ims.RcsMessageStore} classes.
-     *
-     * @hide - not meant for public use
-     */
-    public interface RcsColumns {
-        // TODO(sahinc): Turn this to true once the schema finalizes, so that people can update
-        //  their messaging databases. NOTE: move the switch/case update in MmsSmsDatabaseHelper to
-        //  the latest version of the database before turning this flag to true.
-        boolean IS_RCS_TABLE_SCHEMA_CODE_COMPLETE = false;
-
-        /**
-         * The authority for the content provider
-         */
-        String AUTHORITY = "rcs";
-
-        /**
-         * The URI to start building upon to use {@link com.android.providers.telephony.RcsProvider}
-         */
-        Uri CONTENT_AND_AUTHORITY = Uri.parse("content://" + AUTHORITY);
-
-        /**
-         * The value to be used whenever a transaction that expects an integer to be returned
-         * failed.
-         */
-        int TRANSACTION_FAILED = Integer.MIN_VALUE;
-
-        /**
-         * The value that denotes a timestamp was not set before (e.g. a message that is not
-         * delivered yet will not have a DELIVERED_TIMESTAMP)
-         */
-        long TIMESTAMP_NOT_SET = 0;
-
-        /**
-         * The table that {@link android.telephony.ims.RcsThread} gets persisted to
-         */
-        interface RcsThreadColumns {
-            /**
-             * The path that should be used for referring to
-             * {@link android.telephony.ims.RcsThread}s in
-             * {@link com.android.providers.telephony.RcsProvider} URIs.
-             */
-            String RCS_THREAD_URI_PART = "thread";
-
-            /**
-             * The URI to query or modify {@link android.telephony.ims.RcsThread} via the content
-             * provider.
-             */
-            Uri RCS_THREAD_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY, RCS_THREAD_URI_PART);
-
-            /**
-             * The unique identifier of an {@link android.telephony.ims.RcsThread}
-             */
-            String RCS_THREAD_ID_COLUMN = "rcs_thread_id";
-        }
-
-        /**
-         * The table that {@link android.telephony.ims.Rcs1To1Thread} gets persisted to
-         */
-        interface Rcs1To1ThreadColumns extends RcsThreadColumns {
-            /**
-             * The path that should be used for referring to
-             * {@link android.telephony.ims.Rcs1To1Thread}s in
-             * {@link com.android.providers.telephony.RcsProvider} URIs.
-             */
-            String RCS_1_TO_1_THREAD_URI_PART = "p2p_thread";
-
-            /**
-             * The URI to query or modify {@link android.telephony.ims.Rcs1To1Thread}s via the
-             * content provider. Can also insert to this URI to create a new 1-to-1 thread. When
-             * performing an insert, ensure that the provided content values contain the other
-             * participant's ID under the key
-             * {@link RcsParticipantColumns.RCS_PARTICIPANT_ID_COLUMN}
-             */
-            Uri RCS_1_TO_1_THREAD_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
-                    RCS_1_TO_1_THREAD_URI_PART);
-
-            /**
-             * The SMS/MMS thread to fallback to in case of an RCS outage
-             */
-            String FALLBACK_THREAD_ID_COLUMN = "rcs_fallback_thread_id";
-        }
-
-        /**
-         * The table that {@link android.telephony.ims.RcsGroupThread} gets persisted to
-         */
-        interface RcsGroupThreadColumns extends RcsThreadColumns {
-            /**
-             * The path that should be used for referring to
-             * {@link android.telephony.ims.RcsGroupThread}s in
-             * {@link com.android.providers.telephony.RcsProvider} URIs.
-             */
-            String RCS_GROUP_THREAD_URI_PART = "group_thread";
-
-            /**
-             * The URI to query or modify {@link android.telephony.ims.RcsGroupThread}s via the
-             * content provider
-             */
-            Uri RCS_GROUP_THREAD_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
-                    RCS_GROUP_THREAD_URI_PART);
-
-            /**
-             * The owner/admin of the {@link android.telephony.ims.RcsGroupThread}
-             */
-            String OWNER_PARTICIPANT_COLUMN = "owner_participant";
-
-            /**
-             * The user visible name of the group
-             */
-            String GROUP_NAME_COLUMN = "group_name";
-
-            /**
-             * The user visible icon of the group
-             */
-            String GROUP_ICON_COLUMN = "group_icon";
-
-            /**
-             * The RCS conference URI for this group
-             */
-            String CONFERENCE_URI_COLUMN = "conference_uri";
-        }
-
-        /**
-         * The view that enables polling from all types of RCS threads at once
-         */
-        interface RcsUnifiedThreadColumns extends RcsThreadColumns, Rcs1To1ThreadColumns,
-                RcsGroupThreadColumns {
-            /**
-             * The type of this {@link android.telephony.ims.RcsThread}
-             */
-            String THREAD_TYPE_COLUMN = "thread_type";
-
-            /**
-             * Integer returned as a result from a database query that denotes the thread is 1 to 1
-             */
-            int THREAD_TYPE_1_TO_1 = 0;
-
-            /**
-             * Integer returned as a result from a database query that denotes the thread is 1 to 1
-             */
-            int THREAD_TYPE_GROUP = 1;
-        }
-
-        /**
-         * The table that {@link android.telephony.ims.RcsParticipant} gets persisted to
-         */
-        interface RcsParticipantColumns {
-            /**
-             * The path that should be used for referring to
-             * {@link android.telephony.ims.RcsParticipant}s in
-             * {@link com.android.providers.telephony.RcsProvider} URIs.
-             */
-            String RCS_PARTICIPANT_URI_PART = "participant";
-
-            /**
-             * The URI to query or modify {@link android.telephony.ims.RcsParticipant}s via the
-             * content provider
-             */
-            Uri RCS_PARTICIPANT_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
-                    RCS_PARTICIPANT_URI_PART);
-
-            /**
-             * The unique identifier of the entry in the database
-             */
-            String RCS_PARTICIPANT_ID_COLUMN = "rcs_participant_id";
-
-            /**
-             * A foreign key on canonical_address table, also used by SMS/MMS
-             */
-            String CANONICAL_ADDRESS_ID_COLUMN = "canonical_address_id";
-
-            /**
-             * The user visible RCS alias for this participant.
-             */
-            String RCS_ALIAS_COLUMN = "rcs_alias";
-        }
-
-        /**
-         * Additional constants to enable access to {@link android.telephony.ims.RcsParticipant}
-         * related data
-         */
-        interface RcsParticipantHelpers extends RcsParticipantColumns {
-            /**
-             * The view that unifies "rcs_participant" and "canonical_addresses" tables for easy
-             * access to participant address.
-             */
-            String RCS_PARTICIPANT_WITH_ADDRESS_VIEW = "rcs_participant_with_address_view";
-
-            /**
-             * The view that unifies "rcs_participant", "canonical_addresses" and
-             * "rcs_thread_participant" junction table to get full information on participants that
-             * contribute to threads.
-             */
-            String RCS_PARTICIPANT_WITH_THREAD_VIEW = "rcs_participant_with_thread_view";
-        }
-
-        /**
-         * The table that {@link android.telephony.ims.RcsMessage} gets persisted to
-         */
-        interface RcsMessageColumns {
-            /**
-             * Denotes the type of this message (i.e.
-             * {@link android.telephony.ims.RcsIncomingMessage} or
-             * {@link android.telephony.ims.RcsOutgoingMessage}
-             */
-            String MESSAGE_TYPE_COLUMN = "rcs_message_type";
-
-            /**
-             * The unique identifier for the message in the database - i.e. the primary key.
-             */
-            String MESSAGE_ID_COLUMN = "rcs_message_row_id";
-
-            /**
-             * The globally unique RCS identifier for the message. Please see 4.4.5.2 - GSMA
-             * RCC.53 (RCS Device API 1.6 Specification)
-             */
-            String GLOBAL_ID_COLUMN = "rcs_message_global_id";
-
-            /**
-             * The subscription where this message was sent from/to.
-             */
-            String SUB_ID_COLUMN = "sub_id";
-
-            /**
-             * The sending status of the message.
-             * @see android.telephony.ims.RcsMessage.RcsMessageStatus
-             */
-            String STATUS_COLUMN = "status";
-
-            /**
-             * The creation timestamp of the message.
-             */
-            String ORIGINATION_TIMESTAMP_COLUMN = "origination_timestamp";
-
-            /**
-             * The text content of the message.
-             */
-            String MESSAGE_TEXT_COLUMN = "rcs_text";
-
-            /**
-             * The latitude content of the message, if it contains a location.
-             */
-            String LATITUDE_COLUMN = "latitude";
-
-            /**
-             * The longitude content of the message, if it contains a location.
-             */
-            String LONGITUDE_COLUMN = "longitude";
-        }
-
-        /**
-         * The table that additional information of {@link android.telephony.ims.RcsIncomingMessage}
-         * gets persisted to.
-         */
-        interface RcsIncomingMessageColumns extends RcsMessageColumns {
-            /**
-             The path that should be used for referring to
-             * {@link android.telephony.ims.RcsIncomingMessage}s in
-             * {@link com.android.providers.telephony.RcsProvider} URIs.
-             */
-            String INCOMING_MESSAGE_URI_PART = "incoming_message";
-
-            /**
-             * The URI to query incoming messages through
-             * {@link com.android.providers.telephony.RcsProvider}
-             */
-            Uri INCOMING_MESSAGE_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
-                    INCOMING_MESSAGE_URI_PART);
-
-            /**
-             * The ID of the {@link android.telephony.ims.RcsParticipant} that sent this message
-             */
-            String SENDER_PARTICIPANT_ID_COLUMN = "sender_participant";
-
-            /**
-             * The timestamp of arrival for this message.
-             */
-            String ARRIVAL_TIMESTAMP_COLUMN = "arrival_timestamp";
-
-            /**
-             * The time when the recipient has read this message.
-             */
-            String SEEN_TIMESTAMP_COLUMN = "seen_timestamp";
-        }
-
-        /**
-         * The table that additional information of {@link android.telephony.ims.RcsOutgoingMessage}
-         * gets persisted to.
-         */
-        interface RcsOutgoingMessageColumns extends RcsMessageColumns {
-            /**
-             * The path that should be used for referring to
-             * {@link android.telephony.ims.RcsOutgoingMessage}s in
-             * {@link com.android.providers.telephony.RcsProvider} URIs.
-             */
-            String OUTGOING_MESSAGE_URI_PART = "outgoing_message";
-
-            /**
-             * The URI to query or modify {@link android.telephony.ims.RcsOutgoingMessage}s via the
-             * content provider
-             */
-            Uri OUTGOING_MESSAGE_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
-                    OUTGOING_MESSAGE_URI_PART);
-        }
-
-        /**
-         * The delivery information of an {@link android.telephony.ims.RcsOutgoingMessage}
-         */
-        interface RcsMessageDeliveryColumns extends RcsOutgoingMessageColumns {
-            /**
-             * The path that should be used for referring to
-             * {@link android.telephony.ims.RcsOutgoingMessageDelivery}s in
-             * {@link com.android.providers.telephony.RcsProvider} URIs.
-             */
-            String DELIVERY_URI_PART = "delivery";
-
-            /**
-             * The timestamp of delivery of this message.
-             */
-            String DELIVERED_TIMESTAMP_COLUMN = "delivered_timestamp";
-
-            /**
-             * The time when the recipient has read this message.
-             */
-            String SEEN_TIMESTAMP_COLUMN = "seen_timestamp";
-        }
-
-        /**
-         * The views that allow querying {@link android.telephony.ims.RcsIncomingMessage} and
-         * {@link android.telephony.ims.RcsOutgoingMessage} at the same time.
-         */
-        interface RcsUnifiedMessageColumns extends RcsIncomingMessageColumns,
-                RcsOutgoingMessageColumns {
-            /**
-             * The path that is used to query all {@link android.telephony.ims.RcsMessage} in
-             * {@link com.android.providers.telephony.RcsProvider} URIs.
-             */
-            String UNIFIED_MESSAGE_URI_PART = "message";
-
-            /**
-             * The URI to query all types of {@link android.telephony.ims.RcsMessage}s
-             */
-            Uri UNIFIED_MESSAGE_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
-                    UNIFIED_MESSAGE_URI_PART);
-
-            /**
-             * The name of the view that unites rcs_message and rcs_incoming_message tables.
-             */
-            String UNIFIED_INCOMING_MESSAGE_VIEW = "unified_incoming_message_view";
-
-            /**
-             * The name of the view that unites rcs_message and rcs_outgoing_message tables.
-             */
-            String UNIFIED_OUTGOING_MESSAGE_VIEW = "unified_outgoing_message_view";
-
-            /**
-             * The column that shows from which table the message entry came from.
-             */
-            String MESSAGE_TYPE_COLUMN = "message_type";
-
-            /**
-             * Integer returned as a result from a database query that denotes that the message is
-             * an incoming message
-             */
-            int MESSAGE_TYPE_INCOMING = 1;
-
-            /**
-             * Integer returned as a result from a database query that denotes that the message is
-             * an outgoing message
-             */
-            int MESSAGE_TYPE_OUTGOING = 0;
-        }
-
-        /**
-         * The table that {@link android.telephony.ims.RcsFileTransferPart} gets persisted to.
-         */
-        interface RcsFileTransferColumns {
-            /**
-             * The path that should be used for referring to
-             * {@link android.telephony.ims.RcsFileTransferPart}s in
-             * {@link com.android.providers.telephony.RcsProvider} URIs.
-             */
-            String FILE_TRANSFER_URI_PART = "file_transfer";
-
-            /**
-             * The URI to query or modify {@link android.telephony.ims.RcsFileTransferPart}s via the
-             * content provider
-             */
-            Uri FILE_TRANSFER_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
-                    FILE_TRANSFER_URI_PART);
-
-            /**
-             * The globally unique file transfer ID for this RCS file transfer.
-             */
-            String FILE_TRANSFER_ID_COLUMN = "rcs_file_transfer_id";
-
-            /**
-             * The RCS session ID for this file transfer. The ID is implementation dependent but
-             * should be unique.
-             */
-            String SESSION_ID_COLUMN = "session_id";
-
-            /**
-             * The URI that points to the content of this file transfer
-             */
-            String CONTENT_URI_COLUMN = "content_uri";
-
-            /**
-             * The file type of this file transfer in bytes. The validity of types is not enforced
-             * in {@link android.telephony.ims.RcsMessageStore} APIs.
-             */
-            String CONTENT_TYPE_COLUMN = "content_type";
-
-            /**
-             * The size of the file transfer in bytes.
-             */
-            String FILE_SIZE_COLUMN = "file_size";
-
-            /**
-             * Number of bytes that was successfully transmitted for this file transfer
-             */
-            String SUCCESSFULLY_TRANSFERRED_BYTES = "transfer_offset";
-
-            /**
-             * The status of this file transfer
-             * @see android.telephony.ims.RcsFileTransferPart.RcsFileTransferStatus
-             */
-            String TRANSFER_STATUS_COLUMN = "transfer_status";
-
-            /**
-             * The on-screen width of the file transfer, if it contains multi-media
-             */
-            String WIDTH_COLUMN = "width";
-
-            /**
-             * The on-screen height of the file transfer, if it contains multi-media
-             */
-            String HEIGHT_COLUMN = "height";
-
-            /**
-             * The duration of the content in milliseconds if this file transfer contains
-             * multi-media
-             */
-            String DURATION_MILLIS_COLUMN = "duration";
-
-            /**
-             * The URI to the preview of the content of this file transfer
-             */
-            String PREVIEW_URI_COLUMN = "preview_uri";
-
-            /**
-             * The type of the preview of the content of this file transfer. The validity of types
-             * is not enforced in {@link android.telephony.ims.RcsMessageStore} APIs.
-             */
-            String PREVIEW_TYPE_COLUMN = "preview_type";
-        }
-
-        /**
-         * The table that holds the information for
-         * {@link android.telephony.ims.RcsGroupThreadEvent} and its subclasses.
-         */
-        interface RcsThreadEventColumns {
-            /**
-             * The string used in the {@link com.android.providers.telephony.RcsProvider} URI to
-             * refer to participant joined events (example URI:
-             * {@code content://rcs/group_thread/3/participant_joined_event})
-             */
-            String PARTICIPANT_JOINED_URI_PART = "participant_joined_event";
-
-            /**
-             * The string used in the {@link com.android.providers.telephony.RcsProvider} URI to
-             * refer to participant left events. (example URI:
-             * {@code content://rcs/group_thread/3/participant_left_event/4})
-             */
-            String PARTICIPANT_LEFT_URI_PART = "participant_left_event";
-
-            /**
-             * The string used in the {@link com.android.providers.telephony.RcsProvider} URI to
-             * refer to name changed events. (example URI:
-             * {@code content://rcs/group_thread/3/name_changed_event})
-             */
-            String NAME_CHANGED_URI_PART = "name_changed_event";
-
-            /**
-             * The string used in the {@link com.android.providers.telephony.RcsProvider} URI to
-             * refer to icon changed events. (example URI:
-             * {@code content://rcs/group_thread/3/icon_changed_event})
-             */
-            String ICON_CHANGED_URI_PART = "icon_changed_event";
-
-            /**
-             * The unique ID of this event in the database, i.e. the primary key
-             */
-            String EVENT_ID_COLUMN = "event_id";
-
-            /**
-             * The type of this event
-             *
-             * @see RcsEventTypes
-             */
-            String EVENT_TYPE_COLUMN = "event_type";
-
-            /**
-             * The timestamp in milliseconds of when this event happened
-             */
-            String TIMESTAMP_COLUMN = "origination_timestamp";
-
-            /**
-             * The participant that generated this event
-             */
-            String SOURCE_PARTICIPANT_ID_COLUMN = "source_participant";
-
-            /**
-             * The receiving participant of this event if this was an
-             * {@link android.telephony.ims.RcsGroupThreadParticipantJoinedEvent} or
-             * {@link android.telephony.ims.RcsGroupThreadParticipantLeftEvent}
-             */
-            String DESTINATION_PARTICIPANT_ID_COLUMN = "destination_participant";
-
-            /**
-             * The URI for the new icon of the group thread if this was an
-             * {@link android.telephony.ims.RcsGroupThreadIconChangedEvent}
-             */
-            String NEW_ICON_URI_COLUMN = "new_icon_uri";
-
-            /**
-             * The URI for the new name of the group thread if this was an
-             * {@link android.telephony.ims.RcsGroupThreadNameChangedEvent}
-             */
-            String NEW_NAME_COLUMN = "new_name";
-        }
-
-        /**
-         * The table that {@link android.telephony.ims.RcsParticipantAliasChangedEvent} gets
-         * persisted to
-         */
-        interface RcsParticipantEventColumns {
-            /**
-             * The path that should be used for referring to
-             * {@link android.telephony.ims.RcsParticipantAliasChangedEvent}s in
-             * {@link com.android.providers.telephony.RcsProvider} URIs.
-             */
-            String ALIAS_CHANGE_EVENT_URI_PART = "alias_change_event";
-
-            /**
-             * The new alias of the participant
-             */
-            String NEW_ALIAS_COLUMN = "new_alias";
-        }
-
-        /**
-         * These values are used in {@link com.android.providers.telephony.RcsProvider} to determine
-         * what kind of event is present in the storage.
-         */
-        interface RcsEventTypes {
-            /**
-             * Integer constant that is stored in the
-             * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
-             * is of type {@link android.telephony.ims.RcsParticipantAliasChangedEvent}
-             */
-            int PARTICIPANT_ALIAS_CHANGED_EVENT_TYPE = 1;
-
-            /**
-             * Integer constant that is stored in the
-             * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
-             * is of type {@link android.telephony.ims.RcsGroupThreadParticipantJoinedEvent}
-             */
-            int PARTICIPANT_JOINED_EVENT_TYPE = 2;
-
-            /**
-             * Integer constant that is stored in the
-             * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
-             * is of type {@link android.telephony.ims.RcsGroupThreadParticipantLeftEvent}
-             */
-            int PARTICIPANT_LEFT_EVENT_TYPE = 4;
-
-            /**
-             * Integer constant that is stored in the
-             * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
-             * is of type {@link android.telephony.ims.RcsGroupThreadIconChangedEvent}
-             */
-            int ICON_CHANGED_EVENT_TYPE = 8;
-
-            /**
-             * Integer constant that is stored in the
-             * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
-             * is of type {@link android.telephony.ims.RcsGroupThreadNameChangedEvent}
-             */
-            int NAME_CHANGED_EVENT_TYPE = 16;
-        }
-
-        /**
-         * The view that allows unified querying across all events
-         */
-        interface RcsUnifiedEventHelper extends RcsParticipantEventColumns, RcsThreadEventColumns {
-            /**
-             * The path that should be used for referring to
-             * {@link android.telephony.ims.RcsEvent}s in
-             * {@link com.android.providers.telephony.RcsProvider} URIs.
-             */
-            String RCS_EVENT_QUERY_URI_PATH = "event";
-
-            /**
-             * The URI to query {@link android.telephony.ims.RcsEvent}s via the content provider.
-             */
-            Uri RCS_EVENT_QUERY_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
-                    RCS_EVENT_QUERY_URI_PATH);
-        }
-
-        /**
-         * Allows RCS specific canonical address handling.
-         */
-        interface RcsCanonicalAddressHelper {
-            /**
-             * Returns the canonical address ID for a canonical address, if now row exists, this
-             * will add a row and return its ID. This helper works against the same table used by
-             * the SMS and MMS threads, but is accessible only by the phone process for use by RCS
-             * message storage.
-             *
-             * @throws IllegalArgumentException if unable to retrieve or create the canonical
-             *                                  address entry.
-             */
-            static long getOrCreateCanonicalAddressId(
-                    ContentResolver contentResolver, String canonicalAddress) {
-
-                Uri.Builder uriBuilder = CONTENT_AND_AUTHORITY.buildUpon();
-                uriBuilder.appendPath("canonical-address");
-                uriBuilder.appendQueryParameter("address", canonicalAddress);
-                Uri uri = uriBuilder.build();
-
-                try (Cursor cursor = contentResolver.query(uri, null, null, null)) {
-                    if (cursor != null && cursor.moveToFirst()) {
-                        return cursor.getLong(cursor.getColumnIndex(CanonicalAddressesColumns._ID));
-                    } else {
-                        Rlog.e(TAG, "getOrCreateCanonicalAddressId returned no rows");
-                    }
-                }
-
-                Rlog.e(TAG, "getOrCreateCanonicalAddressId failed");
-                throw new IllegalArgumentException(
-                        "Unable to find or allocate a canonical address ID");
-            }
-        }
-    }
-
-    /**
-     * Contains all MMS messages.
-     */
-    public static final class Mms implements BaseMmsColumns {
-
-        /**
-         * Not instantiable.
-         * @hide
-         */
-        private Mms() {
-        }
-
-        /**
-         * The {@code content://} URI for this table.
-         */
-        public static final Uri CONTENT_URI = Uri.parse("content://mms");
-
-        /**
-         * Content URI for getting MMS report requests.
-         */
-        public static final Uri REPORT_REQUEST_URI = Uri.withAppendedPath(
-                                            CONTENT_URI, "report-request");
-
-        /**
-         * Content URI for getting MMS report status.
-         */
-        public static final Uri REPORT_STATUS_URI = Uri.withAppendedPath(
-                                            CONTENT_URI, "report-status");
-
-        /**
-         * The default sort order for this table.
-         */
-        public static final String DEFAULT_SORT_ORDER = "date DESC";
-
-        /**
-         * Regex pattern for names and email addresses.
-         * <ul>
-         *     <li><em>mailbox</em> = {@code name-addr}</li>
-         *     <li><em>name-addr</em> = {@code [display-name] angle-addr}</li>
-         *     <li><em>angle-addr</em> = {@code [CFWS] "<" addr-spec ">" [CFWS]}</li>
-         * </ul>
-         * @hide
-         */
-        @UnsupportedAppUsage
-        public static final Pattern NAME_ADDR_EMAIL_PATTERN =
-                Pattern.compile("\\s*(\"[^\"]*\"|[^<>\"]+)\\s*<([^<>]+)>\\s*");
-
-        /**
-         * Helper method to query this table.
-         * @hide
-         */
-        public static Cursor query(
-                ContentResolver cr, String[] projection) {
-            return cr.query(CONTENT_URI, projection, null, null, DEFAULT_SORT_ORDER);
-        }
-
-        /**
-         * Helper method to query this table.
-         * @hide
-         */
-        public static Cursor query(
-                ContentResolver cr, String[] projection,
-                String where, String orderBy) {
-            return cr.query(CONTENT_URI, projection,
-                    where, null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
-        }
-
-        /**
-         * Helper method to extract email address from address string.
-         * @hide
-         */
-        @UnsupportedAppUsage
-        public static String extractAddrSpec(String address) {
-            Matcher match = NAME_ADDR_EMAIL_PATTERN.matcher(address);
-
-            if (match.matches()) {
-                return match.group(2);
-            }
-            return address;
-        }
-
-        /**
-         * Is the specified address an email address?
-         *
-         * @param address the input address to test
-         * @return true if address is an email address; false otherwise.
-         * @hide
-         */
-        @UnsupportedAppUsage
-        public static boolean isEmailAddress(String address) {
-            if (TextUtils.isEmpty(address)) {
-                return false;
-            }
-
-            String s = extractAddrSpec(address);
-            Matcher match = Patterns.EMAIL_ADDRESS.matcher(s);
-            return match.matches();
-        }
-
-        /**
-         * Is the specified number a phone number?
-         *
-         * @param number the input number to test
-         * @return true if number is a phone number; false otherwise.
-         * @hide
-         */
-        @UnsupportedAppUsage
-        public static boolean isPhoneNumber(String number) {
-            if (TextUtils.isEmpty(number)) {
-                return false;
-            }
-
-            Matcher match = Patterns.PHONE.matcher(number);
-            return match.matches();
-        }
-
-        /**
-         * Contains all MMS messages in the MMS app inbox.
-         */
-        public static final class Inbox implements BaseMmsColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Inbox() {
-            }
-
-            /**
-             * The {@code content://} style URL for this table.
-             */
-            public static final Uri
-                    CONTENT_URI = Uri.parse("content://mms/inbox");
-
-            /**
-             * The default sort order for this table.
-             */
-            public static final String DEFAULT_SORT_ORDER = "date DESC";
-        }
-
-        /**
-         * Contains all MMS messages in the MMS app sent folder.
-         */
-        public static final class Sent implements BaseMmsColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Sent() {
-            }
-
-            /**
-             * The {@code content://} style URL for this table.
-             */
-            public static final Uri
-                    CONTENT_URI = Uri.parse("content://mms/sent");
-
-            /**
-             * The default sort order for this table.
-             */
-            public static final String DEFAULT_SORT_ORDER = "date DESC";
-        }
-
-        /**
-         * Contains all MMS messages in the MMS app drafts folder.
-         */
-        public static final class Draft implements BaseMmsColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Draft() {
-            }
-
-            /**
-             * The {@code content://} style URL for this table.
-             */
-            public static final Uri
-                    CONTENT_URI = Uri.parse("content://mms/drafts");
-
-            /**
-             * The default sort order for this table.
-             */
-            public static final String DEFAULT_SORT_ORDER = "date DESC";
-        }
-
-        /**
-         * Contains all MMS messages in the MMS app outbox.
-         */
-        public static final class Outbox implements BaseMmsColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Outbox() {
-            }
-
-            /**
-             * The {@code content://} style URL for this table.
-             */
-            public static final Uri
-                    CONTENT_URI = Uri.parse("content://mms/outbox");
-
-            /**
-             * The default sort order for this table.
-             */
-            public static final String DEFAULT_SORT_ORDER = "date DESC";
-        }
-
-        /**
-         * Contains address information for an MMS message.
-         */
-        public static final class Addr implements BaseColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Addr() {
-            }
-
-            /**
-             * The ID of MM which this address entry belongs to.
-             * <P>Type: INTEGER (long)</P>
-             */
-            public static final String MSG_ID = "msg_id";
-
-            /**
-             * The ID of contact entry in Phone Book.
-             * <P>Type: INTEGER (long)</P>
-             */
-            public static final String CONTACT_ID = "contact_id";
-
-            /**
-             * The address text.
-             * <P>Type: TEXT</P>
-             */
-            public static final String ADDRESS = "address";
-
-            /**
-             * Type of address: must be one of {@code PduHeaders.BCC},
-             * {@code PduHeaders.CC}, {@code PduHeaders.FROM}, {@code PduHeaders.TO}.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String TYPE = "type";
-
-            /**
-             * Character set of this entry (MMS charset value).
-             * <P>Type: INTEGER</P>
-             */
-            public static final String CHARSET = "charset";
-
-            /**
-             * Generates a Addr {@link Uri} for message, used to perform Addr table operation
-             * for mms.
-             *
-             * @param messageId the messageId used to generate Addr {@link Uri} dynamically
-             * @return the addrUri used to perform Addr table operation for mms
-             */
-            @NonNull
-            public static Uri getAddrUriForMessage(@NonNull String messageId) {
-                Uri addrUri = Mms.CONTENT_URI.buildUpon()
-                        .appendPath(String.valueOf(messageId)).appendPath("addr").build();
-                return addrUri;
-            }
-        }
-
-        /**
-         * Contains message parts.
-         *
-         * To avoid issues where applications might cache a part ID, the ID of a deleted part must
-         * not be reused to point at a new part.
-         */
-        public static final class Part implements BaseColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Part() {
-            }
-
-            /**
-             * The name of part table.
-             */
-            private static final String TABLE_PART = "part";
-
-            /**
-             * The {@code content://} style URL for this table. Can be appended with a part ID to
-             * address individual parts.
-             */
-            @NonNull
-            public static final Uri CONTENT_URI = Uri.withAppendedPath(Mms.CONTENT_URI, TABLE_PART);
-
-            /**
-             * The identifier of the message which this part belongs to.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String MSG_ID = "mid";
-
-            /**
-             * The order of the part.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String SEQ = "seq";
-
-            /**
-             * The content type of the part.
-             * <P>Type: TEXT</P>
-             */
-            public static final String CONTENT_TYPE = "ct";
-
-            /**
-             * The name of the part.
-             * <P>Type: TEXT</P>
-             */
-            public static final String NAME = "name";
-
-            /**
-             * The charset of the part.
-             * <P>Type: TEXT</P>
-             */
-            public static final String CHARSET = "chset";
-
-            /**
-             * The file name of the part.
-             * <P>Type: TEXT</P>
-             */
-            public static final String FILENAME = "fn";
-
-            /**
-             * The content disposition of the part.
-             * <P>Type: TEXT</P>
-             */
-            public static final String CONTENT_DISPOSITION = "cd";
-
-            /**
-             * The content ID of the part.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String CONTENT_ID = "cid";
-
-            /**
-             * The content location of the part.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String CONTENT_LOCATION = "cl";
-
-            /**
-             * The start of content-type of the message.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String CT_START = "ctt_s";
-
-            /**
-             * The type of content-type of the message.
-             * <P>Type: TEXT</P>
-             */
-            public static final String CT_TYPE = "ctt_t";
-
-            /**
-             * The location (on filesystem) of the binary data of the part.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String _DATA = "_data";
-
-            /**
-             * The message text.
-             * <P>Type: TEXT</P>
-             */
-            public static final String TEXT = "text";
-
-            /**
-             * Generates a Part {@link Uri} for message, used to perform Part table operation
-             * for mms.
-             *
-             * @param messageId the messageId used to generate Part {@link Uri} dynamically
-             * @return the partUri used to perform Part table operation for mms
-             */
-            @NonNull
-            public static Uri getPartUriForMessage(@NonNull String messageId) {
-                Uri partUri = Mms.CONTENT_URI.buildUpon()
-                        .appendPath(String.valueOf(messageId)).appendPath(
-                                TABLE_PART).build();
-                return partUri;
-            }
-        }
-
-        /**
-         * Message send rate table.
-         */
-        public static final class Rate {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Rate() {
-            }
-
-            /**
-             * The {@code content://} style URL for this table.
-             */
-            public static final Uri CONTENT_URI = Uri.withAppendedPath(
-                    Mms.CONTENT_URI, "rate");
-
-            /**
-             * When a message was successfully sent.
-             * <P>Type: INTEGER (long)</P>
-             */
-            public static final String SENT_TIME = "sent_time";
-        }
-
-        /**
-         * Intents class.
-         */
-        public static final class Intents {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Intents() {
-            }
-
-            /**
-             * Indicates that the contents of specified URIs were changed.
-             * The application which is showing or caching these contents
-             * should be updated.
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String CONTENT_CHANGED_ACTION
-                    = "android.intent.action.CONTENT_CHANGED";
-
-            /**
-             * An extra field which stores the URI of deleted contents.
-             */
-            public static final String DELETED_CONTENTS = "deleted_contents";
-        }
-    }
-
-    /**
-     * Contains all MMS and SMS messages.
-     */
-    public static final class MmsSms implements BaseColumns {
-
-        /**
-         * Not instantiable.
-         * @hide
-         */
-        private MmsSms() {
-        }
-
-        /**
-         * The column to distinguish SMS and MMS messages in query results.
-         */
-        public static final String TYPE_DISCRIMINATOR_COLUMN =
-                "transport_type";
-
-        /**
-         * The {@code content://} style URL for this table.
-         */
-        public static final Uri CONTENT_URI = Uri.parse("content://mms-sms/");
-
-        /**
-         * The {@code content://} style URL for this table, by conversation.
-         */
-        public static final Uri CONTENT_CONVERSATIONS_URI = Uri.parse(
-                "content://mms-sms/conversations");
-
-        /**
-         * The {@code content://} style URL for this table, by phone number.
-         */
-        public static final Uri CONTENT_FILTER_BYPHONE_URI = Uri.parse(
-                "content://mms-sms/messages/byphone");
-
-        /**
-         * The {@code content://} style URL for undelivered messages in this table.
-         */
-        public static final Uri CONTENT_UNDELIVERED_URI = Uri.parse(
-                "content://mms-sms/undelivered");
-
-        /**
-         * The {@code content://} style URL for draft messages in this table.
-         */
-        public static final Uri CONTENT_DRAFT_URI = Uri.parse(
-                "content://mms-sms/draft");
-
-        /**
-         * The {@code content://} style URL for locked messages in this table.
-         * <P>This {@link Uri} is used to check at most one locked message found in the union of MMS
-         * and SMS messages. Also this will return only _id column in response.</P>
-         */
-        public static final Uri CONTENT_LOCKED_URI = Uri.parse(
-                "content://mms-sms/locked");
-
-        /**
-         * Pass in a query parameter called "pattern" which is the text to search for.
-         * The sort order is fixed to be: {@code thread_id ASC, date DESC}.
-         */
-        public static final Uri SEARCH_URI = Uri.parse(
-                "content://mms-sms/search");
-
-        // Constants for message protocol types.
-
-        /** SMS protocol type. */
-        public static final int SMS_PROTO = 0;
-
-        /** MMS protocol type. */
-        public static final int MMS_PROTO = 1;
-
-        // Constants for error types of pending messages.
-
-        /** Error type: no error. */
-        public static final int NO_ERROR                      = 0;
-
-        /** Error type: generic transient error. */
-        public static final int ERR_TYPE_GENERIC              = 1;
-
-        /** Error type: SMS protocol transient error. */
-        public static final int ERR_TYPE_SMS_PROTO_TRANSIENT  = 2;
-
-        /** Error type: MMS protocol transient error. */
-        public static final int ERR_TYPE_MMS_PROTO_TRANSIENT  = 3;
-
-        /** Error type: transport failure. */
-        public static final int ERR_TYPE_TRANSPORT_FAILURE    = 4;
-
-        /** Error type: permanent error (along with all higher error values). */
-        public static final int ERR_TYPE_GENERIC_PERMANENT    = 10;
-
-        /** Error type: SMS protocol permanent error. */
-        public static final int ERR_TYPE_SMS_PROTO_PERMANENT  = 11;
-
-        /** Error type: MMS protocol permanent error. */
-        public static final int ERR_TYPE_MMS_PROTO_PERMANENT  = 12;
-
-        /**
-         * Contains pending messages info.
-         */
-        public static final class PendingMessages implements BaseColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private PendingMessages() {
-            }
-
-            public static final Uri CONTENT_URI = Uri.withAppendedPath(
-                    MmsSms.CONTENT_URI, "pending");
-
-            /**
-             * The type of transport protocol (MMS or SMS).
-             * <P>Type: INTEGER</P>
-             */
-            public static final String PROTO_TYPE = "proto_type";
-
-            /**
-             * The ID of the message to be sent or downloaded.
-             * <P>Type: INTEGER (long)</P>
-             */
-            public static final String MSG_ID = "msg_id";
-
-            /**
-             * The type of the message to be sent or downloaded.
-             * This field is only valid for MM. For SM, its value is always set to 0.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String MSG_TYPE = "msg_type";
-
-            /**
-             * The type of the error code.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String ERROR_TYPE = "err_type";
-
-            /**
-             * The error code of sending/retrieving process.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String ERROR_CODE = "err_code";
-
-            /**
-             * How many times we tried to send or download the message.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String RETRY_INDEX = "retry_index";
-
-            /**
-             * The time to do next retry.
-             * <P>Type: INTEGER (long)</P>
-             */
-            public static final String DUE_TIME = "due_time";
-
-            /**
-             * The time we last tried to send or download the message.
-             * <P>Type: INTEGER (long)</P>
-             */
-            public static final String LAST_TRY = "last_try";
-
-            /**
-             * The subscription to which the message belongs to. Its value will be
-             * < 0 if the sub id cannot be determined.
-             * <p>Type: INTEGER (long) </p>
-             */
-            public static final String SUBSCRIPTION_ID = "pending_sub_id";
-        }
-
-        /**
-         * Words table used by provider for full-text searches.
-         * @hide
-         */
-        public static final class WordsTable {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private WordsTable() {}
-
-            /**
-             * Primary key.
-             * <P>Type: INTEGER (long)</P>
-             */
-            public static final String ID = "_id";
-
-            /**
-             * Source row ID.
-             * <P>Type: INTEGER (long)</P>
-             */
-            public static final String SOURCE_ROW_ID = "source_id";
-
-            /**
-             * Table ID (either 1 or 2).
-             * <P>Type: INTEGER</P>
-             */
-            public static final String TABLE_ID = "table_to_use";
-
-            /**
-             * The words to index.
-             * <P>Type: TEXT</P>
-             */
-            public static final String INDEXED_TEXT = "index_text";
-        }
-    }
-
-    /**
-     * Carriers class contains information about APNs, including MMSC information.
-     */
-    public static final class Carriers implements BaseColumns {
-
-        /**
-         * Not instantiable.
-         * @hide
-         */
-        private Carriers() {}
-
-        /**
-         * The {@code content://} style URL for this table.
-         * For MSIM, this will return APNs for the default subscription
-         * {@link SubscriptionManager#getDefaultSubscriptionId()}. To specify subId for MSIM,
-         * use {@link Uri#withAppendedPath(Uri, String)} to append with subscription id.
-         */
-        @NonNull
-        public static final Uri CONTENT_URI = Uri.parse("content://telephony/carriers");
-
-        /**
-         * The {@code content://} style URL for this table. Used for APN query based on current
-         * subscription. Instead of specifying carrier matching information in the selection,
-         * this API will return all matching APNs from current subscription carrier and queries
-         * will be applied on top of that. If there is no match for MVNO (Mobile Virtual Network
-         * Operator) APNs, return APNs from its MNO (based on mccmnc) instead. For MSIM, this will
-         * return APNs for the default subscription
-         * {@link SubscriptionManager#getDefaultSubscriptionId()}. To specify subId for MSIM,
-         * use {@link Uri#withAppendedPath(Uri, String)} to append with subscription id.
-         */
-        @NonNull
-        public static final Uri SIM_APN_URI = Uri.parse(
-                "content://telephony/carriers/sim_apn_list");
-
-        /**
-         * The {@code content://} style URL to be called from DevicePolicyManagerService,
-         * can manage DPC-owned APNs.
-         * @hide
-         */
-        public static final Uri DPC_URI = Uri.parse("content://telephony/carriers/dpc");
-
-        /**
-         * The {@code content://} style URL to be called from Telephony to query APNs.
-         * When DPC-owned APNs are enforced, only DPC-owned APNs are returned, otherwise only
-         * non-DPC-owned APNs are returned. For MSIM, this will return APNs for the default
-         * subscription {@link SubscriptionManager#getDefaultSubscriptionId()}. To specify subId
-         * for MSIM, use {@link Uri#withAppendedPath(Uri, String)} to append with subscription id.
-         * @hide
-         */
-        public static final Uri FILTERED_URI = Uri.parse("content://telephony/carriers/filtered");
-
-        /**
-         * The {@code content://} style URL to be called from DevicePolicyManagerService
-         * or Telephony to manage whether DPC-owned APNs are enforced.
-         * @hide
-         */
-        public static final Uri ENFORCE_MANAGED_URI = Uri.parse(
-                "content://telephony/carriers/enforce_managed");
-
-        /**
-         * The column name for ENFORCE_MANAGED_URI, indicates whether DPC-owned APNs are enforced.
-         * @hide
-         */
-        public static final String ENFORCE_KEY = "enforced";
-
-        /**
-         * The default sort order for this table.
-         */
-        public static final String DEFAULT_SORT_ORDER = "name ASC";
-
-        /**
-         * Entry name.
-         * <P>Type: TEXT</P>
-         */
-        public static final String NAME = "name";
-
-        /**
-         * APN name.
-         * <P>Type: TEXT</P>
-         */
-        public static final String APN = "apn";
-
-        /**
-         * Proxy address.
-         * <P>Type: TEXT</P>
-         */
-        public static final String PROXY = "proxy";
-
-        /**
-         * Proxy port.
-         * <P>Type: TEXT</P>
-         */
-        public static final String PORT = "port";
-
-        /**
-         * MMS proxy address.
-         * <P>Type: TEXT</P>
-         */
-        public static final String MMSPROXY = "mmsproxy";
-
-        /**
-         * MMS proxy port.
-         * <P>Type: TEXT</P>
-         */
-        public static final String MMSPORT = "mmsport";
-
-        /**
-         * Server address.
-         * <P>Type: TEXT</P>
-         */
-        public static final String SERVER = "server";
-
-        /**
-         * APN username.
-         * <P>Type: TEXT</P>
-         */
-        public static final String USER = "user";
-
-        /**
-         * APN password.
-         * <P>Type: TEXT</P>
-         */
-        public static final String PASSWORD = "password";
-
-        /**
-         * MMSC URL.
-         * <P>Type: TEXT</P>
-         */
-        public static final String MMSC = "mmsc";
-
-        /**
-         * Mobile Country Code (MCC).
-         * <P>Type: TEXT</P>
-         * @deprecated Use {@link #SIM_APN_URI} to query APN instead, this API will return
-         * matching APNs based on current subscription carrier, thus no need to specify MCC and
-         * other carrier matching information. In the future, Android will not support MCC for
-         * APN query.
-         */
-        public static final String MCC = "mcc";
-
-        /**
-         * Mobile Network Code (MNC).
-         * <P>Type: TEXT</P>
-         * @deprecated Use {@link #SIM_APN_URI} to query APN instead, this API will return
-         * matching APNs based on current subscription carrier, thus no need to specify MNC and
-         * other carrier matching information. In the future, Android will not support MNC for
-         * APN query.
-         */
-        public static final String MNC = "mnc";
-
-        /**
-         * Numeric operator ID (as String). Usually {@code MCC + MNC}.
-         * <P>Type: TEXT</P>
-         * @deprecated Use {@link #SIM_APN_URI} to query APN instead, this API will return
-         * matching APNs based on current subscription carrier, thus no need to specify Numeric
-         * and other carrier matching information. In the future, Android will not support Numeric
-         * for APN query.
-         */
-        public static final String NUMERIC = "numeric";
-
-        /**
-         * Authentication type.
-         * <P>Type:  INTEGER</P>
-         */
-        public static final String AUTH_TYPE = "authtype";
-
-        /**
-         * Comma-delimited list of APN types.
-         * <P>Type: TEXT</P>
-         */
-        public static final String TYPE = "type";
-
-        /**
-         * The protocol to use to connect to this APN.
-         *
-         * One of the {@code PDP_type} values in TS 27.007 section 10.1.1.
-         * For example: {@code IP}, {@code IPV6}, {@code IPV4V6}, or {@code PPP}.
-         * <P>Type: TEXT</P>
-         */
-        public static final String PROTOCOL = "protocol";
-
-        /**
-         * The protocol to use to connect to this APN when roaming.
-         * The syntax is the same as protocol.
-         * <P>Type: TEXT</P>
-         */
-        public static final String ROAMING_PROTOCOL = "roaming_protocol";
-
-        /**
-         * Is this the current APN?
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String CURRENT = "current";
-
-        /**
-         * Is this APN enabled?
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String CARRIER_ENABLED = "carrier_enabled";
-
-        /**
-         * Radio Access Technology info.
-         * To check what values are allowed, refer to {@link android.telephony.ServiceState}.
-         * This should be spread to other technologies,
-         * but is currently only used for LTE (14) and eHRPD (13).
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported, use {@link #NETWORK_TYPE_BITMASK} instead
-         */
-        @Deprecated
-        public static final String BEARER = "bearer";
-
-        /**
-         * Radio Access Technology bitmask.
-         * To check what values can be contained, refer to {@link android.telephony.ServiceState}.
-         * 0 indicates all techs otherwise first bit refers to RAT/bearer 1, second bit refers to
-         * RAT/bearer 2 and so on.
-         * Bitmask for a radio tech R is (1 << (R - 1))
-         * <P>Type: INTEGER</P>
-         * @hide
-         * @deprecated this column is no longer supported, use {@link #NETWORK_TYPE_BITMASK} instead
-         */
-        @Deprecated
-        public static final String BEARER_BITMASK = "bearer_bitmask";
-
-        /**
-         * Radio technology (network type) bitmask.
-         * To check what values can be contained, refer to the NETWORK_TYPE_ constants in
-         * {@link android.telephony.TelephonyManager}.
-         * Bitmask for a radio tech R is (1 << (R - 1))
-         * <P>Type: INTEGER</P>
-         */
-        public static final String NETWORK_TYPE_BITMASK = "network_type_bitmask";
-
-        /**
-         * MVNO type:
-         * {@code SPN (Service Provider Name), IMSI, GID (Group Identifier Level 1)}.
-         * <P>Type: TEXT</P>
-         * @deprecated Use {@link #SIM_APN_URI} to query APN instead, this API will return
-         * matching APNs based on current subscription carrier, thus no need to specify MVNO_TYPE
-         * and other carrier matching information. In the future, Android will not support MVNO_TYPE
-         * for APN query.
-         */
-        public static final String MVNO_TYPE = "mvno_type";
-
-        /**
-         * MVNO data.
-         * Use the following examples.
-         * <ul>
-         *     <li>SPN: A MOBILE, BEN NL, ...</li>
-         *     <li>IMSI: 302720x94, 2060188, ...</li>
-         *     <li>GID: 4E, 33, ...</li>
-         * </ul>
-         * <P>Type: TEXT</P>
-         * @deprecated Use {@link #SIM_APN_URI} to query APN instead, this API will return
-         * matching APNs based on current subscription carrier, thus no need to specify
-         * MVNO_MATCH_DATA and other carrier matching information. In the future, Android will not
-         * support MVNO_MATCH_DATA for APN query.
-         */
-        public static final String MVNO_MATCH_DATA = "mvno_match_data";
-
-        /**
-         * The subscription to which the APN belongs to
-         * <p>Type: INTEGER (long) </p>
-         */
-        public static final String SUBSCRIPTION_ID = "sub_id";
-
-        /**
-         * The profile_id to which the APN saved in modem.
-         * <p>Type: INTEGER</p>
-         *@hide
-         */
-        public static final String PROFILE_ID = "profile_id";
-
-        /**
-         * If set to {@code true}, then the APN setting will persist to the modem.
-         * <p>Type: INTEGER (boolean)</p>
-         *@hide
-         */
-        @SystemApi
-        public static final String MODEM_PERSIST = "modem_cognitive";
-
-        /**
-         * The max number of connections of this APN.
-         * <p>Type: INTEGER</p>
-         *@hide
-         */
-        @SystemApi
-        public static final String MAX_CONNECTIONS = "max_conns";
-
-        /**
-         * The wait time for retrying the APN, in milliseconds.
-         * <p>Type: INTEGER</p>
-         *@hide
-         */
-        @SystemApi
-        public static final String WAIT_TIME_RETRY = "wait_time";
-
-        /**
-         * The max number of seconds this APN will support its maximum number of connections
-         * as defined in {@link #MAX_CONNECTIONS}.
-         * <p>Type: INTEGER</p>
-         *@hide
-         */
-        @SystemApi
-        public static final String TIME_LIMIT_FOR_MAX_CONNECTIONS = "max_conns_time";
-
-        /**
-         * The MTU (maximum transmit unit) size of the mobile interface to which the APN is
-         * connected, in bytes.
-         * <p>Type: INTEGER </p>
-         * @hide
-         */
-        @SystemApi
-        public static final String MTU = "mtu";
-
-        /**
-         * APN edit status. APN could be added/edited/deleted by a user or carrier.
-         * see all possible returned APN edit status.
-         * <ul>
-         *     <li>{@link #UNEDITED}</li>
-         *     <li>{@link #USER_EDITED}</li>
-         *     <li>{@link #USER_DELETED}</li>
-         *     <li>{@link #CARRIER_EDITED}</li>
-         *     <li>{@link #CARRIER_DELETED}</li>
-         * </ul>
-         * <p>Type: INTEGER </p>
-         * @hide
-         */
-        @SystemApi
-        public static final String EDITED_STATUS = "edited";
-
-        /**
-         * {@code true} if this APN visible to the user, {@code false} otherwise.
-         * <p>Type: INTEGER (boolean)</p>
-         * @hide
-         */
-        @SystemApi
-        public static final String USER_VISIBLE = "user_visible";
-
-        /**
-         * {@code true} if the user allowed to edit this APN, {@code false} otherwise.
-         * <p>Type: INTEGER (boolean)</p>
-         * @hide
-         */
-        @SystemApi
-        public static final String USER_EDITABLE = "user_editable";
-
-        /**
-         * {@link #EDITED_STATUS APN edit status} indicates that this APN has not been edited or
-         * fails to edit.
-         * <p>Type: INTEGER </p>
-         * @hide
-         */
-        @SystemApi
-        public static final @EditStatus int UNEDITED = 0;
-
-        /**
-         * {@link #EDITED_STATUS APN edit status} indicates that this APN has been edited by users.
-         * <p>Type: INTEGER </p>
-         * @hide
-         */
-        @SystemApi
-        public static final @EditStatus int USER_EDITED = 1;
-
-        /**
-         * {@link #EDITED_STATUS APN edit status} indicates that this APN has been deleted by users.
-         * <p>Type: INTEGER </p>
-         * @hide
-         */
-        @SystemApi
-        public static final @EditStatus int USER_DELETED = 2;
-
-        /**
-         * {@link #EDITED_STATUS APN edit status} is an intermediate value used to indicate that an
-         * entry deleted by the user is still present in the new APN database and therefore must
-         * remain tagged as user deleted rather than completely removed from the database.
-         * @hide
-         */
-        public static final int USER_DELETED_BUT_PRESENT_IN_XML = 3;
-
-        /**
-         * {@link #EDITED_STATUS APN edit status} indicates that this APN has been edited by
-         * carriers.
-         * <p>Type: INTEGER </p>
-         * @hide
-         */
-        @SystemApi
-        public static final @EditStatus int CARRIER_EDITED = 4;
-
-        /**
-         * {@link #EDITED_STATUS APN edit status} indicates that this APN has been deleted by
-         * carriers. CARRIER_DELETED values are currently not used as there is no use case.
-         * If they are used, delete() will have to change accordingly. Currently it is hardcoded to
-         * USER_DELETED.
-         * <p>Type: INTEGER </p>
-         * @hide
-         */
-        public static final @EditStatus int CARRIER_DELETED = 5;
-
-        /**
-         * {@link #EDITED_STATUS APN edit status} is an intermediate value used to indicate that an
-         * entry deleted by the carrier is still present in the new APN database and therefore must
-         * remain tagged as user deleted rather than completely removed from the database.
-         * @hide
-         */
-        public static final int CARRIER_DELETED_BUT_PRESENT_IN_XML = 6;
-
-        /**
-         * The owner of the APN.
-         * <p>Type: INTEGER</p>
-         * @hide
-         */
-        public static final String OWNED_BY = "owned_by";
-
-        /**
-         * Possible value for the OWNED_BY field.
-         * APN is owned by DPC.
-         * @hide
-         */
-        public static final int OWNED_BY_DPC = 0;
-
-        /**
-         * Possible value for the OWNED_BY field.
-         * APN is owned by other sources.
-         * @hide
-         */
-        public static final int OWNED_BY_OTHERS = 1;
-
-        /**
-         * The APN set id. When the user manually selects an APN or the framework sets an APN as
-         * preferred, all APNs with the same set id as the selected APN should be prioritized over
-         * APNs in other sets.
-         * <p>Type: INTEGER</p>
-         * @hide
-         */
-        @SystemApi
-        public static final String APN_SET_ID = "apn_set_id";
-
-        /**
-         * Possible value for the {@link #APN_SET_ID} field. By default APNs will not belong to a
-         * set. If the user manually selects an APN without apn set id, there is no need to
-         * prioritize any specific APN set ids.
-         * <p>Type: INTEGER</p>
-         * @hide
-         */
-        @SystemApi
-        public static final int NO_APN_SET_ID = 0;
-
-        /**
-         * A unique carrier id associated with this APN
-         * {@see TelephonyManager#getSimCarrierId()}
-         * <p>Type: STRING</p>
-         */
-        public static final String CARRIER_ID = "carrier_id";
-
-        /**
-         * The skip 464xlat flag. Flag works as follows.
-         * {@link #SKIP_464XLAT_DEFAULT}: the APN will skip only APN is IMS and no internet.
-         * {@link #SKIP_464XLAT_DISABLE}: the APN will NOT skip 464xlat
-         * {@link #SKIP_464XLAT_ENABLE}: the APN will skip 464xlat
-         * <p>Type: INTEGER</p>
-         *
-         * @hide
-         */
-        public static final String SKIP_464XLAT = "skip_464xlat";
-
-        /**
-         * Possible value for the {@link #SKIP_464XLAT} field.
-         * <p>Type: INTEGER</p>
-         *
-         * @hide
-         */
-        public static final int SKIP_464XLAT_DEFAULT = -1;
-
-        /**
-         * Possible value for the {@link #SKIP_464XLAT} field.
-         * <p>Type: INTEGER</p>
-         *
-         * @hide
-         */
-        public static final int SKIP_464XLAT_DISABLE = 0;
-
-        /**
-         * Possible value for the {@link #SKIP_464XLAT} field.
-         * <p>Type: INTEGER</p>
-         *
-         * @hide
-         */
-        public static final int SKIP_464XLAT_ENABLE = 1;
-
-
-        /** @hide */
-        @IntDef({
-                UNEDITED,
-                USER_EDITED,
-                USER_DELETED,
-                CARRIER_DELETED,
-                CARRIER_EDITED,
-        })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface EditStatus {}
-
-        /** @hide */
-        @IntDef({
-                SKIP_464XLAT_DEFAULT,
-                SKIP_464XLAT_DISABLE,
-                SKIP_464XLAT_ENABLE,
-        })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface Skip464XlatStatus {}
-
-    }
-
-    /**
-     * Contains received cell broadcast messages. More details are available in 3GPP TS 23.041.
-     * @hide
-     */
-    @SystemApi
-    @TestApi
-    public static final class CellBroadcasts implements BaseColumns {
-
-        /**
-         * Not instantiable.
-         * @hide
-         */
-        private CellBroadcasts() {}
-
-        /**
-         * The {@code content://} URI for this table.
-         * Only privileged framework components running on phone or network stack uid can
-         * query or modify this table.
-         */
-        @NonNull
-        public static final Uri CONTENT_URI = Uri.parse("content://cellbroadcasts");
-
-        /**
-         * The {@code content://} URI for query cellbroadcast message history.
-         * query results include following entries
-         * <ul>
-         *     <li>{@link #_ID}</li>
-         *     <li>{@link #SLOT_INDEX}</li>
-         *     <li>{@link #GEOGRAPHICAL_SCOPE}</li>
-         *     <li>{@link #PLMN}</li>
-         *     <li>{@link #LAC}</li>
-         *     <li>{@link #CID}</li>
-         *     <li>{@link #SERIAL_NUMBER}</li>
-         *     <li>{@link #SERVICE_CATEGORY}</li>
-         *     <li>{@link #LANGUAGE_CODE}</li>
-         *     <li>{@link #MESSAGE_BODY}</li>
-         *     <li>{@link #DELIVERY_TIME}</li>
-         *     <li>{@link #MESSAGE_READ}</li>
-         *     <li>{@link #MESSAGE_FORMAT}</li>
-         *     <li>{@link #MESSAGE_PRIORITY}</li>
-         *     <li>{@link #ETWS_WARNING_TYPE}</li>
-         *     <li>{@link #CMAS_MESSAGE_CLASS}</li>
-         *     <li>{@link #CMAS_CATEGORY}</li>
-         *     <li>{@link #CMAS_RESPONSE_TYPE}</li>
-         *     <li>{@link #CMAS_SEVERITY}</li>
-         *     <li>{@link #CMAS_URGENCY}</li>
-         *     <li>{@link #CMAS_CERTAINTY}</li>
-         * </ul>
-         */
-        @RequiresPermission(Manifest.permission.READ_CELL_BROADCASTS)
-        @NonNull
-        public static final Uri MESSAGE_HISTORY_URI = Uri.parse("content://cellbroadcasts/history");
-
-        /**
-         * The subscription which received this cell broadcast message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String SUB_ID = "sub_id";
-
-        /**
-         * The slot which received this cell broadcast message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String SLOT_INDEX = "slot_index";
-
-        /**
-         * Message geographical scope. Valid values are:
-         * <ul>
-         * <li>{@link android.telephony.SmsCbMessage#GEOGRAPHICAL_SCOPE_CELL_WIDE}. meaning the
-         * message is for the radio service cell</li>
-         * <li>{@link android.telephony.SmsCbMessage#GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE},
-         * meaning the message is for the radio service cell and immediately displayed</li>
-         * <li>{@link android.telephony.SmsCbMessage#GEOGRAPHICAL_SCOPE_PLMN_WIDE}, meaning the
-         * message is for the PLMN (i.e. MCC/MNC)</li>
-         * <li>{@link android.telephony.SmsCbMessage#GEOGRAPHICAL_SCOPE_LOCATION_AREA_WIDE},
-         * meaning the message is for the location area (in GSM) or service area (in UMTS)</li>
-         * </ul>
-         *
-         * <p>A message meant for a particular scope is automatically dismissed when the device
-         * exits that scope.</p>
-         * <P>Type: INTEGER</P>
-         */
-        public static final String GEOGRAPHICAL_SCOPE = "geo_scope";
-
-        /**
-         * Message serial number.
-         * <p>
-         * A 16-bit integer which identifies a particular CBS (cell
-         * broadcast short message service) message. The core network is responsible for
-         * allocating this value, and the value may be managed cyclically (3GPP TS 23.041 section
-         * 9.2.1) once the serial message has been incremented a sufficient number of times.
-         * </p>
-         * <P>Type: INTEGER</P>
-         */
-        public static final String SERIAL_NUMBER = "serial_number";
-
-        /**
-         * PLMN (i.e. MCC/MNC) of broadcast sender. {@code SERIAL_NUMBER + PLMN + LAC + CID}
-         * uniquely identifies a broadcast for duplicate detection purposes.
-         * <P>Type: TEXT</P>
-         */
-        public static final String PLMN = "plmn";
-
-        /**
-         * Location area code (LAC).
-         * <p>Code representing location area (GSM) or service area (UMTS) of broadcast sender.
-         * Unused for CDMA. Only included if Geographical Scope of message is not PLMN wide (01).
-         * This value is sent by the network based on the cell tower.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String LAC = "lac";
-
-        /**
-         * Cell ID of message sender (GSM/UMTS). Unused for CDMA. Only included when the
-         * Geographical Scope of message is cell wide (00 or 11).
-         * <P>Type: INTEGER</P>
-         */
-        public static final String CID = "cid";
-
-        /**
-         * Message code. <em>OBSOLETE: merged into SERIAL_NUMBER.</em>
-         * <P>Type: INTEGER</P>
-         * @hide
-         */
-        public static final String V1_MESSAGE_CODE = "message_code";
-
-        /**
-         * Message identifier. <em>OBSOLETE: renamed to SERVICE_CATEGORY.</em>
-         * <P>Type: INTEGER</P>
-         * @hide
-         */
-        public static final String V1_MESSAGE_IDENTIFIER = "message_id";
-
-        /**
-         * Service category which represents the general topic of the message.
-         * <p>
-         * For GSM/UMTS: message identifier (see 3GPP TS 23.041 section 9.4.1.2.2)
-         * For CDMA: a 16-bit CDMA service category (see 3GPP2 C.R1001-D section 9.3)
-         * </p>
-         * <P>Type: INTEGER</P>
-         */
-        public static final String SERVICE_CATEGORY = "service_category";
-
-        /**
-         * Message language code. (See 3GPP TS 23.041 section 9.4.1.2.3 for details).
-         * <P>Type: TEXT</P>
-         */
-        public static final String LANGUAGE_CODE = "language";
-
-        /**
-         * Message body.
-         * <P>Type: TEXT</P>
-         */
-        public static final String MESSAGE_BODY = "body";
-
-        /**
-         * Message delivery time.
-         * <p>This value is a system timestamp using {@link System#currentTimeMillis}</p>
-         * <P>Type: INTEGER (long)</P>
-         */
-        public static final String DELIVERY_TIME = "date";
-
-        /**
-         * Has the message been viewed?
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String MESSAGE_READ = "read";
-
-        /**
-         * Message format ({@link android.telephony.SmsCbMessage#MESSAGE_FORMAT_3GPP} or
-         * {@link android.telephony.SmsCbMessage#MESSAGE_FORMAT_3GPP2}).
-         * <P>Type: INTEGER</P>
-         */
-        public static final String MESSAGE_FORMAT = "format";
-
-        /**
-         * Message priority.
-         * <p>This includes
-         * <ul>
-         * <li>{@link android.telephony.SmsCbMessage#MESSAGE_PRIORITY_NORMAL}</li>
-         * <li>{@link android.telephony.SmsCbMessage#MESSAGE_PRIORITY_INTERACTIVE}</li>
-         * <li>{@link android.telephony.SmsCbMessage#MESSAGE_PRIORITY_URGENT}</li>
-         * <li>{@link android.telephony.SmsCbMessage#MESSAGE_PRIORITY_EMERGENCY}</li>
-         * </p>
-         * </ul>
-         * <P>Type: INTEGER</P>
-         */
-        public static final String MESSAGE_PRIORITY = "priority";
-
-        /**
-         * ETWS (Earthquake and Tsunami Warning System) warning type (ETWS alerts only).
-         * <p>See {@link android.telephony.SmsCbEtwsInfo}</p>
-         * <P>Type: INTEGER</P>
-         */
-        public static final String ETWS_WARNING_TYPE = "etws_warning_type";
-
-        /**
-         * CMAS (Commercial Mobile Alert System) message class (CMAS alerts only).
-         * <p>See {@link android.telephony.SmsCbCmasInfo}</p>
-         * <P>Type: INTEGER</P>
-         */
-        public static final String CMAS_MESSAGE_CLASS = "cmas_message_class";
-
-        /**
-         * CMAS category (CMAS alerts only).
-         * <P>Type: INTEGER</P>
-         */
-        public static final String CMAS_CATEGORY = "cmas_category";
-
-        /**
-         * CMAS response type (CMAS alerts only).
-         * <P>Type: INTEGER</P>
-         */
-        public static final String CMAS_RESPONSE_TYPE = "cmas_response_type";
-
-        /**
-         * CMAS severity (CMAS alerts only).
-         * <P>Type: INTEGER</P>
-         */
-        public static final String CMAS_SEVERITY = "cmas_severity";
-
-        /**
-         * CMAS urgency (CMAS alerts only).
-         * <P>Type: INTEGER</P>
-         */
-        public static final String CMAS_URGENCY = "cmas_urgency";
-
-        /**
-         * CMAS certainty (CMAS alerts only).
-         * <P>Type: INTEGER</P>
-         */
-        public static final String CMAS_CERTAINTY = "cmas_certainty";
-
-        /** The default sort order for this table. */
-        public static final String DEFAULT_SORT_ORDER = DELIVERY_TIME + " DESC";
-
-        /**
-         * The timestamp in millisecond of when the device received the message.
-         * <P>Type: BIGINT</P>
-         */
-        public static final String RECEIVED_TIME = "received_time";
-
-        /**
-         * Indicates that whether the message has been broadcasted to the application.
-         * <P>Type: BOOLEAN</P>
-         */
-        public static final String MESSAGE_BROADCASTED = "message_broadcasted";
-
-        /**
-         * The Warning Area Coordinates Elements. This element is used for geo-fencing purpose.
-         *
-         * The geometry and its coordinates are separated vertical bar, the first item is the
-         * geometry type and the remaining items are the parameter of this geometry.
-         *
-         * Only circle and polygon are supported. The coordinates are represented in Horizontal
-         * coordinates format.
-         *
-         * Coordinate encoding:
-         * "latitude, longitude"
-         * where -90.00000 <= latitude <= 90.00000 and -180.00000 <= longitude <= 180.00000
-         *
-         * Polygon encoding:
-         * "polygon|lat1,lng1|lat2,lng2|...|latn,lngn"
-         * lat1,lng1 ... latn,lngn are the vertices coordinate of the polygon.
-         *
-         * Circle encoding:
-         * "circle|lat,lng|radius".
-         * lat,lng is the center of the circle. The unit of circle's radius is meter.
-         *
-         * Example:
-         * "circle|0,0|100" mean a circle which center located at (0,0) and its radius is 100 meter.
-         * "polygon|0,1.5|0,1|1,1|1,0" mean a polygon has vertices (0,1.5),(0,1),(1,1),(1,0).
-         *
-         * There could be more than one geometry store in this field, they are separated by a
-         * semicolon.
-         *
-         * Example:
-         * "circle|0,0|100;polygon|0,0|0,1.5|1,1|1,0;circle|100.123,100|200.123"
-         *
-         * <P>Type: TEXT</P>
-         */
-        public static final String GEOMETRIES = "geometries";
-
-        /**
-         * Geo-Fencing Maximum Wait Time in second. The range of the time is [0, 255]. A device
-         * shall allow to determine its position meeting operator policy. If the device is unable to
-         * determine its position meeting operator policy within the GeoFencing Maximum Wait Time,
-         * it shall present the alert to the user and discontinue further positioning determination
-         * for the alert.
-         *
-         * <P>Type: INTEGER</P>
-         */
-        public static final String MAXIMUM_WAIT_TIME = "maximum_wait_time";
-
-        /**
-         * Query columns for instantiating com.android.cellbroadcastreceiver.CellBroadcastMessage.
-         * @hide
-         */
-        @NonNull
-        public static final String[] QUERY_COLUMNS = {
-                _ID,
-                GEOGRAPHICAL_SCOPE,
-                PLMN,
-                LAC,
-                CID,
-                SERIAL_NUMBER,
-                SERVICE_CATEGORY,
-                LANGUAGE_CODE,
-                MESSAGE_BODY,
-                DELIVERY_TIME,
-                MESSAGE_READ,
-                MESSAGE_FORMAT,
-                MESSAGE_PRIORITY,
-                ETWS_WARNING_TYPE,
-                CMAS_MESSAGE_CLASS,
-                CMAS_CATEGORY,
-                CMAS_RESPONSE_TYPE,
-                CMAS_SEVERITY,
-                CMAS_URGENCY,
-                CMAS_CERTAINTY
-        };
-
-        /**
-         * Query columns for instantiating {@link android.telephony.SmsCbMessage} objects.
-         * @hide
-         */
-        public static final String[] QUERY_COLUMNS_FWK = {
-                _ID,
-                SLOT_INDEX,
-                SUB_ID,
-                GEOGRAPHICAL_SCOPE,
-                PLMN,
-                LAC,
-                CID,
-                SERIAL_NUMBER,
-                SERVICE_CATEGORY,
-                LANGUAGE_CODE,
-                MESSAGE_BODY,
-                MESSAGE_FORMAT,
-                MESSAGE_PRIORITY,
-                ETWS_WARNING_TYPE,
-                CMAS_MESSAGE_CLASS,
-                CMAS_CATEGORY,
-                CMAS_RESPONSE_TYPE,
-                CMAS_SEVERITY,
-                CMAS_URGENCY,
-                CMAS_CERTAINTY,
-                RECEIVED_TIME,
-                MESSAGE_BROADCASTED,
-                GEOMETRIES,
-                MAXIMUM_WAIT_TIME
-        };
-    }
-
-    /**
-     * Constants for interfacing with the ServiceStateProvider and the different fields of the
-     * {@link ServiceState} class accessible through the provider.
-     */
-    public static final class ServiceStateTable {
-
-        /**
-         * Not instantiable.
-         * @hide
-         */
-        private ServiceStateTable() {}
-
-        /**
-         * The authority string for the ServiceStateProvider
-         */
-        public static final String AUTHORITY = "service-state";
-
-        /**
-         * The {@code content://} style URL for the ServiceStateProvider
-         */
-        public static final Uri CONTENT_URI = Uri.parse("content://service-state/");
-
-        /**
-         * Generates a content {@link Uri} used to receive updates on a specific field in the
-         * ServiceState provider.
-         * <p>
-         * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
-         * {@link ServiceState} while your app is running.
-         * You can also use a {@link android.app.job.JobService} to
-         * ensure your app is notified of changes to the {@link Uri} even when it is not running.
-         * Note, however, that using a {@link android.app.job.JobService}
-         * does not guarantee timely delivery of
-         * updates to the {@link Uri}.
-         *
-         * @param subscriptionId the subscriptionId to receive updates on
-         * @param field the ServiceState field to receive updates on
-         * @return the Uri used to observe {@link ServiceState} changes
-         */
-        public static Uri getUriForSubscriptionIdAndField(int subscriptionId, String field) {
-            return CONTENT_URI.buildUpon().appendEncodedPath(String.valueOf(subscriptionId))
-                    .appendEncodedPath(field).build();
-        }
-
-        /**
-         * Generates a content {@link Uri} used to receive updates on every field in the
-         * ServiceState provider.
-         * <p>
-         * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
-         * {@link ServiceState} while your app is running.  You can also use a
-         * {@link android.app.job.JobService} to
-         * ensure your app is notified of changes to the {@link Uri} even when it is not running.
-         * Note, however, that using a {@link android.app.job.JobService}
-         * does not guarantee timely delivery of
-         * updates to the {@link Uri}.
-         *
-         * @param subscriptionId the subscriptionId to receive updates on
-         * @return the Uri used to observe {@link ServiceState} changes
-         */
-        public static Uri getUriForSubscriptionId(int subscriptionId) {
-            return CONTENT_URI.buildUpon().appendEncodedPath(String.valueOf(subscriptionId)).build();
-        }
-
-        /**
-         * Used to insert a ServiceState into the ServiceStateProvider as a ContentValues instance.
-         *
-         * @param state the ServiceState to convert into ContentValues
-         * @return the convertedContentValues instance
-         * @hide
-         */
-        public static ContentValues getContentValuesForServiceState(ServiceState state) {
-            ContentValues values = new ContentValues();
-            final Parcel p = Parcel.obtain();
-            state.writeToParcel(p, 0);
-            // Turn the parcel to byte array. Safe to do this because the content values were never
-            // written into a persistent storage. ServiceStateProvider keeps values in the memory.
-            values.put(SERVICE_STATE, p.marshall());
-            return values;
-        }
-
-        /**
-         * The current service state.
-         *
-         * This is the entire {@link ServiceState} object in byte array.
-         *
-         * @hide
-         */
-        public static final String SERVICE_STATE = "service_state";
-
-        /**
-         * An integer value indicating the current voice service state.
-         * <p>
-         * Valid values: {@link ServiceState#STATE_IN_SERVICE},
-         * {@link ServiceState#STATE_OUT_OF_SERVICE}, {@link ServiceState#STATE_EMERGENCY_ONLY},
-         * {@link ServiceState#STATE_POWER_OFF}.
-         * <p>
-         * This is the same as {@link ServiceState#getState()}.
-         */
-        public static final String VOICE_REG_STATE = "voice_reg_state";
-
-        /**
-         * An integer value indicating the current data service state.
-         * <p>
-         * Valid values: {@link ServiceState#STATE_IN_SERVICE},
-         * {@link ServiceState#STATE_OUT_OF_SERVICE}, {@link ServiceState#STATE_EMERGENCY_ONLY},
-         * {@link ServiceState#STATE_POWER_OFF}.
-         * <p>
-         * This is the same as {@link ServiceState#getDataRegState()}.
-         * @hide
-         */
-        public static final String DATA_REG_STATE = "data_reg_state";
-
-        /**
-         * An integer value indicating the current voice roaming type.
-         * <p>
-         * This is the same as {@link ServiceState#getVoiceRoamingType()}.
-         * @hide
-         */
-        public static final String VOICE_ROAMING_TYPE = "voice_roaming_type";
-
-        /**
-         * An integer value indicating the current data roaming type.
-         * <p>
-         * This is the same as {@link ServiceState#getDataRoamingType()}.
-         * @hide
-         */
-        public static final String DATA_ROAMING_TYPE = "data_roaming_type";
-
-        /**
-         * The current registered voice network operator name in long alphanumeric format.
-         * <p>
-         * This is the same as {@link ServiceState#getVoiceOperatorAlphaLong()}.
-         * @hide
-         */
-        public static final String VOICE_OPERATOR_ALPHA_LONG = "voice_operator_alpha_long";
-
-        /**
-         * The current registered operator name in short alphanumeric format.
-         * <p>
-         * In GSM/UMTS, short format can be up to 8 characters long. The current registered voice
-         * network operator name in long alphanumeric format.
-         * <p>
-         * This is the same as {@link ServiceState#getVoiceOperatorAlphaShort()}.
-         * @hide
-         */
-        public static final String VOICE_OPERATOR_ALPHA_SHORT = "voice_operator_alpha_short";
-
-
-        /**
-         * The current registered operator numeric id.
-         * <p>
-         * In GSM/UMTS, numeric format is 3 digit country code plus 2 or 3 digit
-         * network code.
-         * <p>
-         * This is the same as {@link ServiceState#getOperatorNumeric()}.
-         */
-        public static final String VOICE_OPERATOR_NUMERIC = "voice_operator_numeric";
-
-        /**
-         * The current registered data network operator name in long alphanumeric format.
-         * <p>
-         * This is the same as {@link ServiceState#getDataOperatorAlphaLong()}.
-         * @hide
-         */
-        public static final String DATA_OPERATOR_ALPHA_LONG = "data_operator_alpha_long";
-
-        /**
-         * The current registered data network operator name in short alphanumeric format.
-         * <p>
-         * This is the same as {@link ServiceState#getDataOperatorAlphaShort()}.
-         * @hide
-         */
-        public static final String DATA_OPERATOR_ALPHA_SHORT = "data_operator_alpha_short";
-
-        /**
-         * The current registered data network operator numeric id.
-         * <p>
-         * This is the same as {@link ServiceState#getDataOperatorNumeric()}.
-         * @hide
-         */
-        public static final String DATA_OPERATOR_NUMERIC = "data_operator_numeric";
-
-        /**
-         * The current network selection mode.
-         * <p>
-         * This is the same as {@link ServiceState#getIsManualSelection()}.
-         */
-        public static final String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection";
-
-        /**
-         * This is the same as {@link ServiceState#getRilVoiceRadioTechnology()}.
-         * @hide
-         */
-        public static final String RIL_VOICE_RADIO_TECHNOLOGY = "ril_voice_radio_technology";
-
-        /**
-         * This is the same as {@link ServiceState#getRilDataRadioTechnology()}.
-         * @hide
-         */
-        public static final String RIL_DATA_RADIO_TECHNOLOGY = "ril_data_radio_technology";
-
-        /**
-         * This is the same as {@link ServiceState#getCssIndicator()}.
-         * @hide
-         */
-        public static final String CSS_INDICATOR = "css_indicator";
-
-        /**
-         * This is the same as {@link ServiceState#getCdmaNetworkId()}.
-         * @hide
-         */
-        public static final String NETWORK_ID = "network_id";
-
-        /**
-         * This is the same as {@link ServiceState#getCdmaSystemId()}.
-         * @hide
-         */
-        public static final String SYSTEM_ID = "system_id";
-
-        /**
-         * This is the same as {@link ServiceState#getCdmaRoamingIndicator()}.
-         * @hide
-         */
-        public static final String CDMA_ROAMING_INDICATOR = "cdma_roaming_indicator";
-
-        /**
-         * This is the same as {@link ServiceState#getCdmaDefaultRoamingIndicator()}.
-         * @hide
-         */
-        public static final String CDMA_DEFAULT_ROAMING_INDICATOR =
-                "cdma_default_roaming_indicator";
-
-        /**
-         * This is the same as {@link ServiceState#getCdmaEriIconIndex()}.
-         * @hide
-         */
-        public static final String CDMA_ERI_ICON_INDEX = "cdma_eri_icon_index";
-
-        /**
-         * This is the same as {@link ServiceState#getCdmaEriIconMode()}.
-         * @hide
-         */
-        public static final String CDMA_ERI_ICON_MODE = "cdma_eri_icon_mode";
-
-        /**
-         * This is the same as {@link ServiceState#isEmergencyOnly()}.
-         * @hide
-         */
-        public static final String IS_EMERGENCY_ONLY = "is_emergency_only";
-
-        /**
-         * This is the same as {@link ServiceState#getDataRoamingFromRegistration()}.
-         * @hide
-         */
-        public static final String IS_DATA_ROAMING_FROM_REGISTRATION =
-                "is_data_roaming_from_registration";
-
-        /**
-         * This is the same as {@link ServiceState#isUsingCarrierAggregation()}.
-         * @hide
-         */
-        public static final String IS_USING_CARRIER_AGGREGATION = "is_using_carrier_aggregation";
-
-        /**
-         * The current registered raw data network operator name in long alphanumeric format.
-         * <p>
-         * This is the same as {@link ServiceState#getOperatorAlphaLongRaw()}.
-         * @hide
-         */
-        public static final String OPERATOR_ALPHA_LONG_RAW = "operator_alpha_long_raw";
-
-        /**
-         * The current registered raw data network operator name in short alphanumeric format.
-         * <p>
-         * This is the same as {@link ServiceState#getOperatorAlphaShortRaw()}.
-         * @hide
-         */
-        public static final String OPERATOR_ALPHA_SHORT_RAW = "operator_alpha_short_raw";
-    }
-
-    /**
-     * Contains carrier identification information for the current subscriptions.
-     */
-    public static final class CarrierId implements BaseColumns {
-        /**
-         * Not instantiable.
-         * @hide
-         */
-        private CarrierId() {}
-
-        /**
-         * The {@code content://} style URI for this provider.
-         */
-        public static final Uri CONTENT_URI = Uri.parse("content://carrier_id");
-
-        /**
-         * The authority string for the CarrierId Provider
-         * @hide
-         */
-        public static final String AUTHORITY = "carrier_id";
-
-
-        /**
-         * Generates a content {@link Uri} used to receive updates on carrier identity change
-         * on the given subscriptionId
-         * <p>
-         * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
-         * carrier identity {@link TelephonyManager#getSimCarrierId()}
-         * while your app is running. You can also use a {@link android.app.job.JobService}
-         * to ensure your app
-         * is notified of changes to the {@link Uri} even when it is not running.
-         * Note, however, that using a {@link android.app.job.JobService} does not guarantee
-         * timely delivery of updates to the {@link Uri}.
-         *
-         * @param subscriptionId the subscriptionId to receive updates on
-         * @return the Uri used to observe carrier identity changes
-         */
-        public static Uri getUriForSubscriptionId(int subscriptionId) {
-            return CONTENT_URI.buildUpon().appendEncodedPath(
-                    String.valueOf(subscriptionId)).build();
-        }
-
-        /**
-         * Generates a content {@link Uri} used to receive updates on specific carrier identity
-         * change on the given subscriptionId returned by
-         * {@link TelephonyManager#getSimSpecificCarrierId()}.
-         * @see TelephonyManager#ACTION_SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED
-         * <p>
-         * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
-         * specific carrier identity {@link TelephonyManager#getSimSpecificCarrierId()}
-         * while your app is running. You can also use a {@link android.app.job.JobService}
-         * to ensure your app
-         * is notified of changes to the {@link Uri} even when it is not running.
-         * Note, however, that using a {@link android.app.job.JobService} does not guarantee timely
-         * delivery of updates to the {@link Uri}.
-         *
-         * @param subscriptionId the subscriptionId to receive updates on
-         * @return the Uri used to observe specific carrier identity changes
-         */
-        @NonNull
-        public static Uri getSpecificCarrierIdUriForSubscriptionId(int subscriptionId) {
-            return Uri.withAppendedPath(Uri.withAppendedPath(CONTENT_URI, "specific"),
-                    String.valueOf(subscriptionId));
-        }
-
-        /**
-         * A user facing carrier name.
-         * @see TelephonyManager#getSimCarrierIdName()
-         * <P>Type: TEXT </P>
-         */
-        public static final String CARRIER_NAME = "carrier_name";
-
-        /**
-         * A unique carrier id
-         * @see TelephonyManager#getSimCarrierId()
-         * <P>Type: INTEGER </P>
-         */
-        public static final String CARRIER_ID = "carrier_id";
-
-        /**
-         * A fine-grained carrier id.
-         * The specific carrier ID would be used for configuration purposes, but apps wishing to
-         * know about the carrier itself should use the regular carrier ID returned by
-         * {@link TelephonyManager#getSimCarrierId()}.
-         *
-         * @see TelephonyManager#getSimSpecificCarrierId()
-         * This is not a database column, only used to notify content observers for
-         * {@link #getSpecificCarrierIdUriForSubscriptionId(int)}
-         */
-        public static final String SPECIFIC_CARRIER_ID = "specific_carrier_id";
-
-        /**
-         * A user facing carrier name for specific carrier id {@link #SPECIFIC_CARRIER_ID}.
-         * @see TelephonyManager#getSimSpecificCarrierIdName()
-         * This is not a database column, only used to notify content observers for
-         * {@link #getSpecificCarrierIdUriForSubscriptionId(int)}
-         */
-        public static final String SPECIFIC_CARRIER_ID_NAME = "specific_carrier_id_name";
-
-        /**
-         * A unique parent carrier id. The parent-child
-         * relationship can be used to further differentiate a single carrier by different networks,
-         * by prepaid v.s. postpaid. It's an optional field.
-         * A carrier id with a valid parent_carrier_id is considered fine-grained specific carrier
-         * ID, will not be returned as {@link #CARRIER_ID} but {@link #SPECIFIC_CARRIER_ID}.
-         * <P>Type: INTEGER </P>
-         * @hide
-         */
-        public static final String PARENT_CARRIER_ID = "parent_carrier_id";
-
-        /**
-         * Contains mappings between matching rules with carrier id for all carriers.
-         * @hide
-         */
-        @SystemApi
-        public static final class All implements BaseColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private All() {
-            }
-
-            /**
-             * Numeric operator ID (as String). {@code MCC + MNC}
-             * <P>Type: TEXT </P>
-             */
-            public static final String MCCMNC = "mccmnc";
-
-            /**
-             * Group id level 1 (as String).
-             * <P>Type: TEXT </P>
-             */
-            public static final String GID1 = "gid1";
-
-            /**
-             * Group id level 2 (as String).
-             * <P>Type: TEXT </P>
-             */
-            public static final String GID2 = "gid2";
-
-            /**
-             * Public Land Mobile Network name.
-             * <P>Type: TEXT </P>
-             */
-            public static final String PLMN = "plmn";
-
-            /**
-             * Prefix xpattern of IMSI (International Mobile Subscriber Identity).
-             * <P>Type: TEXT </P>
-             */
-            public static final String IMSI_PREFIX_XPATTERN = "imsi_prefix_xpattern";
-
-            /**
-             * Service Provider Name.
-             * <P>Type: TEXT </P>
-             */
-            public static final String SPN = "spn";
-
-            /**
-             * Prefer APN name.
-             * <P>Type: TEXT </P>
-             */
-            public static final String APN = "apn";
-
-            /**
-             * Prefix of Integrated Circuit Card Identifier.
-             * <P>Type: TEXT </P>
-             */
-            public static final String ICCID_PREFIX = "iccid_prefix";
-
-            /**
-             * Certificate for carrier privilege access rules.
-             * <P>Type: TEXT in hex string </P>
-             */
-            public static final String PRIVILEGE_ACCESS_RULE = "privilege_access_rule";
-
-            /**
-             * The {@code content://} URI for this table.
-             */
-            @NonNull
-            public static final Uri CONTENT_URI = Uri.parse("content://carrier_id/all");
-        }
-    }
-}
diff --git a/core/java/android/service/carrier/CarrierIdentifier.aidl b/telephony/java/android/service/carrier/CarrierIdentifier.aidl
similarity index 100%
rename from core/java/android/service/carrier/CarrierIdentifier.aidl
rename to telephony/java/android/service/carrier/CarrierIdentifier.aidl
diff --git a/core/java/android/service/carrier/CarrierIdentifier.java b/telephony/java/android/service/carrier/CarrierIdentifier.java
similarity index 100%
rename from core/java/android/service/carrier/CarrierIdentifier.java
rename to telephony/java/android/service/carrier/CarrierIdentifier.java
diff --git a/core/java/android/service/carrier/CarrierService.java b/telephony/java/android/service/carrier/CarrierService.java
similarity index 100%
rename from core/java/android/service/carrier/CarrierService.java
rename to telephony/java/android/service/carrier/CarrierService.java
diff --git a/core/java/android/service/carrier/ICarrierService.aidl b/telephony/java/android/service/carrier/ICarrierService.aidl
similarity index 100%
rename from core/java/android/service/carrier/ICarrierService.aidl
rename to telephony/java/android/service/carrier/ICarrierService.aidl
diff --git a/core/java/android/service/euicc/DownloadSubscriptionResult.aidl b/telephony/java/android/service/euicc/DownloadSubscriptionResult.aidl
similarity index 100%
rename from core/java/android/service/euicc/DownloadSubscriptionResult.aidl
rename to telephony/java/android/service/euicc/DownloadSubscriptionResult.aidl
diff --git a/core/java/android/service/euicc/DownloadSubscriptionResult.java b/telephony/java/android/service/euicc/DownloadSubscriptionResult.java
similarity index 100%
rename from core/java/android/service/euicc/DownloadSubscriptionResult.java
rename to telephony/java/android/service/euicc/DownloadSubscriptionResult.java
diff --git a/core/java/android/service/euicc/EuiccProfileInfo.aidl b/telephony/java/android/service/euicc/EuiccProfileInfo.aidl
similarity index 100%
rename from core/java/android/service/euicc/EuiccProfileInfo.aidl
rename to telephony/java/android/service/euicc/EuiccProfileInfo.aidl
diff --git a/core/java/android/service/euicc/EuiccProfileInfo.java b/telephony/java/android/service/euicc/EuiccProfileInfo.java
similarity index 100%
rename from core/java/android/service/euicc/EuiccProfileInfo.java
rename to telephony/java/android/service/euicc/EuiccProfileInfo.java
diff --git a/core/java/android/service/euicc/EuiccService.java b/telephony/java/android/service/euicc/EuiccService.java
similarity index 100%
rename from core/java/android/service/euicc/EuiccService.java
rename to telephony/java/android/service/euicc/EuiccService.java
diff --git a/core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.aidl b/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.aidl
similarity index 100%
rename from core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.aidl
rename to telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.aidl
diff --git a/core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java b/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java
similarity index 100%
rename from core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java
rename to telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java
diff --git a/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.aidl b/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.aidl
similarity index 100%
rename from core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.aidl
rename to telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.aidl
diff --git a/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java b/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java
similarity index 100%
rename from core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java
rename to telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java
diff --git a/core/java/android/service/euicc/GetEuiccProfileInfoListResult.aidl b/telephony/java/android/service/euicc/GetEuiccProfileInfoListResult.aidl
similarity index 100%
rename from core/java/android/service/euicc/GetEuiccProfileInfoListResult.aidl
rename to telephony/java/android/service/euicc/GetEuiccProfileInfoListResult.aidl
diff --git a/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java b/telephony/java/android/service/euicc/GetEuiccProfileInfoListResult.java
similarity index 100%
rename from core/java/android/service/euicc/GetEuiccProfileInfoListResult.java
rename to telephony/java/android/service/euicc/GetEuiccProfileInfoListResult.java
diff --git a/core/java/android/service/euicc/IDeleteSubscriptionCallback.aidl b/telephony/java/android/service/euicc/IDeleteSubscriptionCallback.aidl
similarity index 100%
rename from core/java/android/service/euicc/IDeleteSubscriptionCallback.aidl
rename to telephony/java/android/service/euicc/IDeleteSubscriptionCallback.aidl
diff --git a/core/java/android/service/euicc/IDownloadSubscriptionCallback.aidl b/telephony/java/android/service/euicc/IDownloadSubscriptionCallback.aidl
similarity index 100%
rename from core/java/android/service/euicc/IDownloadSubscriptionCallback.aidl
rename to telephony/java/android/service/euicc/IDownloadSubscriptionCallback.aidl
diff --git a/core/java/android/service/euicc/IEraseSubscriptionsCallback.aidl b/telephony/java/android/service/euicc/IEraseSubscriptionsCallback.aidl
similarity index 100%
rename from core/java/android/service/euicc/IEraseSubscriptionsCallback.aidl
rename to telephony/java/android/service/euicc/IEraseSubscriptionsCallback.aidl
diff --git a/core/java/android/service/euicc/IEuiccService.aidl b/telephony/java/android/service/euicc/IEuiccService.aidl
similarity index 100%
rename from core/java/android/service/euicc/IEuiccService.aidl
rename to telephony/java/android/service/euicc/IEuiccService.aidl
diff --git a/core/java/android/service/euicc/IGetDefaultDownloadableSubscriptionListCallback.aidl b/telephony/java/android/service/euicc/IGetDefaultDownloadableSubscriptionListCallback.aidl
similarity index 100%
rename from core/java/android/service/euicc/IGetDefaultDownloadableSubscriptionListCallback.aidl
rename to telephony/java/android/service/euicc/IGetDefaultDownloadableSubscriptionListCallback.aidl
diff --git a/core/java/android/service/euicc/IGetDownloadableSubscriptionMetadataCallback.aidl b/telephony/java/android/service/euicc/IGetDownloadableSubscriptionMetadataCallback.aidl
similarity index 100%
rename from core/java/android/service/euicc/IGetDownloadableSubscriptionMetadataCallback.aidl
rename to telephony/java/android/service/euicc/IGetDownloadableSubscriptionMetadataCallback.aidl
diff --git a/core/java/android/service/euicc/IGetEidCallback.aidl b/telephony/java/android/service/euicc/IGetEidCallback.aidl
similarity index 100%
rename from core/java/android/service/euicc/IGetEidCallback.aidl
rename to telephony/java/android/service/euicc/IGetEidCallback.aidl
diff --git a/core/java/android/service/euicc/IGetEuiccInfoCallback.aidl b/telephony/java/android/service/euicc/IGetEuiccInfoCallback.aidl
similarity index 100%
rename from core/java/android/service/euicc/IGetEuiccInfoCallback.aidl
rename to telephony/java/android/service/euicc/IGetEuiccInfoCallback.aidl
diff --git a/core/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl b/telephony/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl
similarity index 100%
rename from core/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl
rename to telephony/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl
diff --git a/core/java/android/service/euicc/IGetOtaStatusCallback.aidl b/telephony/java/android/service/euicc/IGetOtaStatusCallback.aidl
similarity index 100%
rename from core/java/android/service/euicc/IGetOtaStatusCallback.aidl
rename to telephony/java/android/service/euicc/IGetOtaStatusCallback.aidl
diff --git a/core/java/android/service/euicc/IOtaStatusChangedCallback.aidl b/telephony/java/android/service/euicc/IOtaStatusChangedCallback.aidl
similarity index 100%
rename from core/java/android/service/euicc/IOtaStatusChangedCallback.aidl
rename to telephony/java/android/service/euicc/IOtaStatusChangedCallback.aidl
diff --git a/core/java/android/service/euicc/IRetainSubscriptionsForFactoryResetCallback.aidl b/telephony/java/android/service/euicc/IRetainSubscriptionsForFactoryResetCallback.aidl
similarity index 100%
rename from core/java/android/service/euicc/IRetainSubscriptionsForFactoryResetCallback.aidl
rename to telephony/java/android/service/euicc/IRetainSubscriptionsForFactoryResetCallback.aidl
diff --git a/core/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl b/telephony/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl
similarity index 100%
rename from core/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl
rename to telephony/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl
diff --git a/core/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl b/telephony/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl
similarity index 100%
rename from core/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl
rename to telephony/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index a0aa60b..bb28df2 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -80,6 +80,7 @@
         public static final int EUTRAN = 3;
         public static final int CDMA2000 = 4;
         public static final int IWLAN = 5;
+        public static final int NGRAN = 6;
 
         /** @hide */
         private AccessNetworkType() {}
@@ -93,6 +94,7 @@
                 case EUTRAN: return "EUTRAN";
                 case CDMA2000: return "CDMA2000";
                 case IWLAN: return "IWLAN";
+                case NGRAN: return "NGRAN";
                 default: return Integer.toString(type);
             }
         }
@@ -247,6 +249,61 @@
         private CdmaBands() {};
     }
 
+    /**
+     * Frequency bands for NGRAN
+     */
+    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;
+
+        /** 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;
+
+        /** @hide */
+        private NgranBands() {};
+    }
+
     /** @hide */
     private AccessNetworkConstants() {};
 }
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index 72f758e..f89bbc7 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -1,6 +1,7 @@
 package android.telephony;
 
 import android.annotation.IntDef;
+import android.telecom.Connection;
 import android.telephony.data.ApnSetting;
 
 import java.lang.annotation.Retention;
@@ -509,4 +510,30 @@
             ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA,
             ServiceState.RIL_RADIO_TECHNOLOGY_NR})
     public @interface RilRadioTechnology {}
+
+    @IntDef({
+            Connection.AUDIO_CODEC_NONE,
+            Connection.AUDIO_CODEC_AMR,
+            Connection.AUDIO_CODEC_AMR_WB,
+            Connection.AUDIO_CODEC_QCELP13K,
+            Connection.AUDIO_CODEC_EVRC,
+            Connection.AUDIO_CODEC_EVRC_B,
+            Connection.AUDIO_CODEC_EVRC_WB,
+            Connection.AUDIO_CODEC_EVRC_NW,
+            Connection.AUDIO_CODEC_GSM_EFR,
+            Connection.AUDIO_CODEC_GSM_FR,
+            Connection.AUDIO_CODEC_G711U,
+            Connection.AUDIO_CODEC_G723,
+            Connection.AUDIO_CODEC_G711A,
+            Connection.AUDIO_CODEC_G722,
+            Connection.AUDIO_CODEC_G711AB,
+            Connection.AUDIO_CODEC_G729,
+            Connection.AUDIO_CODEC_EVS_NB,
+            Connection.AUDIO_CODEC_EVS_WB,
+            Connection.AUDIO_CODEC_EVS_SWB,
+            Connection.AUDIO_CODEC_EVS_FB
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ImsAudioCodec {
+    }
 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 479b144..91646ad 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -100,6 +100,16 @@
             KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool";
 
     /**
+     * Boolean indicating the Supplementary Services(SS) is disable when airplane mode on in the
+     * Call Settings menu.
+     * {@code true}: SS is disable when airplane mode on.
+     * {@code false}: SS is enable when airplane mode on.
+     * The default value for this key is {@code false}
+     */
+    public static final String KEY_DISABLE_SUPPLEMENTARY_SERVICES_IN_AIRPLANE_MODE_BOOL =
+            "disable_supplementary_services_in_airplane_mode_bool";
+
+    /**
      * Boolean indicating if the "Call forwarding" item is visible in the Call Settings menu.
      * true means visible. false means gone.
      * @hide
@@ -1042,6 +1052,9 @@
      *
      * When {@code false}, the old behavior is used, where the toggle in accessibility settings is
      * used to set the IMS stack's RTT enabled state.
+     *
+     * @deprecated -- this flag no longer does anything. Remove once the new behavior is verified.
+     *
      * @hide
      */
     public static final String KEY_IGNORE_RTT_MODE_SETTING_BOOL =
@@ -2313,7 +2326,7 @@
      * Reference: 3GPP TS 38.215
      *
      * 4 threshold integers must be within the boundaries [-20 dB, -3 dB], and the levels are:
-     *     "NONE: [-23, threshold1]"
+     *     "NONE: [-20, threshold1]"
      *     "POOR: (threshold1, threshold2]"
      *     "MODERATE: (threshold2, threshold3]"
      *     "GOOD:  (threshold3, threshold4]"
@@ -2347,15 +2360,26 @@
     /**
      * Bit-field integer to determine whether to use SS reference signal received power (SSRSRP),
      * SS reference signal received quality (SSRSRQ), or/and SS signal-to-noise and interference
-     * ratio (SSSINR) for the number of 5G NR signal bars. If multiple measures are set bit, the
-     * parameter whose value is smallest is used to indicate the signal bar.
+     * ratio (SSSINR) for the number of 5G NR signal bars and signal criteria reporting enabling.
+     *
+     * <p> If a measure is not set, signal criteria reporting from modem will not be triggered and
+     * not be used for calculating signal level. If multiple measures are set bit, the parameter
+     * whose value is smallest is used to indicate the signal level.
      *
      *  SSRSRP = 1 << 0,
      *  SSRSRQ = 1 << 1,
      *  SSSINR = 1 << 2,
      *
+     *  The value of this key must be bitwise OR of {@link CellSignalStrengthNr#USE_SSRSRP},
+     *  {@link CellSignalStrengthNr#USE_SSRSRQ}, {@link CellSignalStrengthNr#USE_SSSINR}.
+     *
+     * For example, if both SSRSRP and SSSINR are used, the value of key is 5 (1 << 0 | 1 << 2).
+     * If the key is invalid or not configured, a default value (SSRSRP = 1 << 0) will apply.
+     *
      *  Reference: 3GPP TS 38.215,
      *             3GPP TS 38.133 10.1.16.1
+     *
+     * @hide
      */
     public static final String KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT =
             "parameters_use_for_5g_nr_signal_bar_int";
@@ -3436,6 +3460,7 @@
         sDefaults.putBoolean(KEY_CALL_FORWARDING_WHEN_UNREACHABLE_SUPPORTED_BOOL, true);
         sDefaults.putBoolean(KEY_ADDITIONAL_SETTINGS_CALLER_ID_VISIBILITY_BOOL, true);
         sDefaults.putBoolean(KEY_ADDITIONAL_SETTINGS_CALL_WAITING_VISIBILITY_BOOL, true);
+        sDefaults.putBoolean(KEY_DISABLE_SUPPLEMENTARY_SERVICES_IN_AIRPLANE_MODE_BOOL, false);
         sDefaults.putBoolean(KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL, false);
         sDefaults.putBoolean(KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL, false);
         sDefaults.putBoolean(KEY_OPERATOR_SELECTION_EXPAND_BOOL, true);
@@ -3523,7 +3548,7 @@
         sDefaults.putInt(KEY_IMS_DTMF_TONE_DELAY_INT, 0);
         sDefaults.putInt(KEY_CDMA_DTMF_TONE_DELAY_INT, 100);
         sDefaults.putBoolean(KEY_CALL_FORWARDING_MAP_NON_NUMBER_TO_VOICEMAIL_BOOL, false);
-        sDefaults.putBoolean(KEY_IGNORE_RTT_MODE_SETTING_BOOL, false);
+        sDefaults.putBoolean(KEY_IGNORE_RTT_MODE_SETTING_BOOL, true);
         sDefaults.putInt(KEY_CDMA_3WAYCALL_FLASH_DELAY_INT , 0);
         sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true);
         sDefaults.putBoolean(KEY_SUPPORT_IMS_CONFERENCE_CALL_BOOL, true);
@@ -3734,6 +3759,32 @@
                         -95, /* SIGNAL_STRENGTH_GOOD */
                         -85  /* SIGNAL_STRENGTH_GREAT */
                 });
+        sDefaults.putIntArray(KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY,
+                // Boundaries: [-140 dB, -44 dB]
+                new int[] {
+                    -125, /* SIGNAL_STRENGTH_POOR */
+                    -115, /* SIGNAL_STRENGTH_MODERATE */
+                    -105, /* SIGNAL_STRENGTH_GOOD */
+                    -95,  /* SIGNAL_STRENGTH_GREAT */
+                });
+        sDefaults.putIntArray(KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY,
+                // Boundaries: [-20 dB, -3 dB]
+                new int[] {
+                    -14, /* SIGNAL_STRENGTH_POOR */
+                    -12, /* SIGNAL_STRENGTH_MODERATE */
+                    -10, /* SIGNAL_STRENGTH_GOOD */
+                    -8  /* SIGNAL_STRENGTH_GREAT */
+                });
+        sDefaults.putIntArray(KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY,
+                // Boundaries: [-23 dB, 40 dB]
+                new int[] {
+                    -8, /* SIGNAL_STRENGTH_POOR */
+                    0, /* SIGNAL_STRENGTH_MODERATE */
+                    8, /* SIGNAL_STRENGTH_GOOD */
+                    16  /* SIGNAL_STRENGTH_GREAT */
+                });
+        sDefaults.putInt(KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT,
+                CellSignalStrengthNr.USE_SSRSRP);
         sDefaults.putString(KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING, "rssi");
         sDefaults.putBoolean(KEY_CONFIG_SHOW_ORIG_DIAL_STRING_FOR_CDMA_BOOL, false);
         sDefaults.putBoolean(KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL, false);
@@ -3862,6 +3913,34 @@
     @SystemApi
     @TestApi
     public void overrideConfig(int subscriptionId, @Nullable PersistableBundle overrideValues) {
+        overrideConfig(subscriptionId, overrideValues, false);
+    }
+
+    /**
+     * Overrides the carrier config of the provided subscription ID with the provided values.
+     *
+     * Any further queries to carrier config from any process will return the overridden values
+     * after this method returns. The overrides are effective until the user passes in {@code null}
+     * for {@code overrideValues}. This removes all previous overrides and sets the carrier config
+     * back to production values.
+     *
+     * The overrides is stored persistently and will survive a reboot if {@code persistent} is true.
+     *
+     * May throw an {@link IllegalArgumentException} if {@code overrideValues} contains invalid
+     * values for the specified config keys.
+     *
+     * NOTE: This API is meant for testing purposes only.
+     *
+     * @param subscriptionId The subscription ID for which the override should be done.
+     * @param overrideValues Key-value pairs of the values that are to be overridden. If set to
+     *                       {@code null}, this will remove all previous overrides and set the
+     *                       carrier configuration back to production values.
+     * @param persistent     Determines whether the override should be persistent.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    public void overrideConfig(int subscriptionId, @Nullable PersistableBundle overrideValues,
+            boolean persistent) {
         try {
             ICarrierConfigLoader loader = getICarrierConfigLoader();
             if (loader == null) {
@@ -3869,7 +3948,7 @@
                         + " ICarrierConfigLoader is null");
                 return;
             }
-            loader.overrideConfig(subscriptionId, overrideValues);
+            loader.overrideConfig(subscriptionId, overrideValues, persistent);
         } catch (RemoteException ex) {
             Rlog.e(TAG, "Error setting config for subId " + subscriptionId + ": "
                     + ex.toString());
diff --git a/telephony/java/android/telephony/CellSignalStrength.java b/telephony/java/android/telephony/CellSignalStrength.java
index e65b048ec..cb8fdf0 100644
--- a/telephony/java/android/telephony/CellSignalStrength.java
+++ b/telephony/java/android/telephony/CellSignalStrength.java
@@ -46,11 +46,6 @@
     protected static final int NUM_SIGNAL_STRENGTH_THRESHOLDS = NUM_SIGNAL_STRENGTH_BINS - 1;
 
     /** @hide */
-    public static final String[] SIGNAL_STRENGTH_NAMES = {
-        "none", "poor", "moderate", "good", "great"
-    };
-
-    /** @hide */
     protected CellSignalStrength() {
     }
 
@@ -157,4 +152,12 @@
         if ((value < rangeMin || value > rangeMax) && value != special) return CellInfo.UNAVAILABLE;
         return value;
     }
+
+    /**
+     * Returns the number of signal strength levels.
+     * @return Number of signal strength levels, enforced to be 5
+     */
+    public static final int getNumSignalStrengthLevels() {
+        return NUM_SIGNAL_STRENGTH_BINS;
+    }
 }
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index f9b7f6d..f31fafe 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -16,11 +16,15 @@
 
 package android.telephony;
 
+import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.PersistableBundle;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
 import java.util.Objects;
 
 /**
@@ -36,13 +40,67 @@
 
     private static final String TAG = "CellSignalStrengthNr";
 
+    // Lifted from Default carrier configs and max range of SSRSRP
+    // Boundaries: [-140 dB, -44 dB]
+    private int[] mSsRsrpThresholds = new int[] {
+            -125, /* SIGNAL_STRENGTH_POOR */
+            -115, /* SIGNAL_STRENGTH_MODERATE */
+            -105, /* SIGNAL_STRENGTH_GOOD */
+            -95,  /* SIGNAL_STRENGTH_GREAT */
+    };
+
+    // Lifted from Default carrier configs and max range of SSRSRQ
+    // Boundaries: [-20 dB, -3 dB]
+    private int[] mSsRsrqThresholds = new int[] {
+            -14, /* SIGNAL_STRENGTH_POOR */
+            -12, /* SIGNAL_STRENGTH_MODERATE */
+            -10, /* SIGNAL_STRENGTH_GOOD */
+            -8  /* SIGNAL_STRENGTH_GREAT */
+    };
+
+    // Lifted from Default carrier configs and max range of SSSINR
+    // Boundaries: [-23 dB, 40 dB]
+    private int[] mSsSinrThresholds = new int[] {
+            -8, /* SIGNAL_STRENGTH_POOR */
+            0, /* SIGNAL_STRENGTH_MODERATE */
+            8, /* SIGNAL_STRENGTH_GOOD */
+            16  /* SIGNAL_STRENGTH_GREAT */
+    };
+
     /**
-     * These threshold values are copied from LTE.
-     * TODO: make it configurable via CarrierConfig.
+     * Indicates SSRSRP is considered for {@link #getLevel()} and reporting from modem.
+     *
+     * @hide
      */
-    private static final int SIGNAL_GREAT_THRESHOLD = -95;
-    private static final int SIGNAL_GOOD_THRESHOLD = -105;
-    private static final int SIGNAL_MODERATE_THRESHOLD = -115;
+    public static final int USE_SSRSRP = 1 << 0;
+    /**
+     * Indicates SSRSRQ is considered for {@link #getLevel()} and reporting from modem.
+     *
+     * @hide
+     */
+    public static final int USE_SSRSRQ = 1 << 1;
+    /**
+     * Indicates SSSINR is considered for {@link #getLevel()} and reporting from modem.
+     *
+     * @hide
+     */
+    public static final int USE_SSSINR = 1 << 2;
+
+    /**
+     * Bit-field integer to determine whether to use SS reference signal received power (SSRSRP),
+     * SS reference signal received quality (SSRSRQ), or/and SS signal-to-noise and interference
+     * ratio (SSSINR) for the number of 5G NR signal bars. If multiple measures are set bit, the
+     * parameter whose value is smallest is used to indicate the signal bar.
+     *
+     * @hide
+     */
+    @IntDef(flag = true, prefix = { "USE_" }, value = {
+        USE_SSRSRP,
+        USE_SSRSRQ,
+        USE_SSSINR
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SignalLevelAndReportCriteriaSource {}
 
     private int mCsiRsrp;
     private int mCsiRsrq;
@@ -52,6 +110,21 @@
     private int mSsSinr;
     private int mLevel;
 
+    /**
+     * Bit-field integer to determine whether to use SS reference signal received power (SSRSRP),
+     * SS reference signal received quality (SSRSRQ), or/and SS signal-to-noise and interference
+     * ratio (SSSINR) for the number of 5G NR signal bars. If multiple measures are set bit, the
+     * parameter whose value is smallest is used to indicate the signal bar.
+     *
+     *  SSRSRP = 1 << 0,
+     *  SSRSRQ = 1 << 1,
+     *  SSSINR = 1 << 2,
+     *
+     * For example, if both SSRSRP and SSSINR are used, the value of key is 5 (1 << 0 | 1 << 2).
+     * If the key is invalid or not configured, a default value (SSRSRP = 1 << 0) will apply.
+     */
+    private int mParametersUseForLevel;
+
     /** @hide */
     public CellSignalStrengthNr() {
         setDefaultValues();
@@ -182,6 +255,7 @@
         mSsRsrq = CellInfo.UNAVAILABLE;
         mSsSinr = CellInfo.UNAVAILABLE;
         mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        mParametersUseForLevel = USE_SSRSRP;
     }
 
     /** {@inheritDoc} */
@@ -191,20 +265,83 @@
         return mLevel;
     }
 
+    /**
+     * Checks if the given parameter type is considered to use for {@link #getLevel()}.
+     *
+     * Note: if multiple parameter types are considered, the smaller level for one of the
+     * parameters would be returned by {@link #getLevel()}
+     *
+     * @param parameterType bitwise OR of {@link #USE_SSRSRP}, {@link #USE_SSRSRQ},
+     *         {@link #USE_SSSINR}
+     * @return {@code true} if the level is calculated based on the given parameter type;
+     *      {@code false} otherwise.
+     *
+     */
+    private boolean isLevelForParameter(@SignalLevelAndReportCriteriaSource int parameterType) {
+        return (parameterType & mParametersUseForLevel) == parameterType;
+    }
+
     /** @hide */
     @Override
     public void updateLevel(PersistableBundle cc, ServiceState ss) {
-        if (mSsRsrp == CellInfo.UNAVAILABLE) {
-            mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-        } else if (mSsRsrp >= SIGNAL_GREAT_THRESHOLD) {
-            mLevel = SIGNAL_STRENGTH_GREAT;
-        } else if (mSsRsrp >= SIGNAL_GOOD_THRESHOLD) {
-            mLevel = SIGNAL_STRENGTH_GOOD;
-        } else if (mSsRsrp >= SIGNAL_MODERATE_THRESHOLD) {
-            mLevel = SIGNAL_STRENGTH_MODERATE;
+        if (cc == null) {
+            mParametersUseForLevel = USE_SSRSRP;
         } else {
-            mLevel = SIGNAL_STRENGTH_POOR;
+            mParametersUseForLevel = cc.getInt(
+                    CarrierConfigManager.KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT, USE_SSRSRP);
+            Rlog.i(TAG, "Using SSRSRP for Level.");
+            mSsRsrpThresholds = cc.getIntArray(
+                    CarrierConfigManager.KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY);
+            Rlog.i(TAG, "Applying 5G NR SSRSRP Thresholds: " + Arrays.toString(mSsRsrpThresholds));
+            mSsRsrqThresholds = cc.getIntArray(
+                    CarrierConfigManager.KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY);
+            Rlog.i(TAG, "Applying 5G NR SSRSRQ Thresholds: " + Arrays.toString(mSsRsrqThresholds));
+            mSsSinrThresholds = cc.getIntArray(
+                    CarrierConfigManager.KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY);
+            Rlog.i(TAG, "Applying 5G NR SSSINR Thresholds: " + Arrays.toString(mSsSinrThresholds));
         }
+        int ssRsrpLevel = SignalStrength.INVALID;
+        int ssRsrqLevel = SignalStrength.INVALID;
+        int ssSinrLevel = SignalStrength.INVALID;
+        if (isLevelForParameter(USE_SSRSRP)) {
+            ssRsrpLevel = updateLevelWithMeasure(mSsRsrp, mSsRsrpThresholds);
+            Rlog.i(TAG, "Updated 5G NR SSRSRP Level: " + ssRsrpLevel);
+        }
+        if (isLevelForParameter(USE_SSRSRQ)) {
+            ssRsrqLevel = updateLevelWithMeasure(mSsRsrq, mSsRsrqThresholds);
+            Rlog.i(TAG, "Updated 5G NR SSRSRQ Level: " + ssRsrqLevel);
+        }
+        if (isLevelForParameter(USE_SSSINR)) {
+            ssSinrLevel = updateLevelWithMeasure(mSsSinr, mSsSinrThresholds);
+            Rlog.i(TAG, "Updated 5G NR SSSINR Level: " + ssSinrLevel);
+        }
+        // Apply the smaller value among three levels of three measures.
+        mLevel = Math.min(Math.min(ssRsrpLevel, ssRsrqLevel), ssSinrLevel);
+    }
+
+    /**
+     * Update level with corresponding measure and thresholds.
+     *
+     * @param measure corresponding signal measure
+     * @param thresholds corresponding signal thresholds
+     * @return level of the signal strength
+     */
+    private int updateLevelWithMeasure(int measure, int[] thresholds) {
+        int level;
+        if (measure == CellInfo.UNAVAILABLE) {
+            level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        } else if (measure > thresholds[3]) {
+            level = SIGNAL_STRENGTH_GREAT;
+        } else if (measure > thresholds[2]) {
+            level = SIGNAL_STRENGTH_GOOD;
+        } else if (measure > thresholds[1]) {
+            level = SIGNAL_STRENGTH_MODERATE;
+        }  else if (measure > thresholds[0]) {
+            level = SIGNAL_STRENGTH_POOR;
+        } else {
+            level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        }
+        return level;
     }
 
     /**
@@ -247,6 +384,7 @@
         mSsRsrq = s.mSsRsrq;
         mSsSinr = s.mSsSinr;
         mLevel = s.mLevel;
+        mParametersUseForLevel = s.mParametersUseForLevel;
     }
 
     /** @hide */
@@ -290,6 +428,7 @@
                 .append(" ssRsrq = " + mSsRsrq)
                 .append(" ssSinr = " + mSsSinr)
                 .append(" level = " + mLevel)
+                .append(" parametersUseForLevel = " + mParametersUseForLevel)
                 .append(" }")
                 .toString();
     }
diff --git a/telephony/java/android/telephony/LocationAccessPolicy.java b/telephony/java/android/telephony/LocationAccessPolicy.java
index 79b3756..fe273b2 100644
--- a/telephony/java/android/telephony/LocationAccessPolicy.java
+++ b/telephony/java/android/telephony/LocationAccessPolicy.java
@@ -193,6 +193,17 @@
         }
     }
 
+    private static String getAppOpsString(String manifestPermission) {
+        switch (manifestPermission) {
+            case Manifest.permission.ACCESS_FINE_LOCATION:
+                return AppOpsManager.OPSTR_FINE_LOCATION;
+            case Manifest.permission.ACCESS_COARSE_LOCATION:
+                return AppOpsManager.OPSTR_COARSE_LOCATION;
+            default:
+                return null;
+        }
+    }
+
     private static LocationPermissionResult checkAppLocationPermissionHelper(Context context,
             LocationPermissionQuery query, String permissionToCheck) {
         String locationTypeForLog =
@@ -206,8 +217,8 @@
         if (hasManifestPermission) {
             // Only check the app op if the app has the permission.
             int appOpMode = context.getSystemService(AppOpsManager.class)
-                    .noteOpNoThrow(AppOpsManager.permissionToOpCode(permissionToCheck),
-                            query.callingUid, query.callingPackage, query.callingFeatureId, null);
+                    .noteOpNoThrow(getAppOpsString(permissionToCheck), query.callingUid,
+                            query.callingPackage, query.callingFeatureId, null);
             if (appOpMode == AppOpsManager.MODE_ALLOWED) {
                 // If the app did everything right, return without logging.
                 return LocationPermissionResult.ALLOWED;
diff --git a/telephony/java/android/telephony/PhoneCapability.java b/telephony/java/android/telephony/PhoneCapability.java
index 17b7963f..8a75831 100644
--- a/telephony/java/android/telephony/PhoneCapability.java
+++ b/telephony/java/android/telephony/PhoneCapability.java
@@ -16,6 +16,8 @@
 
 package android.telephony;
 
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -27,12 +29,13 @@
 /**
  * Define capability of a modem group. That is, the capabilities
  * are shared between those modems defined by list of modem IDs.
- * @hide
  */
-public class PhoneCapability implements Parcelable {
+public final class PhoneCapability implements Parcelable {
     // Hardcoded default DSDS capability.
+    /** @hide */
     public static final PhoneCapability DEFAULT_DSDS_CAPABILITY;
     // Hardcoded default Single SIM single standby capability.
+    /** @hide */
     public static final PhoneCapability DEFAULT_SSSS_CAPABILITY;
 
     static {
@@ -48,13 +51,18 @@
         logicalModemList.add(modemInfo1);
         DEFAULT_SSSS_CAPABILITY = new PhoneCapability(1, 1, 0, logicalModemList, false);
     }
-
+    /** @hide */
     public final int maxActiveVoiceCalls;
+    /** @hide */
     public final int maxActiveData;
+    /** @hide */
     public final int max5G;
+    /** @hide */
     public final boolean validationBeforeSwitchSupported;
+    /** @hide */
     public final List<ModemInfo> logicalModemList;
 
+    /** @hide */
     public PhoneCapability(int maxActiveVoiceCalls, int maxActiveData, int max5G,
             List<ModemInfo> logicalModemList, boolean validationBeforeSwitchSupported) {
         this.maxActiveVoiceCalls = maxActiveVoiceCalls;
@@ -116,7 +124,7 @@
     /**
      * {@link Parcelable#writeToParcel}
      */
-    public void writeToParcel(Parcel dest, @Parcelable.WriteFlags int flags) {
+    public void writeToParcel(@NonNull Parcel dest, @Parcelable.WriteFlags int flags) {
         dest.writeInt(maxActiveVoiceCalls);
         dest.writeInt(maxActiveData);
         dest.writeInt(max5G);
diff --git a/telephony/java/android/telephony/RadioAccessSpecifier.java b/telephony/java/android/telephony/RadioAccessSpecifier.java
index 690e44a..a403095 100644
--- a/telephony/java/android/telephony/RadioAccessSpecifier.java
+++ b/telephony/java/android/telephony/RadioAccessSpecifier.java
@@ -97,8 +97,9 @@
      * Returns the frequency bands that need to be scanned.
      *
      * The returned value is defined in either of {@link AccessNetworkConstants.GeranBand},
-     * {@link AccessNetworkConstants.UtranBand} and {@link AccessNetworkConstants.EutranBand}, and
-     * it depends on the returned value of {@link #getRadioAccessNetwork()}.
+     * {@link AccessNetworkConstants.UtranBand}, {@link AccessNetworkConstants.EutranBand},
+     * and {@link AccessNetworkConstants.NgranBands}, and it depends on
+     * the returned value of {@link #getRadioAccessNetwork()}.
      */
     public int[] getBands() {
         return mBands == null ? null : mBands.clone();
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 9ace86c..d2c8517 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -278,12 +278,9 @@
      */
     public static final int UNKNOWN_ID = -1;
 
-    private String mVoiceOperatorAlphaLong;
-    private String mVoiceOperatorAlphaShort;
-    private String mVoiceOperatorNumeric;
-    private String mDataOperatorAlphaLong;
-    private String mDataOperatorAlphaShort;
-    private String mDataOperatorNumeric;
+    private String mOperatorAlphaLong;
+    private String mOperatorAlphaShort;
+    private String mOperatorNumeric;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private boolean mIsManualNetworkSelection;
 
@@ -379,12 +376,9 @@
     protected void copyFrom(ServiceState s) {
         mVoiceRegState = s.mVoiceRegState;
         mDataRegState = s.mDataRegState;
-        mVoiceOperatorAlphaLong = s.mVoiceOperatorAlphaLong;
-        mVoiceOperatorAlphaShort = s.mVoiceOperatorAlphaShort;
-        mVoiceOperatorNumeric = s.mVoiceOperatorNumeric;
-        mDataOperatorAlphaLong = s.mDataOperatorAlphaLong;
-        mDataOperatorAlphaShort = s.mDataOperatorAlphaShort;
-        mDataOperatorNumeric = s.mDataOperatorNumeric;
+        mOperatorAlphaLong = s.mOperatorAlphaLong;
+        mOperatorAlphaShort = s.mOperatorAlphaShort;
+        mOperatorNumeric = s.mOperatorNumeric;
         mIsManualNetworkSelection = s.mIsManualNetworkSelection;
         mCssIndicator = s.mCssIndicator;
         mNetworkId = s.mNetworkId;
@@ -418,12 +412,9 @@
     public ServiceState(Parcel in) {
         mVoiceRegState = in.readInt();
         mDataRegState = in.readInt();
-        mVoiceOperatorAlphaLong = in.readString();
-        mVoiceOperatorAlphaShort = in.readString();
-        mVoiceOperatorNumeric = in.readString();
-        mDataOperatorAlphaLong = in.readString();
-        mDataOperatorAlphaShort = in.readString();
-        mDataOperatorNumeric = in.readString();
+        mOperatorAlphaLong = in.readString();
+        mOperatorAlphaShort = in.readString();
+        mOperatorNumeric = in.readString();
         mIsManualNetworkSelection = in.readInt() != 0;
         mCssIndicator = (in.readInt() != 0);
         mNetworkId = in.readInt();
@@ -448,12 +439,9 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mVoiceRegState);
         out.writeInt(mDataRegState);
-        out.writeString(mVoiceOperatorAlphaLong);
-        out.writeString(mVoiceOperatorAlphaShort);
-        out.writeString(mVoiceOperatorNumeric);
-        out.writeString(mDataOperatorAlphaLong);
-        out.writeString(mDataOperatorAlphaShort);
-        out.writeString(mDataOperatorNumeric);
+        out.writeString(mOperatorAlphaLong);
+        out.writeString(mOperatorAlphaShort);
+        out.writeString(mOperatorNumeric);
         out.writeInt(mIsManualNetworkSelection ? 1 : 0);
         out.writeInt(mCssIndicator ? 1 : 0);
         out.writeInt(mNetworkId);
@@ -691,7 +679,7 @@
      * @return long name of operator, null if unregistered or unknown
      */
     public String getOperatorAlphaLong() {
-        return mVoiceOperatorAlphaLong;
+        return mOperatorAlphaLong;
     }
 
     /**
@@ -699,18 +687,10 @@
      * @return long name of operator
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@link #getOperatorAlphaLong} instead.")
     public String getVoiceOperatorAlphaLong() {
-        return mVoiceOperatorAlphaLong;
-    }
-
-    /**
-     * Get current registered data network operator name in long alphanumeric format.
-     * @return long name of voice operator
-     * @hide
-     */
-    public String getDataOperatorAlphaLong() {
-        return mDataOperatorAlphaLong;
+        return mOperatorAlphaLong;
     }
 
     /**
@@ -721,7 +701,7 @@
      * @return short name of operator, null if unregistered or unknown
      */
     public String getOperatorAlphaShort() {
-        return mVoiceOperatorAlphaShort;
+        return mOperatorAlphaShort;
     }
 
     /**
@@ -729,9 +709,10 @@
      * @return short name of operator, null if unregistered or unknown
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@link #getOperatorAlphaShort} instead.")
     public String getVoiceOperatorAlphaShort() {
-        return mVoiceOperatorAlphaShort;
+        return mOperatorAlphaShort;
     }
 
     /**
@@ -739,9 +720,10 @@
      * @return short name of operator, null if unregistered or unknown
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@link #getOperatorAlphaShort} instead.")
     public String getDataOperatorAlphaShort() {
-        return mDataOperatorAlphaShort;
+        return mOperatorAlphaShort;
     }
 
     /**
@@ -755,11 +737,11 @@
      * @hide
      */
     public String getOperatorAlpha() {
-        if (TextUtils.isEmpty(mVoiceOperatorAlphaLong)) {
-            return mVoiceOperatorAlphaShort;
+        if (TextUtils.isEmpty(mOperatorAlphaLong)) {
+            return mOperatorAlphaShort;
         }
 
-        return mVoiceOperatorAlphaLong;
+        return mOperatorAlphaLong;
     }
 
     /**
@@ -775,7 +757,7 @@
      * {@link com.android.internal.telephony.MccTable#countryCodeForMcc(int)}.
      */
     public String getOperatorNumeric() {
-        return mVoiceOperatorNumeric;
+        return mOperatorNumeric;
     }
 
     /**
@@ -785,7 +767,7 @@
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getVoiceOperatorNumeric() {
-        return mVoiceOperatorNumeric;
+        return mOperatorNumeric;
     }
 
     /**
@@ -793,9 +775,10 @@
      * @return numeric format of operator, null if unregistered or unknown
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "Use {@link #getOperatorNumeric} instead.")
     public String getDataOperatorNumeric() {
-        return mDataOperatorNumeric;
+        return mOperatorNumeric;
     }
 
     /**
@@ -815,12 +798,9 @@
                     mDataRegState,
                     mChannelNumber,
                     Arrays.hashCode(mCellBandwidths),
-                    mVoiceOperatorAlphaLong,
-                    mVoiceOperatorAlphaShort,
-                    mVoiceOperatorNumeric,
-                    mDataOperatorAlphaLong,
-                    mDataOperatorAlphaShort,
-                    mDataOperatorNumeric,
+                    mOperatorAlphaLong,
+                    mOperatorAlphaShort,
+                    mOperatorNumeric,
                     mIsManualNetworkSelection,
                     mCssIndicator,
                     mNetworkId,
@@ -850,12 +830,9 @@
                     && mIsManualNetworkSelection == s.mIsManualNetworkSelection
                     && mChannelNumber == s.mChannelNumber
                     && Arrays.equals(mCellBandwidths, s.mCellBandwidths)
-                    && equalsHandlesNulls(mVoiceOperatorAlphaLong, s.mVoiceOperatorAlphaLong)
-                    && equalsHandlesNulls(mVoiceOperatorAlphaShort, s.mVoiceOperatorAlphaShort)
-                    && equalsHandlesNulls(mVoiceOperatorNumeric, s.mVoiceOperatorNumeric)
-                    && equalsHandlesNulls(mDataOperatorAlphaLong, s.mDataOperatorAlphaLong)
-                    && equalsHandlesNulls(mDataOperatorAlphaShort, s.mDataOperatorAlphaShort)
-                    && equalsHandlesNulls(mDataOperatorNumeric, s.mDataOperatorNumeric)
+                    && equalsHandlesNulls(mOperatorAlphaLong, s.mOperatorAlphaLong)
+                    && equalsHandlesNulls(mOperatorAlphaShort, s.mOperatorAlphaShort)
+                    && equalsHandlesNulls(mOperatorNumeric, s.mOperatorNumeric)
                     && equalsHandlesNulls(mCssIndicator, s.mCssIndicator)
                     && equalsHandlesNulls(mNetworkId, s.mNetworkId)
                     && equalsHandlesNulls(mSystemId, s.mSystemId)
@@ -1007,10 +984,8 @@
                     .append(", mChannelNumber=").append(mChannelNumber)
                     .append(", duplexMode()=").append(getDuplexMode())
                     .append(", mCellBandwidths=").append(Arrays.toString(mCellBandwidths))
-                    .append(", mVoiceOperatorAlphaLong=").append(mVoiceOperatorAlphaLong)
-                    .append(", mVoiceOperatorAlphaShort=").append(mVoiceOperatorAlphaShort)
-                    .append(", mDataOperatorAlphaLong=").append(mDataOperatorAlphaLong)
-                    .append(", mDataOperatorAlphaShort=").append(mDataOperatorAlphaShort)
+                    .append(", mOperatorAlphaLong=").append(mOperatorAlphaLong)
+                    .append(", mOperatorAlphaShort=").append(mOperatorAlphaShort)
                     .append(", isManualNetworkSelection=").append(mIsManualNetworkSelection)
                     .append(mIsManualNetworkSelection ? "(manual)" : "(automatic)")
                     .append(", getRilVoiceRadioTechnology=").append(getRilVoiceRadioTechnology())
@@ -1040,12 +1015,9 @@
         mDataRegState = STATE_OUT_OF_SERVICE;
         mChannelNumber = -1;
         mCellBandwidths = new int[0];
-        mVoiceOperatorAlphaLong = null;
-        mVoiceOperatorAlphaShort = null;
-        mVoiceOperatorNumeric = null;
-        mDataOperatorAlphaLong = null;
-        mDataOperatorAlphaShort = null;
-        mDataOperatorNumeric = null;
+        mOperatorAlphaLong = null;
+        mOperatorAlphaShort = null;
+        mOperatorNumeric = null;
         mIsManualNetworkSelection = false;
         mCssIndicator = false;
         mNetworkId = -1;
@@ -1204,26 +1176,9 @@
     }
 
     public void setOperatorName(String longName, String shortName, String numeric) {
-        mVoiceOperatorAlphaLong = longName;
-        mVoiceOperatorAlphaShort = shortName;
-        mVoiceOperatorNumeric = numeric;
-        mDataOperatorAlphaLong = longName;
-        mDataOperatorAlphaShort = shortName;
-        mDataOperatorNumeric = numeric;
-    }
-
-    /** @hide */
-    public void setVoiceOperatorName(String longName, String shortName, String numeric) {
-        mVoiceOperatorAlphaLong = longName;
-        mVoiceOperatorAlphaShort = shortName;
-        mVoiceOperatorNumeric = numeric;
-    }
-
-    /** @hide */
-    public void setDataOperatorName(String longName, String shortName, String numeric) {
-        mDataOperatorAlphaLong = longName;
-        mDataOperatorAlphaShort = shortName;
-        mDataOperatorNumeric = numeric;
+        mOperatorAlphaLong = longName;
+        mOperatorAlphaShort = shortName;
+        mOperatorNumeric = numeric;
     }
 
     /**
@@ -1233,19 +1188,8 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public void setOperatorAlphaLong(String longName) {
-        mVoiceOperatorAlphaLong = longName;
-        mDataOperatorAlphaLong = longName;
-    }
-
-    /** @hide */
-    public void setVoiceOperatorAlphaLong(String longName) {
-        mVoiceOperatorAlphaLong = longName;
-    }
-
-    /** @hide */
-    public void setDataOperatorAlphaLong(String longName) {
-        mDataOperatorAlphaLong = longName;
+    public void setOperatorAlphaLong(@Nullable String longName) {
+        mOperatorAlphaLong = longName;
     }
 
     public void setIsManualSelection(boolean isManual) {
@@ -1293,12 +1237,12 @@
         m.putInt("dataRegState", mDataRegState);
         m.putInt("dataRoamingType", getDataRoamingType());
         m.putInt("voiceRoamingType", getVoiceRoamingType());
-        m.putString("operator-alpha-long", mVoiceOperatorAlphaLong);
-        m.putString("operator-alpha-short", mVoiceOperatorAlphaShort);
-        m.putString("operator-numeric", mVoiceOperatorNumeric);
-        m.putString("data-operator-alpha-long", mDataOperatorAlphaLong);
-        m.putString("data-operator-alpha-short", mDataOperatorAlphaShort);
-        m.putString("data-operator-numeric", mDataOperatorNumeric);
+        m.putString("operator-alpha-long", mOperatorAlphaLong);
+        m.putString("operator-alpha-short", mOperatorAlphaShort);
+        m.putString("operator-numeric", mOperatorNumeric);
+        m.putString("data-operator-alpha-long", mOperatorAlphaLong);
+        m.putString("data-operator-alpha-short", mOperatorAlphaShort);
+        m.putString("data-operator-numeric", mOperatorNumeric);
         m.putBoolean("manual", mIsManualNetworkSelection);
         m.putInt("radioTechnology", getRilVoiceRadioTechnology());
         m.putInt("dataRadioTechnology", getRadioTechnology());
@@ -1933,12 +1877,9 @@
         }
         if (!removeCoarseLocation) return state;
 
-        state.mDataOperatorAlphaLong = null;
-        state.mDataOperatorAlphaShort = null;
-        state.mDataOperatorNumeric = null;
-        state.mVoiceOperatorAlphaLong = null;
-        state.mVoiceOperatorAlphaShort = null;
-        state.mVoiceOperatorNumeric = null;
+        state.mOperatorAlphaLong = null;
+        state.mOperatorAlphaShort = null;
+        state.mOperatorNumeric = null;
 
         return state;
     }
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index 480c9d9..9aafc1b 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -60,12 +60,6 @@
     @UnsupportedAppUsage
     public static final int NUM_SIGNAL_STRENGTH_BINS = 5;
 
-    /** SIGNAL_STRENGTH_NAMES is currently used by BatteryStats, but to-be-removed soon. */
-    /** @hide */
-    public static final String[] SIGNAL_STRENGTH_NAMES = {
-        "none", "poor", "moderate", "good", "great"
-    };
-
     /**
      * Indicates the invalid measures of signal strength.
      *
diff --git a/telephony/java/android/telephony/SignalThresholdInfo.java b/telephony/java/android/telephony/SignalThresholdInfo.java
new file mode 100644
index 0000000..f6f6d75
--- /dev/null
+++ b/telephony/java/android/telephony/SignalThresholdInfo.java
@@ -0,0 +1,256 @@
+/*
+ * 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.telephony;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Defines the threshold value of the signal strength.
+ * @hide
+ */
+public class SignalThresholdInfo implements Parcelable {
+    /**
+     * Received Signal Strength Indication.
+     * Range: -113 dBm and -51 dBm
+     * Used RAN: GERAN, CDMA2000
+     * Reference: 3GPP TS 27.007 section 8.5.
+     */
+    public static final int SIGNAL_RSSI = 1;
+
+    /**
+     * Received Signal Code Power.
+     * Range: -120 dBm to -25 dBm;
+     * Used RAN: UTRAN
+     * Reference: 3GPP TS 25.123, section 9.1.1.1
+     */
+    public static final int SIGNAL_RSCP = 2;
+
+    /**
+     * Reference Signal Received Power.
+     * Range: -140 dBm to -44 dBm;
+     * Used RAN: EUTRAN
+     * Reference: 3GPP TS 36.133 9.1.4
+     */
+    public static final int SIGNAL_RSRP = 3;
+
+    /**
+     * Reference Signal Received Quality
+     * Range: -20 dB to -3 dB;
+     * Used RAN: EUTRAN
+     * Reference: 3GPP TS 36.133 9.1.7
+     */
+    public static final int SIGNAL_RSRQ = 4;
+
+    /**
+     * Reference Signal Signal to Noise Ratio
+     * Range: -20 dB to 30 dB;
+     * Used RAN: EUTRAN
+     */
+    public static final int SIGNAL_RSSNR = 5;
+
+    /**
+     * 5G SS reference signal received power.
+     * Range: -140 dBm to -44 dBm.
+     * Used RAN: NGRAN
+     * Reference: 3GPP TS 38.215.
+     */
+    public static final int SIGNAL_SSRSRP = 6;
+
+    /**
+     * 5G SS reference signal received quality.
+     * Range: -20 dB to -3 dB.
+     * Used RAN: NGRAN
+     * Reference: 3GPP TS 38.215.
+     */
+    public static final int SIGNAL_SSRSRQ = 7;
+
+    /**
+     * 5G SS signal-to-noise and interference ratio.
+     * Range: -23 dB to 40 dB
+     * Used RAN: NGRAN
+     * Reference: 3GPP TS 38.215 section 5.1.*, 3GPP TS 38.133 section 10.1.16.1.
+     */
+    public static final int SIGNAL_SSSINR = 8;
+
+    /** @hide */
+    @IntDef(prefix = { "SIGNAL_" }, value = {
+        SIGNAL_RSSI,
+        SIGNAL_RSCP,
+        SIGNAL_RSRP,
+        SIGNAL_RSRQ,
+        SIGNAL_RSSNR,
+        SIGNAL_SSRSRP,
+        SIGNAL_SSRSRQ,
+        SIGNAL_SSSINR
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SignalMeasurementType {}
+
+    @SignalMeasurementType
+    private int mSignalMeasurement;
+
+    /**
+     * A hysteresis time in milliseconds to prevent flapping.
+     * A value of 0 disables hysteresis
+     */
+    private int mHysteresisMs;
+
+    /**
+     * An interval in dB defining the required magnitude change between reports.
+     * hysteresisDb must be smaller than the smallest threshold delta.
+     * An interval value of 0 disables hysteresis.
+     */
+    private int mHysteresisDb;
+
+    /**
+     * List of threshold values.
+     * Range and unit must reference specific SignalMeasurementType
+     * The threshold values for which to apply criteria.
+     * A vector size of 0 disables the use of thresholds for reporting.
+     */
+    private int[] mThresholds = null;
+
+    /**
+     * {@code true} means modem must trigger the report based on the criteria;
+     * {@code false} means modem must not trigger the report based on the criteria.
+     */
+    private boolean mIsEnabled = true;
+
+    /**
+     * Indicates the hysteresisMs is disabled.
+     */
+    public static final int HYSTERESIS_MS_DISABLED = 0;
+
+    /**
+     * Indicates the hysteresisDb is disabled.
+     */
+    public static final int HYSTERESIS_DB_DISABLED = 0;
+
+    /**
+     * Constructor
+     *
+     * @param signalMeasurement Signal Measurement Type
+     * @param hysteresisMs hysteresisMs
+     * @param hysteresisDb hysteresisDb
+     * @param thresholds threshold value
+     * @param isEnabled isEnabled
+     */
+    public SignalThresholdInfo(@SignalMeasurementType int signalMeasurement,
+            int hysteresisMs, int hysteresisDb, @NonNull int [] thresholds, boolean isEnabled) {
+        mSignalMeasurement = signalMeasurement;
+        mHysteresisMs = hysteresisMs < 0 ? HYSTERESIS_MS_DISABLED : hysteresisMs;
+        mHysteresisDb = hysteresisDb < 0 ? HYSTERESIS_DB_DISABLED : hysteresisDb;
+        mThresholds = thresholds == null ? null : thresholds.clone();
+        mIsEnabled = isEnabled;
+    }
+
+    public @SignalMeasurementType int getSignalMeasurement() {
+        return mSignalMeasurement;
+    }
+
+    public int getHysteresisMs() {
+        return mHysteresisMs;
+    }
+
+    public int getHysteresisDb() {
+        return mHysteresisDb;
+    }
+
+    public boolean isEnabled() {
+        return mIsEnabled;
+    }
+
+    public int[] getThresholds() {
+        return mThresholds == null ? null : mThresholds.clone();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mSignalMeasurement);
+        out.writeInt(mHysteresisMs);
+        out.writeInt(mHysteresisDb);
+        out.writeIntArray(mThresholds);
+        out.writeBoolean(mIsEnabled);
+    }
+
+    private SignalThresholdInfo(Parcel in) {
+        mSignalMeasurement = in.readInt();
+        mHysteresisMs = in.readInt();
+        mHysteresisDb = in.readInt();
+        mThresholds = in.createIntArray();
+        mIsEnabled = in.readBoolean();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (!(o instanceof SignalThresholdInfo)) {
+            return false;
+        }
+
+        SignalThresholdInfo other = (SignalThresholdInfo) o;
+        return mSignalMeasurement == other.mSignalMeasurement
+                && mHysteresisMs == other.mHysteresisMs
+                && mHysteresisDb == other.mHysteresisDb
+                && Arrays.equals(mThresholds, other.mThresholds)
+                && mIsEnabled == other.mIsEnabled;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(
+                mSignalMeasurement, mHysteresisMs, mHysteresisDb, mThresholds, mIsEnabled);
+    }
+
+    public static final @NonNull Parcelable.Creator<SignalThresholdInfo> CREATOR =
+            new Parcelable.Creator<SignalThresholdInfo>() {
+                @Override
+                public SignalThresholdInfo createFromParcel(Parcel in) {
+                    return new SignalThresholdInfo(in);
+                }
+
+                @Override
+                public SignalThresholdInfo[] newArray(int size) {
+                    return new SignalThresholdInfo[size];
+                }
+            };
+
+    @Override
+    public String toString() {
+        return new StringBuilder("SignalThresholdInfo{")
+            .append("mSignalMeasurement=").append(mSignalMeasurement)
+            .append("mHysteresisMs=").append(mSignalMeasurement)
+            .append("mHysteresisDb=").append(mHysteresisDb)
+            .append("mThresholds=").append(Arrays.toString(mThresholds))
+            .append("mIsEnabled=").append(mIsEnabled)
+            .append("}").toString();
+    }
+}
diff --git a/telephony/java/android/telephony/SmsCbMessage.java b/telephony/java/android/telephony/SmsCbMessage.java
index fad70d2..045d1eb 100644
--- a/telephony/java/android/telephony/SmsCbMessage.java
+++ b/telephony/java/android/telephony/SmsCbMessage.java
@@ -29,6 +29,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -407,13 +408,17 @@
     }
 
     /**
-     * Get the warning area coordinates information represent by polygons and circles.
-     * @return a list of geometries, {@link Nullable} means there is no coordinate information
-     * associated to this message.
+     * Get the warning area coordinates information represented by polygons and circles.
+     * @return a list of geometries, or an empty list if there is no coordinate information
+     * associated with this message.
      * @hide
      */
-    @Nullable
+    @SystemApi
+    @NonNull
     public List<Geometry> getGeometries() {
+        if (mGeometries == null) {
+            return new ArrayList<>();
+        }
         return mGeometries;
     }
 
@@ -528,7 +533,8 @@
                 + ", priority=" + mPriority
                 + (mEtwsWarningInfo != null ? (", " + mEtwsWarningInfo.toString()) : "")
                 + (mCmasWarningInfo != null ? (", " + mCmasWarningInfo.toString()) : "")
-                + ", maximumWaitingTime = " + mMaximumWaitTimeSec
+                + ", maximumWaitingTime=" + mMaximumWaitTimeSec
+                + ", received time=" + mReceivedTimeMillis
                 + ", slotIndex = " + mSlotIndex
                 + ", geo=" + (mGeometries != null
                 ? CbGeoUtils.encodeGeometriesToString(mGeometries) : "null")
@@ -720,6 +726,6 @@
      * @return {@code True} if this message needs geo-fencing check.
      */
     public boolean needGeoFencingCheck() {
-        return mMaximumWaitTimeSec > 0 && mGeometries != null;
+        return mMaximumWaitTimeSec > 0 && mGeometries != null && !mGeometries.isEmpty();
     }
 }
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 9eff809..ebb5175 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -89,8 +89,8 @@
     private int mCarrierId;
 
     /**
-     * The source of the name, NAME_SOURCE_DEFAULT_SOURCE, NAME_SOURCE_SIM_SOURCE or
-     * NAME_SOURCE_USER_INPUT.
+     * The source of the name, NAME_SOURCE_DEFAULT_SOURCE, NAME_SOURCE_SIM_SPN,
+     * NAME_SOURCE_SIM_PNN, or NAME_SOURCE_USER_INPUT.
      */
     private int mNameSource;
 
@@ -334,7 +334,7 @@
     }
 
     /**
-     * @return the source of the name, eg NAME_SOURCE_DEFAULT_SOURCE, NAME_SOURCE_SIM_SOURCE or
+     * @return the source of the name, eg NAME_SOURCE_DEFAULT_SOURCE, NAME_SOURCE_SIM_SPN or
      * NAME_SOURCE_USER_INPUT.
      * @hide
      */
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index e9ce7e3..cf705f4 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -54,6 +54,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.provider.Telephony.SimInfo;
 import android.telephony.euicc.EuiccManager;
 import android.telephony.ims.ImsMmTelManager;
 import android.util.DisplayMetrics;
@@ -129,7 +130,7 @@
 
     /** @hide */
     @UnsupportedAppUsage
-    public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
+    public static final Uri CONTENT_URI = SimInfo.CONTENT_URI;
 
     /**
      * Generates a content {@link Uri} used to receive updates on simInfo change
@@ -400,19 +401,19 @@
     public static final String NAME_SOURCE = "name_source";
 
     /**
-     * The name_source is the default
+     * The name_source is the default, which is from the carrier id.
      * @hide
      */
     public static final int NAME_SOURCE_DEFAULT_SOURCE = 0;
 
     /**
-     * The name_source is from the SIM
+     * The name_source is from SIM EF_SPN.
      * @hide
      */
-    public static final int NAME_SOURCE_SIM_SOURCE = 1;
+    public static final int NAME_SOURCE_SIM_SPN = 1;
 
     /**
-     * The name_source is from the user
+     * The name_source is from user input
      * @hide
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
@@ -425,6 +426,24 @@
     public static final int NAME_SOURCE_CARRIER = 3;
 
     /**
+     * The name_source is from SIM EF_PNN.
+     * @hide
+     */
+    public static final int NAME_SOURCE_SIM_PNN = 4;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"NAME_SOURCE_"},
+            value = {
+                    NAME_SOURCE_DEFAULT_SOURCE,
+                    NAME_SOURCE_SIM_SPN,
+                    NAME_SOURCE_USER_INPUT,
+                    NAME_SOURCE_CARRIER,
+                    NAME_SOURCE_SIM_PNN
+            })
+    public @interface SimDisplayNameSource {}
+
+    /**
      * TelephonyProvider column name for the color of a SIM.
      * <P>Type: INTEGER (int)</P>
      */
@@ -1667,13 +1686,12 @@
      * Set display name by simInfo index with name source
      * @param displayName the display name of SIM card
      * @param subId the unique SubscriptionInfo index in database
-     * @param nameSource 0: NAME_SOURCE_DEFAULT_SOURCE, 1: NAME_SOURCE_SIM_SOURCE,
-     *                   2: NAME_SOURCE_USER_INPUT
+     * @param nameSource SIM display name source
      * @return the number of records updated or < 0 if invalid subId
      * @hide
      */
     @UnsupportedAppUsage
-    public int setDisplayName(String displayName, int subId, int nameSource) {
+    public int setDisplayName(String displayName, int subId, @SimDisplayNameSource int nameSource) {
         if (VDBG) {
             logd("[setDisplayName]+  displayName:" + displayName + " subId:" + subId
                     + " nameSource:" + nameSource);
@@ -2713,9 +2731,14 @@
                     if (executor == null || callback == null) {
                         return;
                     }
-                    Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
-                        callback.accept(result);
-                    }));
+                    final long identity = Binder.clearCallingIdentity();
+                    try {
+                        executor.execute(() -> {
+                            callback.accept(result);
+                        });
+                    } finally {
+                        Binder.restoreCallingIdentity(identity);
+                    }
                 }
             };
             iSub.setPreferredDataSubscriptionId(subId, needValidation, callbackStub);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 9f8a213..e3981f6 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -86,7 +86,6 @@
 
 import com.android.ims.internal.IImsServiceFeatureCallback;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telecom.ITelecomService;
 import com.android.internal.telephony.CellNetworkScanResult;
 import com.android.internal.telephony.INumberVerificationCallback;
 import com.android.internal.telephony.IOns;
@@ -4724,17 +4723,6 @@
     }
 
     /**
-     * Sim activation type: voice
-     * @hide
-     */
-    public static final int SIM_ACTIVATION_TYPE_VOICE = 0;
-    /**
-     * Sim activation type: data
-     * @hide
-     */
-    public static final int SIM_ACTIVATION_TYPE_DATA = 1;
-
-    /**
      * Initial SIM activation state, unknown. Not set by any carrier apps.
      * @hide
      */
@@ -5176,13 +5164,11 @@
      * @return the current call state.
      */
     public @CallState int getCallState() {
-        try {
-            ITelecomService telecom = getTelecomService();
-            if (telecom != null) {
-                return telecom.getCallState();
+        if (mContext != null) {
+            TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class);
+            if (telecomManager != null) {
+                return telecomManager.getCallState();
             }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelecomService#getCallState", e);
         }
         return CALL_STATE_IDLE;
     }
@@ -5341,13 +5327,6 @@
         return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
     }
 
-    /**
-    * @hide
-    */
-    private ITelecomService getTelecomService() {
-        return ITelecomService.Stub.asInterface(ServiceManager.getService(TELECOM_SERVICE));
-    }
-
     private ITelephonyRegistry getTelephonyRegistry() {
         return ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));
     }
@@ -5682,16 +5661,24 @@
                     new ICellInfoCallback.Stub() {
                         @Override
                         public void onCellInfo(List<CellInfo> cellInfo) {
-                            Binder.withCleanCallingIdentity(() ->
-                                    executor.execute(() -> callback.onCellInfo(cellInfo)));
+                            final long identity = Binder.clearCallingIdentity();
+                            try {
+                                executor.execute(() -> callback.onCellInfo(cellInfo));
+                            } finally {
+                                Binder.restoreCallingIdentity(identity);
+                            }
                         }
 
                         @Override
                         public void onError(int errorCode, String exceptionName, String message) {
-                            Binder.withCleanCallingIdentity(() ->
-                                    executor.execute(() -> callback.onError(
-                                            errorCode,
-                                            createThrowableByClassName(exceptionName, message))));
+                            final long identity = Binder.clearCallingIdentity();
+                            try {
+                                executor.execute(() -> callback.onError(
+                                        errorCode,
+                                        createThrowableByClassName(exceptionName, message)));
+                            } finally {
+                                Binder.restoreCallingIdentity(identity);
+                            }
                         }
                     }, getOpPackageName(), getFeatureId());
         } catch (RemoteException ex) {
@@ -5724,16 +5711,25 @@
                     new ICellInfoCallback.Stub() {
                         @Override
                         public void onCellInfo(List<CellInfo> cellInfo) {
-                            Binder.withCleanCallingIdentity(() ->
-                                    executor.execute(() -> callback.onCellInfo(cellInfo)));
+                            final long identity = Binder.clearCallingIdentity();
+                            try {
+                                executor.execute(() -> callback.onCellInfo(cellInfo));
+                            } finally {
+                                Binder.restoreCallingIdentity(identity);
+                            }
+
                         }
 
                         @Override
                         public void onError(int errorCode, String exceptionName, String message) {
-                            Binder.withCleanCallingIdentity(() ->
-                                    executor.execute(() -> callback.onError(
-                                            errorCode,
-                                            createThrowableByClassName(exceptionName, message))));
+                            final long identity = Binder.clearCallingIdentity();
+                            try {
+                                executor.execute(() -> callback.onError(
+                                        errorCode,
+                                        createThrowableByClassName(exceptionName, message)));
+                            } finally {
+                                Binder.restoreCallingIdentity(identity);
+                            }
                         }
                     }, getOpPackageName(), getFeatureId(), workSource);
         } catch (RemoteException ex) {
@@ -6598,16 +6594,24 @@
         INumberVerificationCallback internalCallback = new INumberVerificationCallback.Stub() {
             @Override
             public void onCallReceived(String phoneNumber) {
-                Binder.withCleanCallingIdentity(() ->
-                        executor.execute(() ->
-                                callback.onCallReceived(phoneNumber)));
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    executor.execute(() ->
+                            callback.onCallReceived(phoneNumber));
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
             }
 
             @Override
             public void onVerificationFailed(int reason) {
-                Binder.withCleanCallingIdentity(() ->
-                        executor.execute(() ->
-                                callback.onVerificationFailed(reason)));
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    executor.execute(() ->
+                            callback.onVerificationFailed(reason));
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
             }
         };
 
@@ -8157,17 +8161,25 @@
         return Collections.EMPTY_LIST;
     }
 
-    /** @hide */
-    public List<String> getPackagesWithCarrierPrivilegesForAllPhones() {
+    /**
+     * Get the names of packages with carrier privileges for all the active subscriptions.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @NonNull
+    public List<String> getCarrierPrivilegedPackagesForAllActiveSubscriptions() {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 return telephony.getPackagesWithCarrierPrivilegesForAllPhones();
             }
         } catch (RemoteException ex) {
-            Rlog.e(TAG, "getPackagesWithCarrierPrivilegesForAllPhones RemoteException", ex);
+            Rlog.e(TAG, "getCarrierPrivilegedPackagesForAllActiveSubscriptions RemoteException",
+                    ex);
         } catch (NullPointerException ex) {
-            Rlog.e(TAG, "getPackagesWithCarrierPrivilegesForAllPhones NPE", ex);
+            Rlog.e(TAG, "getCarrierPrivilegedPackagesForAllActiveSubscriptions NPE", ex);
         }
         return Collections.EMPTY_LIST;
     }
@@ -11507,9 +11519,14 @@
                 if (executor == null || callback == null) {
                     return;
                 }
-                Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
-                    callback.accept(SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION);
-                }));
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    executor.execute(() -> {
+                        callback.accept(SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION);
+                    });
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
                 return;
             }
             ISetOpportunisticDataCallback callbackStub = new ISetOpportunisticDataCallback.Stub() {
@@ -11518,9 +11535,14 @@
                     if (executor == null || callback == null) {
                         return;
                     }
-                    Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
-                        callback.accept(result);
-                    }));
+                    final long identity = Binder.clearCallingIdentity();
+                    try {
+                        executor.execute(() -> {
+                            callback.accept(result);
+                        });
+                    } finally {
+                        Binder.restoreCallingIdentity(identity);
+                    }
                 }
             };
 
@@ -11594,13 +11616,23 @@
                     return;
                 }
                 if (iOpportunisticNetworkService == null) {
-                    Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
-                        callback.accept(UPDATE_AVAILABLE_NETWORKS_REMOTE_SERVICE_EXCEPTION);
-                    }));
+                    final long identity = Binder.clearCallingIdentity();
+                    try {
+                        executor.execute(() -> {
+                            callback.accept(UPDATE_AVAILABLE_NETWORKS_REMOTE_SERVICE_EXCEPTION);
+                        });
+                    } finally {
+                        Binder.restoreCallingIdentity(identity);
+                    }
                 } else {
-                    Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
-                        callback.accept(UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS);
-                    }));
+                    final long identity = Binder.clearCallingIdentity();
+                    try {
+                        executor.execute(() -> {
+                            callback.accept(UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS);
+                        });
+                    } finally {
+                        Binder.restoreCallingIdentity(identity);
+                    }
                 }
                 return;
             }
@@ -11611,9 +11643,14 @@
                             if (executor == null || callback == null) {
                                 return;
                             }
-                            Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
-                                callback.accept(result);
-                            }));
+                            final long identity = Binder.clearCallingIdentity();
+                            try {
+                                executor.execute(() -> {
+                                    callback.accept(result);
+                                });
+                            } finally {
+                                Binder.restoreCallingIdentity(identity);
+                            }
                         }
                     };
             iOpportunisticNetworkService.updateAvailableNetworks(availableNetworks, callbackStub,
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 5fd0af5..057d22c 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -161,9 +161,13 @@
             public void onCapabilitiesStatusChanged(int config) {
                 if (mLocalCallback == null) return;
 
-                Binder.withCleanCallingIdentity(() ->
-                        mExecutor.execute(() -> mLocalCallback.onCapabilitiesStatusChanged(
-                                new MmTelFeature.MmTelCapabilities(config))));
+                long callingIdentity = Binder.clearCallingIdentity();
+                try {
+                    mExecutor.execute(() -> mLocalCallback.onCapabilitiesStatusChanged(
+                            new MmTelFeature.MmTelCapabilities(config)));
+                } finally {
+                    restoreCallingIdentity(callingIdentity);
+                }
             }
 
             @Override
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index 21707b0..b37d7c7 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -67,9 +67,13 @@
             public void onCapabilitiesStatusChanged(int config) {
                 if (mLocalCallback == null) return;
 
-                Binder.withCleanCallingIdentity(() ->
-                        mExecutor.execute(() -> mLocalCallback.onAvailabilityChanged(
-                                new RcsFeature.RcsImsCapabilities(config))));
+                long callingIdentity = Binder.clearCallingIdentity();
+                try {
+                    mExecutor.execute(() -> mLocalCallback.onAvailabilityChanged(
+                            new RcsFeature.RcsImsCapabilities(config)));
+                } finally {
+                    restoreCallingIdentity(callingIdentity);
+                }
             }
 
             @Override
diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java
index 663b09a..f4b2cef 100644
--- a/telephony/java/android/telephony/ims/ImsReasonInfo.java
+++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java
@@ -18,9 +18,10 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -28,12 +29,13 @@
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * This class enables an application to get details on why a method call failed.
- *
- * @hide
+ * Provides details on why an IMS call failed. Applications can use the methods in this class to
+ * get local or network fault behind an IMS services failure. For example, if the code is
+ * CODE_CALL_BARRED, then the call was blocked by network call barring configuration and it is not
+ * the device's bug and the user can retry the call when network lift the barring.
+ * Typical use case includes call backs when IMS call state changed with this class as a param
+ * containing details on why IMS call changed state/failed.
  */
-@SystemApi
-@TestApi
 public final class ImsReasonInfo implements Parcelable {
 
     /**
@@ -1096,9 +1098,11 @@
     /**
      * Network string error messages.
      * mExtraMessage may have these values.
+     * @hide
      */
-    public static final String EXTRA_MSG_SERVICE_NOT_AUTHORIZED
-            = "Forbidden. Not Authorized for Service";
+    @SystemApi
+    public static final String EXTRA_MSG_SERVICE_NOT_AUTHORIZED =
+            "Forbidden. Not Authorized for Service";
 
 
     /*
@@ -1106,21 +1110,21 @@
      * This value can be referred when the code is CODE_LOCAL_CALL_CS_RETRY_REQUIRED.
      */
     /**
-     * An extra that may be populated when the {@link CODE_LOCAL_CALL_CS_RETRY_REQUIRED} result has
+     * An extra that may be populated when the {@link #CODE_LOCAL_CALL_CS_RETRY_REQUIRED} result has
      * been returned.
      * <p>
      * Try to connect the call using CS
      */
     public static final int EXTRA_CODE_CALL_RETRY_NORMAL = 1;
     /**
-     * An extra that may be populated when the {@link CODE_LOCAL_CALL_CS_RETRY_REQUIRED} result has
+     * An extra that may be populated when the {@link #CODE_LOCAL_CALL_CS_RETRY_REQUIRED} result has
      * been returned.
      * <p>
      * Try to connect the call using CS and do not notify the user.
      */
     public static final int EXTRA_CODE_CALL_RETRY_SILENT_REDIAL = 2;
     /**
-     * An extra that may be populated when the {@link CODE_LOCAL_CALL_CS_RETRY_REQUIRED} result has
+     * An extra that may be populated when the {@link #CODE_LOCAL_CALL_CS_RETRY_REQUIRED} result has
      * been returned.
      * <p>
      * Try to connect the call using CS by using the settings.
@@ -1130,15 +1134,18 @@
 
     // For main reason code
     /** @hide */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "{@code "
+            + "#getCode()}")
     public int mCode;
     // For the extra code value; it depends on the code value.
     /** @hide */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "{@code "
+            + "#getExtraCode()}")
     public int mExtraCode;
     // For the additional message of the reason info.
     /** @hide */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "{@code "
+            + "#getExtraMessage()}")
     public String mExtraMessage;
 
     /** @hide */
@@ -1162,7 +1169,7 @@
         mExtraMessage = null;
     }
 
-    public ImsReasonInfo(int code, int extraCode, String extraMessage) {
+    public ImsReasonInfo(@ImsCode int code, int extraCode, @Nullable String extraMessage) {
         mCode = code;
         mExtraCode = extraCode;
         mExtraMessage = extraMessage;
@@ -1186,7 +1193,7 @@
      * @return an optional OEM specified string that provides extra information about the operation
      * result.
      */
-    public String getExtraMessage() {
+    public @Nullable String getExtraMessage() {
         return mExtraMessage;
     }
 
@@ -1205,13 +1212,13 @@
     }
 
     @Override
-    public void writeToParcel(Parcel out, int flags) {
+    public void writeToParcel(@NonNull Parcel out, int flags) {
         out.writeInt(mCode);
         out.writeInt(mExtraCode);
         out.writeString(mExtraMessage);
     }
 
-    public static final @android.annotation.NonNull Creator<ImsReasonInfo> CREATOR = new Creator<ImsReasonInfo>() {
+    public static final @NonNull Creator<ImsReasonInfo> CREATOR = new Creator<ImsReasonInfo>() {
         @Override
         public ImsReasonInfo createFromParcel(Parcel in) {
             return new ImsReasonInfo(in);
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index e16085e..e4d6335 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -136,17 +136,24 @@
 
             @Override
             public final void onIntConfigChanged(int item, int value) {
-                Binder.withCleanCallingIdentity(() ->
-                        mExecutor.execute(() ->
-                                mLocalConfigurationCallback.onProvisioningIntChanged(item, value)));
+                long callingIdentity = Binder.clearCallingIdentity();
+                try {
+                    mExecutor.execute(() ->
+                            mLocalConfigurationCallback.onProvisioningIntChanged(item, value));
+                } finally {
+                    restoreCallingIdentity(callingIdentity);
+                }
             }
 
             @Override
             public final void onStringConfigChanged(int item, String value) {
-                Binder.withCleanCallingIdentity(() ->
-                        mExecutor.execute(() ->
-                                mLocalConfigurationCallback.onProvisioningStringChanged(item,
-                                        value)));
+                long callingIdentity = Binder.clearCallingIdentity();
+                try {
+                    mExecutor.execute(() ->
+                            mLocalConfigurationCallback.onProvisioningStringChanged(item, value));
+                } finally {
+                    restoreCallingIdentity(callingIdentity);
+                }
             }
 
             private void setExecutor(Executor executor) {
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index b47bcb9..75e3f0a 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -245,15 +245,22 @@
         IRcsUceControllerCallback internalCallback = new IRcsUceControllerCallback.Stub() {
             @Override
             public void onCapabilitiesReceived(List<RcsContactUceCapability> contactCapabilities) {
-                Binder.withCleanCallingIdentity(() ->
-                        executor.execute(() ->
-                                c.onCapabilitiesReceived(contactCapabilities)));
+                long callingIdentity = Binder.clearCallingIdentity();
+                try {
+                    executor.execute(() ->
+                            c.onCapabilitiesReceived(contactCapabilities));
+                } finally {
+                    restoreCallingIdentity(callingIdentity);
+                }
             }
             @Override
             public void onError(int errorCode) {
-                Binder.withCleanCallingIdentity(() ->
-                        executor.execute(() ->
-                                c.onError(errorCode)));
+                long callingIdentity = Binder.clearCallingIdentity();
+                try {
+                    executor.execute(() -> c.onError(errorCode));
+                } finally {
+                    restoreCallingIdentity(callingIdentity);
+                }
             }
         };
 
diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java
index 99bb259..ca081ec 100644
--- a/telephony/java/android/telephony/ims/RegistrationManager.java
+++ b/telephony/java/android/telephony/ims/RegistrationManager.java
@@ -110,42 +110,63 @@
             public void onRegistered(int imsRadioTech) {
                 if (mLocalCallback == null) return;
 
-                Binder.withCleanCallingIdentity(() -> mExecutor.execute(() ->
-                        mLocalCallback.onRegistered(getAccessType(imsRadioTech))));
+                long callingIdentity = Binder.clearCallingIdentity();
+                try {
+                    mExecutor.execute(() ->
+                            mLocalCallback.onRegistered(getAccessType(imsRadioTech)));
+                } finally {
+                    restoreCallingIdentity(callingIdentity);
+                }
             }
 
             @Override
             public void onRegistering(int imsRadioTech) {
                 if (mLocalCallback == null) return;
 
-                Binder.withCleanCallingIdentity(() -> mExecutor.execute(() ->
-                        mLocalCallback.onRegistering(getAccessType(imsRadioTech))));
+                long callingIdentity = Binder.clearCallingIdentity();
+                try {
+                    mExecutor.execute(() ->
+                            mLocalCallback.onRegistering(getAccessType(imsRadioTech)));
+                } finally {
+                    restoreCallingIdentity(callingIdentity);
+                }
             }
 
             @Override
             public void onDeregistered(ImsReasonInfo info) {
                 if (mLocalCallback == null) return;
 
-                Binder.withCleanCallingIdentity(() ->
-                        mExecutor.execute(() -> mLocalCallback.onUnregistered(info)));
+                long callingIdentity = Binder.clearCallingIdentity();
+                try {
+                    mExecutor.execute(() -> mLocalCallback.onUnregistered(info));
+                } finally {
+                    restoreCallingIdentity(callingIdentity);
+                }
             }
 
             @Override
             public void onTechnologyChangeFailed(int imsRadioTech, ImsReasonInfo info) {
                 if (mLocalCallback == null) return;
 
-                Binder.withCleanCallingIdentity(() ->
-                        mExecutor.execute(() -> mLocalCallback.onTechnologyChangeFailed(
-                                getAccessType(imsRadioTech), info)));
+                long callingIdentity = Binder.clearCallingIdentity();
+                try {
+                    mExecutor.execute(() -> mLocalCallback.onTechnologyChangeFailed(
+                            getAccessType(imsRadioTech), info));
+                } finally {
+                    restoreCallingIdentity(callingIdentity);
+                }
             }
 
             @Override
             public void onSubscriberAssociatedUriChanged(Uri[] uris) {
                 if (mLocalCallback == null) return;
 
-                Binder.withCleanCallingIdentity(() ->
-                        mExecutor.execute(() ->
-                                mLocalCallback.onSubscriberAssociatedUriChanged(uris)));
+                long callingIdentity = Binder.clearCallingIdentity();
+                try {
+                    mExecutor.execute(() -> mLocalCallback.onSubscriberAssociatedUriChanged(uris));
+                } finally {
+                    restoreCallingIdentity(callingIdentity);
+                }
             }
 
             private void setExecutor(Executor executor) {
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index e96d082..0eaf8dc 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -22,7 +22,6 @@
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.net.Uri;
-import android.os.Binder;
 import android.os.RemoteException;
 import android.telephony.ims.RcsContactUceCapability;
 import android.telephony.ims.aidl.IImsCapabilityCallback;
@@ -33,7 +32,7 @@
 import android.telephony.ims.stub.RcsSipOptionsImplBase;
 import android.util.Log;
 
-import com.android.internal.util.FunctionalUtils;
+import com.android.internal.telephony.util.TelephonyUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -43,6 +42,7 @@
 import java.util.concurrent.CompletionException;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
+import java.util.function.Supplier;
 
 /**
  * Base implementation of the RcsFeature APIs. Any ImsService wishing to support RCS should extend
@@ -150,13 +150,13 @@
 
         // Call the methods with a clean calling identity on the executor and wait indefinitely for
         // the future to return.
-        private void executeMethodAsync(FunctionalUtils.ThrowingRunnable r, String errorLogName)
+        private void executeMethodAsync(Runnable r, String errorLogName)
                 throws RemoteException {
             // call with a clean calling identity on the executor and wait indefinitely for the
             // future to return.
             try {
                 CompletableFuture.runAsync(
-                        () -> Binder.withCleanCallingIdentity(r), mExecutor).join();
+                        () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
             } catch (CancellationException | CompletionException e) {
                 Log.w(LOG_TAG, "RcsFeatureBinder - " + errorLogName + " exception: "
                         + e.getMessage());
@@ -164,12 +164,12 @@
             }
         }
 
-        private <T> T executeMethodAsyncForResult(FunctionalUtils.ThrowingSupplier<T> r,
+        private <T> T executeMethodAsyncForResult(Supplier<T> r,
                 String errorLogName) throws RemoteException {
             // call with a clean calling identity on the executor and wait indefinitely for the
             // future to return.
             CompletableFuture<T> future = CompletableFuture.supplyAsync(
-                    () -> Binder.withCleanCallingIdentity(r), mExecutor);
+                    () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
             try {
                 return future.get();
             } catch (ExecutionException | InterruptedException e) {
diff --git a/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl b/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl
index ee09c1c..76ebc0f 100644
--- a/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl
+++ b/telephony/java/com/android/internal/telephony/ICarrierConfigLoader.aidl
@@ -30,7 +30,7 @@
     PersistableBundle getConfigForSubIdWithFeature(int subId, String callingPackage,
             String callingFeatureId);
 
-    void overrideConfig(int subId, in PersistableBundle overrides);
+    void overrideConfig(int subId, in PersistableBundle overrides, boolean persistent);
 
     void notifyConfigChangedForSubId(int subId);
 
diff --git a/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java b/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java
index 2cdf2f6..dcea9bb 100644
--- a/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java
+++ b/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java
@@ -23,7 +23,7 @@
 import android.util.SparseIntArray;
 
 import com.android.internal.telephony.cdma.sms.UserData;
-import com.android.internal.util.XmlUtils;
+import com.android.internal.telephony.util.XmlUtils;
 
 import dalvik.annotation.compat.UnsupportedAppUsage;
 
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 8b62872..b2c3fc7 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -240,25 +240,6 @@
      */
     public static final String ACTION_NETWORK_SET_TIME = "android.intent.action.NETWORK_SET_TIME";
 
-
-    /**
-     * Broadcast Action: The timezone was set by the carrier (typically by the NITZ string).
-     * This is a sticky broadcast.
-     * The intent will have the following extra values:</p>
-     * <ul>
-     *   <li><em>time-zone</em> - The java.util.TimeZone.getID() value identifying the new time
-     *          zone.</li>
-     * </ul>
-     *
-     * <p class="note">
-     * Requires the READ_PHONE_STATE permission.
-     *
-     * <p class="note">This is a protected intent that can only be sent
-     * by the system.
-     */
-    public static final String ACTION_NETWORK_SET_TIMEZONE
-            = "android.intent.action.NETWORK_SET_TIMEZONE";
-
     /**
      * <p>Broadcast Action: It indicates the Emergency callback mode blocks datacall/sms
      * <p class="note">.
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
deleted file mode 100644
index 6e20621..0000000
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ /dev/null
@@ -1,667 +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.internal.telephony;
-
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-
-import android.Manifest;
-import android.annotation.Nullable;
-import android.app.AppOpsManager;
-import android.app.admin.DevicePolicyManager;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.os.Binder;
-import android.os.Build;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.UserHandle;
-import android.telephony.Rlog;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-import android.util.StatsLog;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Supplier;
-
-/** Utility class for Telephony permission enforcement. */
-public final class TelephonyPermissions {
-    private static final String LOG_TAG = "TelephonyPermissions";
-
-    private static final boolean DBG = false;
-
-    private static final Supplier<ITelephony> TELEPHONY_SUPPLIER = () ->
-            ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
-
-    /**
-     * Whether to disable the new device identifier access restrictions.
-     */
-    private static final String PROPERTY_DEVICE_IDENTIFIER_ACCESS_RESTRICTIONS_DISABLED =
-            "device_identifier_access_restrictions_disabled";
-
-    // Contains a mapping of packages that did not meet the new requirements to access device
-    // identifiers and the methods they were attempting to invoke; used to prevent duplicate
-    // reporting of packages / methods.
-    private static final Map<String, Set<String>> sReportedDeviceIDPackages;
-    static {
-        sReportedDeviceIDPackages = new HashMap<>();
-    }
-
-    private TelephonyPermissions() {}
-
-    /**
-     * Check whether the caller (or self, if not processing an IPC) can read phone state.
-     *
-     * <p>This method behaves in one of the following ways:
-     * <ul>
-     *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the
-     *       READ_PHONE_STATE runtime permission, or carrier privileges on the given subId.
-     *   <li>throw SecurityException: if the caller didn't declare any of these permissions, or, for
-     *       apps which support runtime permissions, if the caller does not currently have any of
-     *       these permissions.
-     *   <li>return false: if the caller lacks all of these permissions and doesn't support runtime
-     *       permissions. This implies that the user revoked the ability to read phone state
-     *       manually (via AppOps). In this case we can't throw as it would break app compatibility,
-     *       so we return false to indicate that the calling function should return dummy data.
-     * </ul>
-     *
-     * <p>Note: for simplicity, this method always returns false for callers using legacy
-     * permissions and who have had READ_PHONE_STATE revoked, even if they are carrier-privileged.
-     * Such apps should migrate to runtime permissions or stop requiring READ_PHONE_STATE on P+
-     * devices.
-     *
-     * @param subId the subId of the relevant subscription; used to check carrier privileges. May be
-     *              {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} to skip this check for cases
-     *              where it isn't relevant (hidden APIs, or APIs which are otherwise okay to leave
-     *              inaccesible to carrier-privileged apps).
-     */
-    public static boolean checkCallingOrSelfReadPhoneState(
-            Context context, int subId, String callingPackage, @Nullable String callingFeatureId,
-            String message) {
-        return checkReadPhoneState(context, subId, Binder.getCallingPid(), Binder.getCallingUid(),
-                callingPackage, callingFeatureId, message);
-    }
-
-    /** Identical to checkCallingOrSelfReadPhoneState but never throws SecurityException */
-    public static boolean checkCallingOrSelfReadPhoneStateNoThrow(
-            Context context, int subId, String callingPackage, @Nullable String callingFeatureId,
-            String message) {
-        try {
-            return checkCallingOrSelfReadPhoneState(context, subId, callingPackage,
-                    callingFeatureId, message);
-        } catch (SecurityException se) {
-            return false;
-        }
-    }
-
-    /**
-     * Check whether the app with the given pid/uid can read phone state.
-     *
-     * <p>This method behaves in one of the following ways:
-     * <ul>
-     *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the
-     *       READ_PHONE_STATE runtime permission, or carrier privileges on the given subId.
-     *   <li>throw SecurityException: if the caller didn't declare any of these permissions, or, for
-     *       apps which support runtime permissions, if the caller does not currently have any of
-     *       these permissions.
-     *   <li>return false: if the caller lacks all of these permissions and doesn't support runtime
-     *       permissions. This implies that the user revoked the ability to read phone state
-     *       manually (via AppOps). In this case we can't throw as it would break app compatibility,
-     *       so we return false to indicate that the calling function should return dummy data.
-     * </ul>
-     *
-     * <p>Note: for simplicity, this method always returns false for callers using legacy
-     * permissions and who have had READ_PHONE_STATE revoked, even if they are carrier-privileged.
-     * Such apps should migrate to runtime permissions or stop requiring READ_PHONE_STATE on P+
-     * devices.
-     */
-    public static boolean checkReadPhoneState(
-            Context context, int subId, int pid, int uid, String callingPackage,
-            @Nullable  String callingFeatureId, String message) {
-        return checkReadPhoneState(
-                context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage, callingFeatureId,
-                message);
-    }
-
-    /**
-     * Check whether the calling packages has carrier privileges for the passing subscription.
-     * @return {@code true} if the caller has carrier privileges, {@false} otherwise.
-     */
-    public static boolean checkCarrierPrivilegeForSubId(int subId) {
-        if (SubscriptionManager.isValidSubscriptionId(subId)
-                && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, Binder.getCallingUid())
-                == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
-            return true;
-        }
-        return false;
-    }
-
-    @VisibleForTesting
-    public static boolean checkReadPhoneState(
-            Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
-            String callingPackage, @Nullable String callingFeatureId, String message) {
-        try {
-            context.enforcePermission(
-                    android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message);
-
-            // SKIP checking for run-time permission since caller has PRIVILEGED permission
-            return true;
-        } catch (SecurityException privilegedPhoneStateException) {
-            try {
-                context.enforcePermission(
-                        android.Manifest.permission.READ_PHONE_STATE, pid, uid, message);
-            } catch (SecurityException phoneStateException) {
-                // If we don't have the runtime permission, but do have carrier privileges, that
-                // suffices for reading phone state.
-                if (SubscriptionManager.isValidSubscriptionId(subId)) {
-                    enforceCarrierPrivilege(telephonySupplier, subId, uid, message);
-                    return true;
-                }
-                throw phoneStateException;
-            }
-        }
-
-        // We have READ_PHONE_STATE permission, so return true as long as the AppOps bit hasn't been
-        // revoked.
-        AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
-        return appOps.noteOp(AppOpsManager.OPSTR_READ_PHONE_STATE, uid, callingPackage,
-                callingFeatureId, null) == AppOpsManager.MODE_ALLOWED;
-    }
-
-    /**
-     * Check whether the app with the given pid/uid can read phone state, or has carrier
-     * privileges on any active subscription.
-     *
-     * <p>If the app does not have carrier privilege, this method will return {@code false} instead
-     * of throwing a SecurityException. Therefore, the callers cannot tell the difference
-     * between M+ apps which declare the runtime permission but do not have it, and pre-M apps
-     * which declare the static permission but had access revoked via AppOps. Apps in the former
-     * category expect SecurityExceptions; apps in the latter don't. So this method is suitable for
-     * use only if the behavior in both scenarios is meant to be identical.
-     *
-     * @return {@code true} if the app can read phone state or has carrier privilege;
-     *         {@code false} otherwise.
-     */
-    public static boolean checkReadPhoneStateOnAnyActiveSub(Context context, int pid, int uid,
-            String callingPackage, @Nullable String callingFeatureId, String message) {
-        return checkReadPhoneStateOnAnyActiveSub(context, TELEPHONY_SUPPLIER, pid, uid,
-                callingPackage, callingFeatureId, message);
-    }
-
-    @VisibleForTesting
-    public static boolean checkReadPhoneStateOnAnyActiveSub(
-            Context context, Supplier<ITelephony> telephonySupplier, int pid, int uid,
-            String callingPackage, @Nullable String callingFeatureId, String message) {
-        try {
-            context.enforcePermission(
-                    android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message);
-
-            // SKIP checking for run-time permission since caller has PRIVILEGED permission
-            return true;
-        } catch (SecurityException privilegedPhoneStateException) {
-            try {
-                context.enforcePermission(
-                        android.Manifest.permission.READ_PHONE_STATE, pid, uid, message);
-            } catch (SecurityException phoneStateException) {
-                // If we don't have the runtime permission, but do have carrier privileges, that
-                // suffices for reading phone state.
-                return checkCarrierPrivilegeForAnySubId(context, telephonySupplier, uid);
-            }
-        }
-
-        // We have READ_PHONE_STATE permission, so return true as long as the AppOps bit hasn't been
-        // revoked.
-        AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
-        return appOps.noteOp(AppOpsManager.OPSTR_READ_PHONE_STATE, uid, callingPackage,
-                callingFeatureId, null) == AppOpsManager.MODE_ALLOWED;
-    }
-
-    /**
-     * Check whether the caller (or self, if not processing an IPC) can read device identifiers.
-     *
-     * <p>This method behaves in one of the following ways:
-     * <ul>
-     *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the calling
-     *       package passes a DevicePolicyManager Device Owner / Profile Owner device identifier
-     *       access check, or the calling package has carrier privileges on any active subscription.
-    *   <li>throw SecurityException: if the caller does not meet any of the requirements and is
-     *       targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission
-     *       or carrier privileges of any active subscription.
-     *   <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
-     *       permission. In this case the caller would expect to have access to the device
-     *       identifiers so false is returned instead of throwing a SecurityException to indicate
-     *       the calling function should return dummy data.
-     * </ul>
-     */
-    public static boolean checkCallingOrSelfReadDeviceIdentifiers(Context context,
-            String callingPackage, @Nullable String callingFeatureId, String message) {
-        return checkCallingOrSelfReadDeviceIdentifiers(context,
-                SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage, callingFeatureId,
-                message);
-    }
-
-    /**
-     * Check whether the caller (or self, if not processing an IPC) can read device identifiers.
-     *
-     * <p>This method behaves in one of the following ways:
-     * <ul>
-     *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the calling
-     *       package passes a DevicePolicyManager Device Owner / Profile Owner device identifier
-     *       access check, or the calling package has carrier privileges on any active subscription.
-     *   <li>throw SecurityException: if the caller does not meet any of the requirements and is
-     *       targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission
-     *       or carrier privileges of any active subscription.
-     *   <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
-     *       permission or carrier privileges. In this case the caller would expect to have access
-     *       to the device identifiers so false is returned instead of throwing a SecurityException
-     *       to indicate the calling function should return dummy data.
-     * </ul>
-     */
-    public static boolean checkCallingOrSelfReadDeviceIdentifiers(Context context, int subId,
-            String callingPackage, @Nullable String callingFeatureId, String message) {
-        return checkPrivilegedReadPermissionOrCarrierPrivilegePermission(
-                context, subId, callingPackage, callingFeatureId, message, true);
-    }
-
-    /**
-     * Check whether the caller (or self, if not processing an IPC) can read subscriber identifiers.
-     *
-     * <p>This method behaves in one of the following ways:
-     * <ul>
-     *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the calling
-     *       package passes a DevicePolicyManager Device Owner / Profile Owner device identifier
-     *       access check, or the calling package has carrier privileges on specified subscription.
-     *   <li>throw SecurityException: if the caller does not meet any of the requirements and is
-     *       targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission.
-     *   <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
-     *       permission. In this case the caller would expect to have access to the device
-     *       identifiers so false is returned instead of throwing a SecurityException to indicate
-     *       the calling function should return dummy data.
-     * </ul>
-     */
-    public static boolean checkCallingOrSelfReadSubscriberIdentifiers(Context context, int subId,
-            String callingPackage, @Nullable String callingFeatureId, String message) {
-        return checkPrivilegedReadPermissionOrCarrierPrivilegePermission(
-                context, subId, callingPackage, callingFeatureId, message, false);
-    }
-
-    /**
-     * Checks whether the app with the given pid/uid can read device identifiers.
-     *
-     * <p>This method behaves in one of the following ways:
-     * <ul>
-     *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the calling
-     *       package passes a DevicePolicyManager Device Owner / Profile Owner device identifier
-     *       access check; or the calling package has carrier privileges on the specified
-     *       subscription; or allowCarrierPrivilegeOnAnySub is true and has carrier privilege on
-     *       any active subscription.
-     *   <li>throw SecurityException: if the caller does not meet any of the requirements and is
-     *       targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission.
-     *   <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
-     *       permission. In this case the caller would expect to have access to the device
-     *       identifiers so false is returned instead of throwing a SecurityException to indicate
-     *       the calling function should return dummy data.
-     * </ul>
-     */
-    private static boolean checkPrivilegedReadPermissionOrCarrierPrivilegePermission(
-            Context context, int subId, String callingPackage, @Nullable String callingFeatureId,
-            String message, boolean allowCarrierPrivilegeOnAnySub) {
-        int uid = Binder.getCallingUid();
-        int pid = Binder.getCallingPid();
-        // Allow system and root access to the device identifiers.
-        final int appId = UserHandle.getAppId(uid);
-        if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID) {
-            return true;
-        }
-        // Allow access to packages that have the READ_PRIVILEGED_PHONE_STATE permission.
-        if (context.checkPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid,
-                uid) == PackageManager.PERMISSION_GRANTED) {
-            return true;
-        }
-
-        // If the calling package has carrier privileges for specified sub, then allow access.
-        if (checkCarrierPrivilegeForSubId(subId)) return true;
-
-        // If the calling package has carrier privileges for any subscription
-        // and allowCarrierPrivilegeOnAnySub is set true, then allow access.
-        if (allowCarrierPrivilegeOnAnySub && checkCarrierPrivilegeForAnySubId(
-                context, TELEPHONY_SUPPLIER, uid)) {
-            return true;
-        }
-
-        // if the calling package is not null then perform the DevicePolicyManager device /
-        // profile owner and Appop checks.
-        if (callingPackage != null) {
-            // Allow access to an app that has been granted the READ_DEVICE_IDENTIFIERS app op.
-            long token = Binder.clearCallingIdentity();
-            AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(
-                    Context.APP_OPS_SERVICE);
-            try {
-                if (appOpsManager.noteOpNoThrow(AppOpsManager.OPSTR_READ_DEVICE_IDENTIFIERS, uid,
-                        callingPackage, callingFeatureId, null) == AppOpsManager.MODE_ALLOWED) {
-                    return true;
-                }
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-            // Allow access to a device / profile owner app.
-            DevicePolicyManager devicePolicyManager =
-                    (DevicePolicyManager) context.getSystemService(
-                            Context.DEVICE_POLICY_SERVICE);
-            if (devicePolicyManager != null && devicePolicyManager.checkDeviceIdentifierAccess(
-                    callingPackage, pid, uid)) {
-                return true;
-            }
-        }
-        return reportAccessDeniedToReadIdentifiers(context, subId, pid, uid, callingPackage,
-                message);
-    }
-
-    /**
-     * Reports a failure when the app with the given pid/uid cannot access the requested identifier.
-     *
-     * @returns false if the caller is targeting pre-Q and does have the READ_PHONE_STATE
-     * permission or carrier privileges.
-     * @throws SecurityException if the caller does not meet any of the requirements for the
-     *                           requested identifier and is targeting Q or is targeting pre-Q
-     *                           and does not have the READ_PHONE_STATE permission or carrier
-     *                           privileges.
-     */
-    private static boolean reportAccessDeniedToReadIdentifiers(Context context, int subId, int pid,
-            int uid, String callingPackage, String message) {
-        boolean isPreinstalled = false;
-        boolean isPrivApp = false;
-        ApplicationInfo callingPackageInfo = null;
-        try {
-            callingPackageInfo = context.getPackageManager().getApplicationInfoAsUser(
-                    callingPackage, 0, UserHandle.getUserHandleForUid(uid));
-            if (callingPackageInfo != null) {
-                if (callingPackageInfo.isSystemApp()) {
-                    isPreinstalled = true;
-                    if (callingPackageInfo.isPrivilegedApp()) {
-                        isPrivApp = true;
-                    }
-                }
-            }
-        } catch (PackageManager.NameNotFoundException e) {
-            // If the application info for the calling package could not be found then assume the
-            // calling app is a non-preinstalled app to detect any issues with the check
-            Log.e(LOG_TAG, "Exception caught obtaining package info for package " + callingPackage,
-                    e);
-        }
-        // The current package should only be reported in StatsLog if it has not previously been
-        // reported for the currently invoked device identifier method.
-        boolean packageReported = sReportedDeviceIDPackages.containsKey(callingPackage);
-        if (!packageReported || !sReportedDeviceIDPackages.get(callingPackage).contains(
-                message)) {
-            Set invokedMethods;
-            if (!packageReported) {
-                invokedMethods = new HashSet<String>();
-                sReportedDeviceIDPackages.put(callingPackage, invokedMethods);
-            } else {
-                invokedMethods = sReportedDeviceIDPackages.get(callingPackage);
-            }
-            invokedMethods.add(message);
-            StatsLog.write(StatsLog.DEVICE_IDENTIFIER_ACCESS_DENIED, callingPackage, message,
-                    isPreinstalled, isPrivApp);
-        }
-        Log.w(LOG_TAG, "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message
-                + ":isPreinstalled=" + isPreinstalled + ":isPrivApp=" + isPrivApp);
-        // if the target SDK is pre-Q then check if the calling package would have previously
-        // had access to device identifiers.
-        if (callingPackageInfo != null && (
-                callingPackageInfo.targetSdkVersion < Build.VERSION_CODES.Q)) {
-            if (context.checkPermission(
-                    android.Manifest.permission.READ_PHONE_STATE,
-                    pid,
-                    uid) == PackageManager.PERMISSION_GRANTED) {
-                return false;
-            }
-            if (checkCarrierPrivilegeForSubId(subId)) {
-                return false;
-            }
-        }
-        throw new SecurityException(message + ": The user " + uid
-                + " does not meet the requirements to access device identifiers.");
-    }
-
-    /**
-     * Check whether the app with the given pid/uid can read the call log.
-     * @return {@code true} if the specified app has the read call log permission and AppOpp granted
-     *      to it, {@code false} otherwise.
-     */
-    public static boolean checkReadCallLog(
-            Context context, int subId, int pid, int uid, String callingPackage,
-            @Nullable String callingPackageName) {
-        return checkReadCallLog(
-                context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage, callingPackageName);
-    }
-
-    @VisibleForTesting
-    public static boolean checkReadCallLog(
-            Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
-            String callingPackage, @Nullable String callingFeatureId) {
-
-        if (context.checkPermission(Manifest.permission.READ_CALL_LOG, pid, uid)
-                != PERMISSION_GRANTED) {
-            // If we don't have the runtime permission, but do have carrier privileges, that
-            // suffices for being able to see the call phone numbers.
-            if (SubscriptionManager.isValidSubscriptionId(subId)) {
-                enforceCarrierPrivilege(telephonySupplier, subId, uid, "readCallLog");
-                return true;
-            }
-            return false;
-        }
-
-        // We have READ_CALL_LOG permission, so return true as long as the AppOps bit hasn't been
-        // revoked.
-        AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
-        return appOps.noteOp(AppOpsManager.OPSTR_READ_CALL_LOG, uid, callingPackage,
-                callingFeatureId, null) == AppOpsManager.MODE_ALLOWED;
-    }
-
-    /**
-     * Returns whether the caller can read phone numbers.
-     *
-     * <p>Besides apps with the ability to read phone state per {@link #checkReadPhoneState}, the
-     * default SMS app and apps with READ_SMS or READ_PHONE_NUMBERS can also read phone numbers.
-     */
-    public static boolean checkCallingOrSelfReadPhoneNumber(
-            Context context, int subId, String callingPackage, @Nullable String callingFeatureId,
-            String message) {
-        return checkReadPhoneNumber(
-                context, TELEPHONY_SUPPLIER, subId, Binder.getCallingPid(), Binder.getCallingUid(),
-                callingPackage, callingFeatureId, message);
-    }
-
-    @VisibleForTesting
-    public static boolean checkReadPhoneNumber(
-            Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
-            String callingPackage, @Nullable String callingFeatureId, String message) {
-        // Default SMS app can always read it.
-        AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
-        if (appOps.noteOp(AppOpsManager.OPSTR_WRITE_SMS, uid, callingPackage, callingFeatureId,
-                null) == AppOpsManager.MODE_ALLOWED) {
-            return true;
-        }
-
-        // NOTE(b/73308711): If an app has one of the following AppOps bits explicitly revoked, they
-        // will be denied access, even if they have another permission and AppOps bit if needed.
-
-        // First, check if we can read the phone state.
-        try {
-            return checkReadPhoneState(
-                    context, telephonySupplier, subId, pid, uid, callingPackage, callingFeatureId,
-                    message);
-        } catch (SecurityException readPhoneStateSecurityException) {
-        }
-        // Can be read with READ_SMS too.
-        try {
-            context.enforcePermission(android.Manifest.permission.READ_SMS, pid, uid, message);
-            return appOps.noteOp(AppOpsManager.OPSTR_READ_SMS, uid, callingPackage,
-                    callingFeatureId, null) == AppOpsManager.MODE_ALLOWED;
-
-        } catch (SecurityException readSmsSecurityException) {
-        }
-        // Can be read with READ_PHONE_NUMBERS too.
-        try {
-            context.enforcePermission(android.Manifest.permission.READ_PHONE_NUMBERS, pid, uid,
-                    message);
-            return appOps.noteOp(AppOpsManager.OPSTR_READ_PHONE_NUMBERS, uid, callingPackage,
-                    callingFeatureId, null) == AppOpsManager.MODE_ALLOWED;
-
-        } catch (SecurityException readPhoneNumberSecurityException) {
-        }
-
-        throw new SecurityException(message + ": Neither user " + uid +
-                " nor current process has " + android.Manifest.permission.READ_PHONE_STATE +
-                ", " + android.Manifest.permission.READ_SMS + ", or " +
-                android.Manifest.permission.READ_PHONE_NUMBERS);
-    }
-
-    /**
-     * Ensure the caller (or self, if not processing an IPC) has MODIFY_PHONE_STATE (and is thus a
-     * privileged app) or carrier privileges.
-     *
-     * @throws SecurityException if the caller does not have the required permission/privileges
-     */
-    public static void enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
-            Context context, int subId, String message) {
-        if (context.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE) ==
-                PERMISSION_GRANTED) {
-            return;
-        }
-
-        if (DBG) Rlog.d(LOG_TAG, "No modify permission, check carrier privilege next.");
-        enforceCallingOrSelfCarrierPrivilege(subId, message);
-    }
-
-    /**
-     * Ensure the caller (or self, if not processing an IPC) has
-     * {@link android.Manifest.permission#READ_PHONE_STATE} or carrier privileges.
-     *
-     * @throws SecurityException if the caller does not have the required permission/privileges
-     */
-    public static void enforeceCallingOrSelfReadPhoneStatePermissionOrCarrierPrivilege(
-            Context context, int subId, String message) {
-        if (context.checkCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE)
-                == PERMISSION_GRANTED) {
-            return;
-        }
-
-        if (DBG) {
-            Rlog.d(LOG_TAG, "No READ_PHONE_STATE permission, check carrier privilege next.");
-        }
-
-        enforceCallingOrSelfCarrierPrivilege(subId, message);
-    }
-
-    /**
-     * Ensure the caller (or self, if not processing an IPC) has
-     * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} or carrier privileges.
-     *
-     * @throws SecurityException if the caller does not have the required permission/privileges
-     */
-    public static void enforeceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
-            Context context, int subId, String message) {
-        if (context.checkCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-                == PERMISSION_GRANTED) {
-            return;
-        }
-
-        if (DBG) {
-            Rlog.d(LOG_TAG, "No READ_PRIVILEDED_PHONE_STATE permission, " +
-                    "check carrier privilege next.");
-        }
-
-        enforceCallingOrSelfCarrierPrivilege(subId, message);
-    }
-
-    /**
-     * Make sure the caller (or self, if not processing an IPC) has carrier privileges.
-     *
-     * @throws SecurityException if the caller does not have the required privileges
-     */
-    public static void enforceCallingOrSelfCarrierPrivilege(int subId, String message) {
-        // NOTE: It's critical that we explicitly pass the calling UID here rather than call
-        // TelephonyManager#hasCarrierPrivileges directly, as the latter only works when called from
-        // the phone process. When called from another process, it will check whether that process
-        // has carrier privileges instead.
-        enforceCarrierPrivilege(subId, Binder.getCallingUid(), message);
-    }
-
-    private static void enforceCarrierPrivilege(int subId, int uid, String message) {
-        enforceCarrierPrivilege(TELEPHONY_SUPPLIER, subId, uid, message);
-    }
-
-    private static void enforceCarrierPrivilege(
-            Supplier<ITelephony> telephonySupplier, int subId, int uid, String message) {
-        if (getCarrierPrivilegeStatus(telephonySupplier, subId, uid) !=
-                TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
-            if (DBG) Rlog.e(LOG_TAG, "No Carrier Privilege.");
-            throw new SecurityException(message);
-        }
-    }
-
-    /** Returns whether the provided uid has carrier privileges for any active subscription ID. */
-    private static boolean checkCarrierPrivilegeForAnySubId(
-            Context context, Supplier<ITelephony> telephonySupplier, int uid) {
-        SubscriptionManager sm = (SubscriptionManager) context.getSystemService(
-                Context.TELEPHONY_SUBSCRIPTION_SERVICE);
-        int[] activeSubIds = sm.getActiveSubscriptionIdList(/* visibleOnly */ false);
-        for (int activeSubId : activeSubIds) {
-            if (getCarrierPrivilegeStatus(telephonySupplier, activeSubId, uid)
-                    == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private static int getCarrierPrivilegeStatus(
-            Supplier<ITelephony> telephonySupplier, int subId, int uid) {
-        ITelephony telephony = telephonySupplier.get();
-        try {
-            if (telephony != null) {
-                return telephony.getCarrierPrivilegeStatusForUid(subId, uid);
-            }
-        } catch (RemoteException e) {
-            // Fallback below.
-        }
-        Rlog.e(LOG_TAG, "Phone process is down, cannot check carrier privileges");
-        return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
-    }
-
-    /**
-     * Throws if the caller is not of a shell (or root) UID.
-     *
-     * @param callingUid pass Binder.callingUid().
-     */
-    public static void enforceShellOnly(int callingUid, String message) {
-        if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
-            return; // okay
-        }
-
-        throw new SecurityException(message + ": Only shell user can call it");
-    }
-}
diff --git a/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java
new file mode 100644
index 0000000..306b9ee
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java
@@ -0,0 +1,111 @@
+/*
+ * 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.internal.telephony.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.ComponentInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+
+import java.io.PrintWriter;
+import java.util.function.Supplier;
+
+/**
+ * This class provides various util functions
+ */
+public final class TelephonyUtils {
+    public static boolean IS_USER = "user".equals(android.os.Build.TYPE);
+    public static boolean IS_DEBUGGABLE = SystemProperties.getInt("ro.debuggable", 0) == 1;
+
+    /**
+     * Verify that caller holds {@link android.Manifest.permission#DUMP}.
+     *
+     * @return true if access should be granted.
+     */
+    public static boolean checkDumpPermission(Context context, String tag, PrintWriter pw) {
+        if (context.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump " + tag + " from from pid="
+                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+                    + " due to missing android.permission.DUMP permission");
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    /** Returns an empty string if the input is {@code null}. */
+    public static String emptyIfNull(@Nullable String str) {
+        return str == null ? "" : str;
+    }
+
+    /** Throws a {@link RuntimeException} that wrapps the {@link RemoteException}. */
+    public static RuntimeException rethrowAsRuntimeException(RemoteException remoteException) {
+        throw new RuntimeException(remoteException);
+    }
+
+    /**
+     * Returns a {@link ComponentInfo} from the {@link ResolveInfo},
+     * or throws an {@link IllegalStateException} if not available.
+     */
+    public static ComponentInfo getComponentInfo(@NonNull ResolveInfo resolveInfo) {
+        if (resolveInfo.activityInfo != null) return resolveInfo.activityInfo;
+        if (resolveInfo.serviceInfo != null) return resolveInfo.serviceInfo;
+        if (resolveInfo.providerInfo != null) return resolveInfo.providerInfo;
+        throw new IllegalStateException("Missing ComponentInfo!");
+    }
+
+    /**
+     * Convenience method for running the provided action enclosed in
+     * {@link Binder#clearCallingIdentity}/{@link Binder#restoreCallingIdentity}
+     *
+     * Any exception thrown by the given action will need to be handled by caller.
+     *
+     */
+    public static void runWithCleanCallingIdentity(
+            @NonNull Runnable action) {
+        long callingIdentity = Binder.clearCallingIdentity();
+        try {
+            action.run();
+        } finally {
+            Binder.restoreCallingIdentity(callingIdentity);
+        }
+    }
+
+
+    /**
+     * Convenience method for running the provided action enclosed in
+     * {@link Binder#clearCallingIdentity}/{@link Binder#restoreCallingIdentity} and return
+     * the result.
+     *
+     * Any exception thrown by the given action will need to be handled by caller.
+     *
+     */
+    public static <T> T runWithCleanCallingIdentity(
+            @NonNull Supplier<T> action) {
+        long callingIdentity = Binder.clearCallingIdentity();
+        try {
+            return action.get();
+        } finally {
+            Binder.restoreCallingIdentity(callingIdentity);
+        }
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/util/XmlUtils.java b/telephony/java/com/android/internal/telephony/util/XmlUtils.java
new file mode 100644
index 0000000..72c5d3a
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/util/XmlUtils.java
@@ -0,0 +1,75 @@
+/*
+ * 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.internal.telephony.util;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/** Utility methods for XML operations. */
+public final class XmlUtils {
+    private XmlUtils() {}
+
+    /**
+     * Moves parser to the first start tag, and expects the tag name being {@code firstElementName}.
+     */
+    public static void beginDocument(XmlPullParser parser, String firstElementName)
+            throws XmlPullParserException, IOException {
+        int type;
+        while ((type = parser.next()) != parser.START_TAG && type != parser.END_DOCUMENT) {
+            // no-op
+        }
+
+        if (type != parser.START_TAG) {
+            throw new XmlPullParserException("No start tag found");
+        }
+
+        if (!parser.getName().equals(firstElementName)) {
+            throw new XmlPullParserException("Unexpected start tag: found " + parser.getName()
+                    + ", expected " + firstElementName);
+        }
+    }
+
+    /**
+     * Moves parser to the next start tag.
+     */
+    public static void nextElement(XmlPullParser parser)
+            throws XmlPullParserException, IOException {
+        int type;
+        while ((type = parser.next()) != parser.START_TAG && type != parser.END_DOCUMENT) {
+            // no-op
+        }
+    }
+
+    /**
+     * Moves parser to the next start tag within the {@code outerDepth}.
+     */
+    public static boolean nextElementWithin(XmlPullParser parser, int outerDepth)
+            throws IOException, XmlPullParserException {
+        for (;;) {
+            int type = parser.next();
+            if (type == XmlPullParser.END_DOCUMENT
+                    || (type == XmlPullParser.END_TAG && parser.getDepth() == outerDepth)) {
+                return false;
+            }
+            if (type == XmlPullParser.START_TAG && parser.getDepth() == outerDepth + 1) {
+                return true;
+            }
+        }
+    }
+}
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index 45b236c..0208c3a 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -470,6 +470,13 @@
     }
 
     @Override
+    public void sendOrderedBroadcast(Intent intent, String receiverPermission, String receiverAppOp,
+            Bundle options, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
+            String initialData, Bundle initialExtras) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public void sendStickyBroadcast(Intent intent) {
         throw new UnsupportedOperationException();
     }
diff --git a/tests/ApkVerityTest/TEST_MAPPING b/tests/ApkVerityTest/TEST_MAPPING
new file mode 100644
index 0000000..a660839
--- /dev/null
+++ b/tests/ApkVerityTest/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    // nextgen test only runs during postsubmit.
+    {
+      "name": "ApkVerityTest",
+      "keywords": ["nextgen"]
+    }
+  ],
+  "postsubmit": [
+    // TODO: move to presubmit once it's confirmed stable.
+    {
+      "name": "ApkVerityTest"
+    }
+  ]
+}
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index d433df5..d1da47f 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -25,6 +25,6 @@
     <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
         <option name="directory-keys" value="/sdcard/flicker" />
         <option name="collect-on-run-ended-only" value="true" />
-        <option name="clean-up" value="false" />
+        <option name="clean-up" value="true" />
     </metrics_collector>
 </configuration>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
index 0787d82..51bae3a 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
@@ -29,9 +29,13 @@
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
+import android.graphics.RuntimeShader;
 import android.os.Bundle;
 import android.view.View;
 
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
 @SuppressWarnings({"UnusedDeclaration"})
 public class ColorFiltersMutateActivity extends Activity {
     @Override
@@ -47,12 +51,21 @@
         private final Paint mColorMatrixPaint;
         private final Paint mLightingPaint;
         private final Paint mBlendPaint;
+        private final Paint mShaderPaint;
 
         private float mSaturation = 0.0f;
         private int mLightAdd = 0;
         private int mLightMul = 0;
         private int mPorterDuffColor = 0;
 
+        static final String sSkSL =
+                "uniform float param1;\n"
+                + "void main(float x, float y, inout half4 color) {\n"
+                + "color = half4(color.r, half(param1), color.b, 1.0);\n"
+                + "}\n";
+
+        private byte[] mUniforms = new byte[4];
+
         BitmapsView(Context c) {
             super(c);
 
@@ -70,6 +83,10 @@
             mBlendPaint = new Paint();
             mBlendPaint.setColorFilter(new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_OVER));
 
+            mShaderPaint = new Paint();
+            mShaderPaint.setShader(new RuntimeShader(sSkSL, mUniforms, true));
+            setShaderParam1(0.0f);
+
             ObjectAnimator sat = ObjectAnimator.ofFloat(this, "saturation", 1.0f);
             sat.setDuration(1000);
             sat.setRepeatCount(ObjectAnimator.INFINITE);
@@ -96,6 +113,12 @@
             color.setRepeatCount(ObjectAnimator.INFINITE);
             color.setRepeatMode(ObjectAnimator.REVERSE);
             color.start();
+
+            ObjectAnimator shaderUniform = ObjectAnimator.ofFloat(this, "shaderParam1", 1.0f);
+            shaderUniform.setDuration(1000);
+            shaderUniform.setRepeatCount(ObjectAnimator.INFINITE);
+            shaderUniform.setRepeatMode(ObjectAnimator.REVERSE);
+            shaderUniform.start();
         }
 
         public int getPorterDuffColor() {
@@ -148,6 +171,23 @@
             return mSaturation;
         }
 
+        public void setShaderParam1(float value) {
+            RuntimeShader shader = (RuntimeShader) mShaderPaint.getShader();
+            ByteBuffer buffer = ByteBuffer.wrap(mUniforms);
+            buffer.order(ByteOrder.LITTLE_ENDIAN);
+            buffer.putFloat(value);
+            shader.updateUniforms(mUniforms);
+            invalidate();
+        }
+
+        // If either valueFrom or valueTo is null, then a getter function will also be derived
+        // and called by the animator class.
+        public float getShaderParam1() {
+            ByteBuffer buffer = ByteBuffer.wrap(mUniforms);
+            buffer.order(ByteOrder.LITTLE_ENDIAN);
+            return buffer.getFloat();
+        }
+
         @Override
         protected void onDraw(Canvas canvas) {
             super.onDraw(canvas);
@@ -163,6 +203,10 @@
 
             canvas.translate(0.0f, 50.0f + mBitmap1.getHeight());
             canvas.drawBitmap(mBitmap1, 0.0f, 0.0f, mBlendPaint);
+
+            canvas.translate(0.0f, 50.0f + mBitmap1.getHeight());
+            canvas.drawRect(0.0f, 0.0f, mBitmap1.getWidth(), mBitmap1.getHeight(),
+                    mShaderPaint);
             canvas.restore();
 
             canvas.save();
@@ -174,6 +218,10 @@
 
             canvas.translate(0.0f, 50.0f + mBitmap2.getHeight());
             canvas.drawBitmap(mBitmap2, 0.0f, 0.0f, mBlendPaint);
+
+            canvas.translate(0.0f, 50.0f + mBitmap2.getHeight());
+            canvas.drawRoundRect(0.0f, 0.0f, mBitmap2.getWidth(), mBitmap2.getHeight(), 20, 20,
+                    mShaderPaint);
             canvas.restore();
         }
     }
diff --git a/tests/ManagedProfileLifecycleStressTest/Android.bp b/tests/ManagedProfileLifecycleStressTest/Android.bp
new file mode 100644
index 0000000..639ce3c
--- /dev/null
+++ b/tests/ManagedProfileLifecycleStressTest/Android.bp
@@ -0,0 +1,23 @@
+// 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_test_host {
+    name: "ManagedProfileLifecycleStressTest",
+    srcs: ["src/**/*.java"],
+    libs: ["tradefed"],
+    test_suites: ["device-tests"],
+    target_required: [
+        "DummyDPC",
+    ],
+}
diff --git a/tests/ManagedProfileLifecycleStressTest/AndroidTest.xml b/tests/ManagedProfileLifecycleStressTest/AndroidTest.xml
new file mode 100644
index 0000000..e7dbc51
--- /dev/null
+++ b/tests/ManagedProfileLifecycleStressTest/AndroidTest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Stress test for managed profile lifecycle">
+  <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+    <option name="jar" value="ManagedProfileLifecycleStressTest.jar" />
+  </test>
+</configuration>
diff --git a/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/Android.bp b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/Android.bp
new file mode 100644
index 0000000..d95af34
--- /dev/null
+++ b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/Android.bp
@@ -0,0 +1,20 @@
+// 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.
+
+android_test {
+    name: "DummyDPC",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    sdk_version: "current",
+}
diff --git a/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/AndroidManifest.xml b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/AndroidManifest.xml
new file mode 100644
index 0000000..860940d
--- /dev/null
+++ b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.dummydpc">
+
+    <application
+        android:testOnly="true">
+        <receiver
+            android:name="com.android.dummydpc.DummyDeviceAdminReceiver"
+            android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data android:name="android.app.device_admin"
+                       android:resource="@xml/device_admin" />
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+            </intent-filter>
+        </receiver>
+    </application>
+</manifest>
diff --git a/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/res/xml/device_admin.xml b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/res/xml/device_admin.xml
new file mode 100644
index 0000000..4b3581e
--- /dev/null
+++ b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/res/xml/device_admin.xml
@@ -0,0 +1,4 @@
+<device-admin>
+    <uses-policies>
+    </uses-policies>
+</device-admin>
diff --git a/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/src/com/android/dummydpc/DummyDeviceAdminReceiver.java b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/src/com/android/dummydpc/DummyDeviceAdminReceiver.java
new file mode 100644
index 0000000..92190b7
--- /dev/null
+++ b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/src/com/android/dummydpc/DummyDeviceAdminReceiver.java
@@ -0,0 +1,25 @@
+/*
+ * 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.dummydpc;
+
+import android.app.admin.DeviceAdminReceiver;
+
+/**
+ * Empty admin to use as a managed profile owner.
+ */
+public class DummyDeviceAdminReceiver extends DeviceAdminReceiver {
+}
+
diff --git a/tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java b/tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java
new file mode 100644
index 0000000..e323592
--- /dev/null
+++ b/tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.test.stress;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A test to exercise Android Framework parts related to creating, starting, stopping, and deleting
+ * a managed profile as much as possible. The aim is to catch any issues in this code before it
+ * affects managed profile CTS tests.
+ */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class ManagedProfileLifecycleStressTest extends BaseHostJUnit4Test {
+    // Stop the test once this time limit has been reached. 25 minutes used as a limit to make total
+    // test time less than 30 minutes, so that it can be put into presubmit.
+    private static final int TIME_LIMIT_MINUTES = 25;
+
+    private static final String DUMMY_DPC_APK = "DummyDPC.apk";
+    private static final String DUMMY_DPC_COMPONENT =
+            "com.android.dummydpc/com.android.dummydpc.DummyDeviceAdminReceiver";
+    private static final Pattern CREATE_USER_OUTPUT_REGEX =
+            Pattern.compile("Success: created user id (\\d+)");
+
+    /**
+     * Create, start, and kill managed profiles in a loop.
+     */
+    @Test
+    public void testCreateStartDelete() throws Exception {
+        int iteration = 0;
+        final long deadline = System.nanoTime() + TimeUnit.MINUTES.toNanos(TIME_LIMIT_MINUTES);
+        while (System.nanoTime() < deadline) {
+            iteration++;
+            CLog.w("Iteration N" + iteration);
+            final int userId = createManagedProfile();
+            startUser(userId);
+            installPackageAsUser(DUMMY_DPC_APK, true /* grantPermissions */, userId, "-t");
+            setProfileOwner(DUMMY_DPC_COMPONENT, userId);
+            removeUser(userId);
+        }
+        CLog.w("Completed " + iteration + " iterations.");
+    }
+
+    private int createManagedProfile() throws Exception {
+        final String output = getDevice().executeShellCommand(
+                "pm create-user --profileOf 0 --managed TestProfile");
+        final Matcher matcher = CREATE_USER_OUTPUT_REGEX.matcher(output.trim());
+        if (!matcher.matches() || matcher.groupCount() != 1) {
+            fail("user creation failed, output: " + output);
+        }
+        return Integer.parseInt(matcher.group(1));
+    }
+
+    private void setProfileOwner(String componentName, int userId) throws Exception {
+        String command = "dpm set-profile-owner --user " + userId + " '" + componentName + "'";
+        String commandOutput = getDevice().executeShellCommand(command);
+        assertTrue("Unexpected dpm output: " + commandOutput, commandOutput.startsWith("Success:"));
+    }
+
+    private void removeUser(int userId) throws Exception {
+        final String output = getDevice().executeShellCommand("pm remove-user " + userId).trim();
+        assertEquals("Unexpected pm output: " + output, "Success: removed user", output);
+    }
+
+    private void startUser(int userId) throws Exception {
+        final String output = getDevice().executeShellCommand("am start-user -w " + userId).trim();
+        assertEquals("Unexpected am output: " + output, "Success: user started", output);
+    }
+}
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index 06b58fd..ef8face 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -118,7 +118,8 @@
 
         watchdog.startObservingHealth(observer, Arrays.asList(APP_A), SHORT_DURATION);
         raiseFatalFailureAndDispatch(watchdog,
-                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
+                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
 
         // The failed packages should be the same as the registered ones to ensure registration is
         // done successfully
@@ -135,7 +136,8 @@
         watchdog.startObservingHealth(observer2, Arrays.asList(APP_A, APP_B), SHORT_DURATION);
         raiseFatalFailureAndDispatch(watchdog,
                 Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE),
-                        new VersionedPackage(APP_B, VERSION_CODE)));
+                        new VersionedPackage(APP_B, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
 
         // The failed packages should be the same as the registered ones to ensure registration is
         // done successfully
@@ -151,7 +153,8 @@
         watchdog.startObservingHealth(observer, Arrays.asList(APP_A), SHORT_DURATION);
         watchdog.unregisterHealthObserver(observer);
         raiseFatalFailureAndDispatch(watchdog,
-                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
+                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
 
         // We should have no failed packages to ensure unregistration is done successfully
         assertThat(observer.mHealthCheckFailedPackages).isEmpty();
@@ -167,7 +170,8 @@
         watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION);
         watchdog.unregisterHealthObserver(observer2);
         raiseFatalFailureAndDispatch(watchdog,
-                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
+                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
 
         // observer1 should receive failed packages as intended.
         assertThat(observer1.mHealthCheckFailedPackages).containsExactly(APP_A);
@@ -183,7 +187,8 @@
         watchdog.startObservingHealth(observer, Arrays.asList(APP_A), SHORT_DURATION);
         moveTimeForwardAndDispatch(SHORT_DURATION);
         raiseFatalFailureAndDispatch(watchdog,
-                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
+                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
 
         // We should have no failed packages for the fatal failure is raised after expiration
         assertThat(observer.mHealthCheckFailedPackages).isEmpty();
@@ -199,7 +204,8 @@
         watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), LONG_DURATION);
         moveTimeForwardAndDispatch(SHORT_DURATION);
         raiseFatalFailureAndDispatch(watchdog,
-                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
+                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
 
         // We should have no failed packages for the fatal failure is raised after expiration
         assertThat(observer1.mHealthCheckFailedPackages).isEmpty();
@@ -226,7 +232,8 @@
         moveTimeForwardAndDispatch((SHORT_DURATION / 2) + 1);
 
         raiseFatalFailureAndDispatch(watchdog,
-                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
+                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
 
         // Verify that we receive failed packages as expected for APP_A not expired
         assertThat(observer.mHealthCheckFailedPackages).containsExactly(APP_A);
@@ -252,7 +259,8 @@
         watchdog2.registerHealthObserver(observer2);
         raiseFatalFailureAndDispatch(watchdog2,
                 Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE),
-                        new VersionedPackage(APP_B, VERSION_CODE)));
+                        new VersionedPackage(APP_B, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
 
         // We should receive failed packages as expected to ensure observers are persisted and
         // resumed correctly
@@ -274,7 +282,8 @@
 
         // Then fail APP_A below the threshold
         for (int i = 0; i < watchdog.getTriggerFailureCount() - 1; i++) {
-            watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
+            watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+                    PackageWatchdog.FAILURE_REASON_UNKNOWN);
         }
 
         // Run handler so package failures are dispatched to observers
@@ -301,7 +310,8 @@
 
         // Then fail APP_C (not observed) above the threshold
         raiseFatalFailureAndDispatch(watchdog,
-                Arrays.asList(new VersionedPackage(APP_C, VERSION_CODE)));
+                Arrays.asList(new VersionedPackage(APP_C, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
 
         // Verify that observers are not notified
         assertThat(observer1.mHealthCheckFailedPackages).isEmpty();
@@ -331,7 +341,8 @@
 
         // Then fail APP_A (different version) above the threshold
         raiseFatalFailureAndDispatch(watchdog,
-                Arrays.asList(new VersionedPackage(APP_A, differentVersionCode)));
+                Arrays.asList(new VersionedPackage(APP_A, differentVersionCode)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
 
         // Verify that observers are not notified
         assertThat(observer.mHealthCheckFailedPackages).isEmpty();
@@ -368,7 +379,8 @@
                 Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE),
                         new VersionedPackage(APP_B, VERSION_CODE),
                         new VersionedPackage(APP_C, VERSION_CODE),
-                        new VersionedPackage(APP_D, VERSION_CODE)));
+                        new VersionedPackage(APP_D, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
 
         // Verify least impact observers are notifed of package failures
         List<String> observerNonePackages = observerNone.mMitigatedPackages;
@@ -411,7 +423,8 @@
 
         // Then fail APP_A above the threshold
         raiseFatalFailureAndDispatch(watchdog,
-                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
+                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
 
         // Verify only observerFirst is notifed
         assertThat(observerFirst.mMitigatedPackages).containsExactly(APP_A);
@@ -424,7 +437,8 @@
 
         // Then fail APP_A again above the threshold
         raiseFatalFailureAndDispatch(watchdog,
-                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
+                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
 
         // Verify only observerSecond is notifed cos it has least impact
         assertThat(observerSecond.mMitigatedPackages).containsExactly(APP_A);
@@ -437,7 +451,8 @@
 
         // Then fail APP_A again above the threshold
         raiseFatalFailureAndDispatch(watchdog,
-                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
+                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
 
         // Verify only observerFirst is notifed cos it has the only action
         assertThat(observerFirst.mMitigatedPackages).containsExactly(APP_A);
@@ -450,7 +465,8 @@
 
         // Then fail APP_A again above the threshold
         raiseFatalFailureAndDispatch(watchdog,
-                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
+                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
 
         // Verify no observer is notified cos no actions left
         assertThat(observerFirst.mMitigatedPackages).isEmpty();
@@ -474,7 +490,8 @@
 
         // Then fail APP_A above the threshold
         raiseFatalFailureAndDispatch(watchdog,
-                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
+                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
 
         // Verify only one observer is notifed
         assertThat(observer1.mMitigatedPackages).containsExactly(APP_A);
@@ -670,11 +687,11 @@
     public void testPackageHealthCheckStateTransitions() {
         TestController controller = new TestController();
         PackageWatchdog wd = createWatchdog(controller, true /* withPackagesReady */);
-        MonitoredPackage m1 = wd.new MonitoredPackage(APP_A, LONG_DURATION,
+        MonitoredPackage m1 = wd.newMonitoredPackage(APP_A, LONG_DURATION,
                 false /* hasPassedHealthCheck */);
-        MonitoredPackage m2 = wd.new MonitoredPackage(APP_B, LONG_DURATION, false);
-        MonitoredPackage m3 = wd.new MonitoredPackage(APP_C, LONG_DURATION, false);
-        MonitoredPackage m4 = wd.new MonitoredPackage(APP_D, LONG_DURATION, SHORT_DURATION, true);
+        MonitoredPackage m2 = wd.newMonitoredPackage(APP_B, LONG_DURATION, false);
+        MonitoredPackage m3 = wd.newMonitoredPackage(APP_C, LONG_DURATION, false);
+        MonitoredPackage m4 = wd.newMonitoredPackage(APP_D, LONG_DURATION, SHORT_DURATION, true);
 
         // Verify transition: inactive -> active -> passed
         // Verify initially inactive
@@ -746,13 +763,15 @@
         watchdog.startObservingHealth(observer, Arrays.asList(APP_A), SHORT_DURATION);
         // Fail APP_A below the threshold which should not trigger package failures
         for (int i = 0; i < PackageWatchdog.DEFAULT_TRIGGER_FAILURE_COUNT - 1; i++) {
-            watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
+            watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+                    PackageWatchdog.FAILURE_REASON_UNKNOWN);
         }
         mTestLooper.dispatchAll();
         assertThat(observer.mHealthCheckFailedPackages).isEmpty();
 
         // One more to trigger the package failure
-        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
+        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
         mTestLooper.dispatchAll();
         assertThat(observer.mHealthCheckFailedPackages).containsExactly(APP_A);
     }
@@ -773,20 +792,24 @@
         TestObserver observer = new TestObserver(OBSERVER_NAME_1);
 
         watchdog.startObservingHealth(observer, Arrays.asList(APP_A, APP_B), Long.MAX_VALUE);
-        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
+        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
         mTestLooper.dispatchAll();
         moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_TRIGGER_FAILURE_DURATION_MS + 1);
-        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
+        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
         mTestLooper.dispatchAll();
 
         // We shouldn't receive APP_A since the interval of 2 failures is greater than
         // DEFAULT_TRIGGER_FAILURE_DURATION_MS.
         assertThat(observer.mHealthCheckFailedPackages).isEmpty();
 
-        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE)));
+        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
         mTestLooper.dispatchAll();
         moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_TRIGGER_FAILURE_DURATION_MS - 1);
-        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE)));
+        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
         mTestLooper.dispatchAll();
 
         // We should receive APP_B since the interval of 2 failures is less than
@@ -809,7 +832,8 @@
         // small timeouts.
         moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_OBSERVING_DURATION_MS - 100);
         raiseFatalFailureAndDispatch(watchdog,
-                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
+                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
 
         // We should receive APP_A since the observer hasn't expired
         assertThat(observer.mHealthCheckFailedPackages).containsExactly(APP_A);
@@ -827,7 +851,8 @@
         watchdog.startObservingHealth(observer, Arrays.asList(APP_A), -1);
         moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_OBSERVING_DURATION_MS + 1);
         raiseFatalFailureAndDispatch(watchdog,
-                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
+                Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
 
         // We should receive nothing since the observer has expired
         assertThat(observer.mHealthCheckFailedPackages).isEmpty();
@@ -850,22 +875,59 @@
 
         watchdog.startObservingHealth(observer, Arrays.asList(APP_A), Long.MAX_VALUE);
         // Raise 2 failures at t=0 and t=900 respectively
-        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
+        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
         mTestLooper.dispatchAll();
         moveTimeForwardAndDispatch(900);
-        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
+        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
         mTestLooper.dispatchAll();
 
         // Raise 2 failures at t=1100
         moveTimeForwardAndDispatch(200);
-        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
-        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
+        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
+        watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)),
+                PackageWatchdog.FAILURE_REASON_UNKNOWN);
         mTestLooper.dispatchAll();
 
         // We should receive APP_A since there are 3 failures within 1000ms window
         assertThat(observer.mHealthCheckFailedPackages).containsExactly(APP_A);
     }
 
+    /** Test that observers execute correctly for different failure reasons */
+    @Test
+    public void testFailureReasons() {
+        PackageWatchdog watchdog = createWatchdog();
+        TestObserver observer1 = new TestObserver(OBSERVER_NAME_1);
+        TestObserver observer2 = new TestObserver(OBSERVER_NAME_2);
+        TestObserver observer3 = new TestObserver(OBSERVER_NAME_3);
+        TestObserver observer4 = new TestObserver(OBSERVER_NAME_4);
+
+        watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
+        watchdog.startObservingHealth(observer2, Arrays.asList(APP_B), SHORT_DURATION);
+        watchdog.startObservingHealth(observer3, Arrays.asList(APP_C), SHORT_DURATION);
+        watchdog.startObservingHealth(observer4, Arrays.asList(APP_D), SHORT_DURATION);
+
+        raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
+                VERSION_CODE)), PackageWatchdog.FAILURE_REASON_NATIVE_CRASH);
+        raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_B,
+                VERSION_CODE)), PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK);
+        raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_C,
+                VERSION_CODE)), PackageWatchdog.FAILURE_REASON_APP_CRASH);
+        raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_D,
+                VERSION_CODE)), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING);
+
+        assertThat(observer1.getLastFailureReason()).isEqualTo(
+                PackageWatchdog.FAILURE_REASON_NATIVE_CRASH);
+        assertThat(observer2.getLastFailureReason()).isEqualTo(
+                PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK);
+        assertThat(observer3.getLastFailureReason()).isEqualTo(
+                PackageWatchdog.FAILURE_REASON_APP_CRASH);
+        assertThat(observer4.getLastFailureReason()).isEqualTo(
+                PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING);
+    }
+
     private void adoptShellPermissions(String... permissions) {
         InstrumentationRegistry
                 .getInstrumentation()
@@ -900,9 +962,9 @@
 
     /** Trigger package failures above the threshold. */
     private void raiseFatalFailureAndDispatch(PackageWatchdog watchdog,
-            List<VersionedPackage> packages) {
+            List<VersionedPackage> packages, int failureReason) {
         for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) {
-            watchdog.onPackageFailure(packages);
+            watchdog.onPackageFailure(packages, failureReason);
         }
         mTestLooper.dispatchAll();
     }
@@ -936,6 +998,7 @@
     private static class TestObserver implements PackageHealthObserver {
         private final String mName;
         private int mImpact;
+        private int mLastFailureReason;
         final List<String> mHealthCheckFailedPackages = new ArrayList<>();
         final List<String> mMitigatedPackages = new ArrayList<>();
 
@@ -954,14 +1017,19 @@
             return mImpact;
         }
 
-        public boolean execute(VersionedPackage versionedPackage) {
+        public boolean execute(VersionedPackage versionedPackage, int failureReason) {
             mMitigatedPackages.add(versionedPackage.getPackageName());
+            mLastFailureReason = failureReason;
             return true;
         }
 
         public String getName() {
             return mName;
         }
+
+        public int getLastFailureReason() {
+            return mLastFailureReason;
+        }
     }
 
     private static class TestController extends ExplicitHealthCheckController {
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index 10f27e2..b2f384a 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -45,7 +45,6 @@
     name: "FrameworksNetTests",
     defaults: ["FrameworksNetTests-jni-defaults"],
     srcs: [
-        ":tethering-tests-src",
         "java/**/*.java",
         "java/**/*.kt",
     ],
diff --git a/tests/net/AndroidManifest.xml b/tests/net/AndroidManifest.xml
index dcacb6d..638b6d1 100644
--- a/tests/net/AndroidManifest.xml
+++ b/tests/net/AndroidManifest.xml
@@ -32,7 +32,7 @@
     <uses-permission android:name="android.permission.GET_DETAILED_TASKS" />
     <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
     <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
-    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+    <uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.MANAGE_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
@@ -45,6 +45,8 @@
     <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
     <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
     <uses-permission android:name="android.permission.NETWORK_STACK" />
+    <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" />
+    <uses-permission android:name="android.permission.NETWORK_FACTORY" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
index 334b26d..25028fb 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
@@ -32,6 +32,7 @@
 import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
 import android.net.NetworkRequest
 import android.net.TestNetworkStackClient
+import android.net.TetheringManager
 import android.net.metrics.IpConnectivityLog
 import android.os.ConditionVariable
 import android.os.IBinder
@@ -48,7 +49,6 @@
 import com.android.server.connectivity.IpConnectivityMetrics
 import com.android.server.connectivity.MockableSystemProperties
 import com.android.server.connectivity.ProxyTracker
-import com.android.server.connectivity.Tethering
 import com.android.server.net.NetworkPolicyManagerInternal
 import com.android.testutils.TestableNetworkCallback
 import org.junit.After
@@ -169,8 +169,7 @@
         val deps = spy(ConnectivityService.Dependencies())
         doReturn(networkStackClient).`when`(deps).networkStack
         doReturn(metricsLogger).`when`(deps).metricsLogger
-        doReturn(mock(Tethering::class.java)).`when`(deps).makeTethering(
-                any(), any(), any(), any(), any())
+        doReturn(mock(TetheringManager::class.java)).`when`(deps).getTetheringManager()
         doReturn(mock(ProxyTracker::class.java)).`when`(deps).makeProxyTracker(any(), any())
         doReturn(mock(MockableSystemProperties::class.java)).`when`(deps).systemProperties
         doReturn(TestNetIdManager()).`when`(deps).makeNetIdManager()
diff --git a/tests/net/java/android/net/util/VersionedBroadcastListenerTest.java b/tests/net/java/android/net/util/VersionedBroadcastListenerTest.java
deleted file mode 100644
index 0d27d5b..0000000
--- a/tests/net/java/android/net/util/VersionedBroadcastListenerTest.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.util;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.reset;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.UserHandle;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.util.test.BroadcastInterceptingContext;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class VersionedBroadcastListenerTest {
-    private static final String TAG = VersionedBroadcastListenerTest.class.getSimpleName();
-    private static final String ACTION_TEST = "action.test.happy.broadcasts";
-
-    @Mock private Context mContext;
-    private BroadcastInterceptingContext mServiceContext;
-    private Handler mHandler;
-    private VersionedBroadcastListener mListener;
-    private int mCallbackCount;
-
-    private void doCallback() { mCallbackCount++; }
-
-    private class MockContext extends BroadcastInterceptingContext {
-        MockContext(Context base) {
-            super(base);
-        }
-    }
-
-    @BeforeClass
-    public static void setUpBeforeClass() throws Exception {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-    }
-
-    @Before public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        reset(mContext);
-        mServiceContext = new MockContext(mContext);
-        mHandler = new Handler(Looper.myLooper());
-        mCallbackCount = 0;
-        final IntentFilter filter = new IntentFilter();
-        filter.addAction(ACTION_TEST);
-        mListener = new VersionedBroadcastListener(
-                TAG, mServiceContext, mHandler, filter, (Intent intent) -> doCallback());
-    }
-
-    @After public void tearDown() throws Exception {
-        if (mListener != null) {
-            mListener.stopListening();
-            mListener = null;
-        }
-    }
-
-    private void sendBroadcast() {
-        final Intent intent = new Intent(ACTION_TEST);
-        mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
-    }
-
-    @Test
-    public void testBasicListening() {
-        assertEquals(0, mCallbackCount);
-        mListener.startListening();
-        for (int i = 0; i < 5; i++) {
-            sendBroadcast();
-            assertEquals(i+1, mCallbackCount);
-        }
-        mListener.stopListening();
-    }
-
-    @Test
-    public void testBroadcastsBeforeStartAreIgnored() {
-        assertEquals(0, mCallbackCount);
-        for (int i = 0; i < 5; i++) {
-            sendBroadcast();
-            assertEquals(0, mCallbackCount);
-        }
-
-        mListener.startListening();
-        sendBroadcast();
-        assertEquals(1, mCallbackCount);
-    }
-
-    @Test
-    public void testBroadcastsAfterStopAreIgnored() {
-        mListener.startListening();
-        sendBroadcast();
-        assertEquals(1, mCallbackCount);
-        mListener.stopListening();
-
-        for (int i = 0; i < 5; i++) {
-            sendBroadcast();
-            assertEquals(1, mCallbackCount);
-        }
-    }
-}
diff --git a/tests/net/java/com/android/internal/util/BitUtilsTest.java b/tests/net/java/com/android/internal/util/BitUtilsTest.java
index 01fb0df..d2fbdce 100644
--- a/tests/net/java/com/android/internal/util/BitUtilsTest.java
+++ b/tests/net/java/com/android/internal/util/BitUtilsTest.java
@@ -21,11 +21,14 @@
 import static com.android.internal.util.BitUtils.getUint16;
 import static com.android.internal.util.BitUtils.getUint32;
 import static com.android.internal.util.BitUtils.getUint8;
+import static com.android.internal.util.BitUtils.packBits;
 import static com.android.internal.util.BitUtils.uint16;
 import static com.android.internal.util.BitUtils.uint32;
 import static com.android.internal.util.BitUtils.uint8;
+import static com.android.internal.util.BitUtils.unpackBits;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -34,6 +37,8 @@
 import org.junit.runner.RunWith;
 
 import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Random;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -110,20 +115,66 @@
 
     @Test
     public void testUnsignedGetters() {
-      ByteBuffer b = ByteBuffer.allocate(4);
-      b.putInt(0xffff);
+        ByteBuffer b = ByteBuffer.allocate(4);
+        b.putInt(0xffff);
 
-      assertEquals(0x0, getUint8(b, 0));
-      assertEquals(0x0, getUint8(b, 1));
-      assertEquals(0xff, getUint8(b, 2));
-      assertEquals(0xff, getUint8(b, 3));
+        assertEquals(0x0, getUint8(b, 0));
+        assertEquals(0x0, getUint8(b, 1));
+        assertEquals(0xff, getUint8(b, 2));
+        assertEquals(0xff, getUint8(b, 3));
 
-      assertEquals(0x0, getUint16(b, 0));
-      assertEquals(0xffff, getUint16(b, 2));
+        assertEquals(0x0, getUint16(b, 0));
+        assertEquals(0xffff, getUint16(b, 2));
 
-      b.rewind();
-      b.putInt(0xffffffff);
-      assertEquals(0xffffffffL, getUint32(b, 0));
+        b.rewind();
+        b.putInt(0xffffffff);
+        assertEquals(0xffffffffL, getUint32(b, 0));
+    }
+
+    @Test
+    public void testBitsPacking() {
+        BitPackingTestCase[] testCases = {
+            new BitPackingTestCase(0, ints()),
+            new BitPackingTestCase(1, ints(0)),
+            new BitPackingTestCase(2, ints(1)),
+            new BitPackingTestCase(3, ints(0, 1)),
+            new BitPackingTestCase(4, ints(2)),
+            new BitPackingTestCase(6, ints(1, 2)),
+            new BitPackingTestCase(9, ints(0, 3)),
+            new BitPackingTestCase(~Long.MAX_VALUE, ints(63)),
+            new BitPackingTestCase(~Long.MAX_VALUE + 1, ints(0, 63)),
+            new BitPackingTestCase(~Long.MAX_VALUE + 2, ints(1, 63)),
+        };
+        for (BitPackingTestCase tc : testCases) {
+            int[] got = unpackBits(tc.packedBits);
+            assertTrue(
+                    "unpackBits("
+                            + tc.packedBits
+                            + "): expected "
+                            + Arrays.toString(tc.bits)
+                            + " but got "
+                            + Arrays.toString(got),
+                    Arrays.equals(tc.bits, got));
+        }
+        for (BitPackingTestCase tc : testCases) {
+            long got = packBits(tc.bits);
+            assertEquals(
+                    "packBits("
+                            + Arrays.toString(tc.bits)
+                            + "): expected "
+                            + tc.packedBits
+                            + " but got "
+                            + got,
+                    tc.packedBits,
+                    got);
+        }
+
+        long[] moreTestCases = {
+            0, 1, -1, 23895, -908235, Long.MAX_VALUE, Long.MIN_VALUE, new Random().nextLong(),
+        };
+        for (long l : moreTestCases) {
+            assertEquals(l, packBits(unpackBits(l)));
+        }
     }
 
     static byte[] bytes(int b1, int b2, int b3, int b4) {
@@ -133,4 +184,18 @@
     static byte b(int i) {
         return (byte) i;
     }
+
+    static int[] ints(int... array) {
+        return array;
+    }
+
+    static class BitPackingTestCase {
+        final int[] bits;
+        final long packedBits;
+
+        BitPackingTestCase(long packedBits, int[] bits) {
+            this.bits = bits;
+            this.packedBits = packedBits;
+        }
+    }
 }
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 7ea9bcf..a24426b 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -96,6 +96,7 @@
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.startsWith;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.atLeastOnce;
@@ -163,6 +164,7 @@
 import android.net.ResolverParamsParcel;
 import android.net.RouteInfo;
 import android.net.SocketKeepalive;
+import android.net.TetheringManager;
 import android.net.UidRange;
 import android.net.metrics.IpConnectivityLog;
 import android.net.shared.NetworkMonitorUtils;
@@ -197,6 +199,7 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.app.IBatteryStats;
 import com.android.internal.net.VpnConfig;
 import com.android.internal.net.VpnInfo;
 import com.android.internal.util.ArrayUtils;
@@ -210,7 +213,6 @@
 import com.android.server.connectivity.Nat464Xlat;
 import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
 import com.android.server.connectivity.ProxyTracker;
-import com.android.server.connectivity.Tethering;
 import com.android.server.connectivity.Vpn;
 import com.android.server.net.NetworkPinner;
 import com.android.server.net.NetworkPolicyManagerInternal;
@@ -305,6 +307,7 @@
     @Mock DefaultNetworkMetrics mDefaultNetworkMetrics;
     @Mock INetworkManagementService mNetworkManagementService;
     @Mock INetworkStatsService mStatsService;
+    @Mock IBatteryStats mBatteryStatsService;
     @Mock INetworkPolicyManager mNpm;
     @Mock IDnsResolver mMockDnsResolver;
     @Mock INetd mMockNetd;
@@ -1130,11 +1133,12 @@
         doReturn(new TestNetIdManager()).when(deps).makeNetIdManager();
         doReturn(mNetworkStack).when(deps).getNetworkStack();
         doReturn(systemProperties).when(deps).getSystemProperties();
-        doReturn(mock(Tethering.class)).when(deps).makeTethering(any(), any(), any(), any(), any());
+        doReturn(mock(TetheringManager.class)).when(deps).getTetheringManager();
         doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any());
         doReturn(mMetricsService).when(deps).getMetricsLogger();
         doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt());
         doReturn(mIpConnectivityMetrics).when(deps).getIpConnectivityMetrics();
+        doReturn(mBatteryStatsService).when(deps).getBatteryStatsService();
         doReturn(true).when(deps).hasService(Context.ETHERNET_SERVICE);
         doAnswer(inv -> {
             mPolicyTracker = new WrappedMultinetworkPolicyTracker(
@@ -3130,14 +3134,11 @@
                 .addTransportType(TRANSPORT_CELLULAR).build();
         final TestNetworkCallback cellCallback = new TestNetworkCallback();
         mCm.requestNetwork(cellRequest, cellCallback);
-        // NOTE: This request causes the network's capabilities to change. This
-        // is currently delivered before the onAvailable() callbacks.
-        // TODO: Fix this.
-        cellCallback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
         cellCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
         fgCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
         // Expect a network capabilities update with FOREGROUND, because the most recent
         // request causes its state to change.
+        cellCallback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
         callback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
         assertTrue(isForegroundNetwork(mCellNetworkAgent));
         assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
@@ -5640,6 +5641,37 @@
         mCm.unregisterNetworkCallback(defaultCallback);
     }
 
+    @Ignore // 40%+ flakiness : figure out why and re-enable.
+    @Test
+    public final void testBatteryStatsNetworkType() throws Exception {
+        final LinkProperties cellLp = new LinkProperties();
+        cellLp.setInterfaceName("cell0");
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
+        mCellNetworkAgent.connect(true);
+        waitForIdle();
+        verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
+                TYPE_MOBILE);
+        reset(mBatteryStatsService);
+
+        final LinkProperties wifiLp = new LinkProperties();
+        wifiLp.setInterfaceName("wifi0");
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp);
+        mWiFiNetworkAgent.connect(true);
+        waitForIdle();
+        verify(mBatteryStatsService).noteNetworkInterfaceType(wifiLp.getInterfaceName(),
+                TYPE_WIFI);
+        reset(mBatteryStatsService);
+
+        mCellNetworkAgent.disconnect();
+
+        cellLp.setInterfaceName("wifi0");
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
+        mCellNetworkAgent.connect(true);
+        waitForIdle();
+        verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
+                TYPE_MOBILE);
+    }
+
     /**
      * Make simulated InterfaceConfig for Nat464Xlat to query clat lower layer info.
      */
@@ -5680,25 +5712,28 @@
         mCm.registerNetworkCallback(networkRequest, networkCallback);
 
         // Prepare ipv6 only link properties.
-        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
-        final int cellNetId = mCellNetworkAgent.getNetwork().netId;
         final LinkProperties cellLp = new LinkProperties();
         cellLp.setInterfaceName(MOBILE_IFNAME);
         cellLp.addLinkAddress(myIpv6);
         cellLp.addRoute(new RouteInfo((IpPrefix) null, myIpv6.getAddress(), MOBILE_IFNAME));
         cellLp.addRoute(new RouteInfo(myIpv6, null, MOBILE_IFNAME));
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
         reset(mNetworkManagementService);
         reset(mMockDnsResolver);
         reset(mMockNetd);
+        reset(mBatteryStatsService);
         when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
                 .thenReturn(getClatInterfaceConfig(myIpv4));
 
         // Connect with ipv6 link properties. Expect prefix discovery to be started.
-        mCellNetworkAgent.sendLinkProperties(cellLp);
         mCellNetworkAgent.connect(true);
+        final int cellNetId = mCellNetworkAgent.getNetwork().netId;
+        waitForIdle();
 
         verify(mMockNetd, times(1)).networkCreatePhysical(eq(cellNetId), anyInt());
         verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId));
+        verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
+                TYPE_MOBILE);
 
         networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
         verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
@@ -5714,6 +5749,11 @@
         verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
         verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any());
 
+        // Make sure BatteryStats was not told about any v4- interfaces, as none should have
+        // come online yet.
+        waitForIdle();
+        verify(mBatteryStatsService, never()).noteNetworkInterfaceType(startsWith("v4-"), anyInt());
+
         verifyNoMoreInteractions(mMockNetd);
         verifyNoMoreInteractions(mMockDnsResolver);
         reset(mMockNetd);
@@ -5760,6 +5800,11 @@
         assertEquals(1, resolvrParams.servers.length);
         assertTrue(ArrayUtils.contains(resolvrParams.servers, "8.8.8.8"));
 
+        for (final LinkProperties stackedLp : stackedLpsAfterChange) {
+            verify(mBatteryStatsService).noteNetworkInterfaceType(stackedLp.getInterfaceName(),
+                    TYPE_MOBILE);
+        }
+
         // Add ipv4 address, expect that clatd and prefix discovery are stopped and stacked
         // linkproperties are cleaned up.
         cellLp.addLinkAddress(myIpv4);
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index 2738daa..39f849c 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -265,6 +265,8 @@
         assertFalse(mPermissionMonitor.hasNetworkPermission(app));
         app = systemPackageInfoWithPermissions(CONNECTIVITY_USE_RESTRICTED_NETWORKS);
         assertFalse(mPermissionMonitor.hasNetworkPermission(app));
+        app = systemPackageInfoWithPermissions(CONNECTIVITY_INTERNAL);
+        assertFalse(mPermissionMonitor.hasNetworkPermission(app));
     }
 
     @Test
@@ -274,7 +276,7 @@
                 PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
         assertTrue(hasRestrictedNetworkPermission(
                 PARTITION_SYSTEM, VERSION_P, MOCK_UID1, NETWORK_STACK));
-        assertTrue(hasRestrictedNetworkPermission(
+        assertFalse(hasRestrictedNetworkPermission(
                 PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
         assertTrue(hasRestrictedNetworkPermission(
                 PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
@@ -283,7 +285,7 @@
 
         assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
         assertFalse(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_Q, MOCK_UID1, CHANGE_WIFI_STATE));
+                PARTITION_SYSTEM, VERSION_Q, MOCK_UID1, CONNECTIVITY_INTERNAL));
     }
 
     @Test
@@ -291,14 +293,14 @@
         doReturn(VERSION_P).when(mPermissionMonitor).getDeviceFirstSdkInt();
         assertTrue(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
         assertTrue(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CHANGE_WIFI_STATE));
+                PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_INTERNAL));
         assertTrue(hasRestrictedNetworkPermission(
                 PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
 
         doReturn(VERSION_Q).when(mPermissionMonitor).getDeviceFirstSdkInt();
         assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
         assertFalse(hasRestrictedNetworkPermission(
-                PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CHANGE_WIFI_STATE));
+                PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_INTERNAL));
         assertTrue(hasRestrictedNetworkPermission(
                 PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
     }
@@ -319,7 +321,7 @@
 
         assertFalse(hasRestrictedNetworkPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
         assertFalse(hasRestrictedNetworkPermission(
-                PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_WIFI_STATE));
+                PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CONNECTIVITY_INTERNAL));
         assertFalse(hasRestrictedNetworkPermission(
                 PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_NETWORK_STATE));
     }
@@ -337,7 +339,7 @@
     public void testHasUseBackgroundNetworksPermission() throws Exception {
         assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(SYSTEM_UID));
         assertBackgroundPermission(false, SYSTEM_PACKAGE1, SYSTEM_UID);
-        assertBackgroundPermission(false, SYSTEM_PACKAGE1, SYSTEM_UID, CHANGE_WIFI_STATE);
+        assertBackgroundPermission(false, SYSTEM_PACKAGE1, SYSTEM_UID, CONNECTIVITY_INTERNAL);
         assertBackgroundPermission(true, SYSTEM_PACKAGE1, SYSTEM_UID, CHANGE_NETWORK_STATE);
         assertBackgroundPermission(true, SYSTEM_PACKAGE1, SYSTEM_UID, NETWORK_STACK);
 
@@ -348,8 +350,9 @@
 
         assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID2));
         assertBackgroundPermission(false, MOCK_PACKAGE2, MOCK_UID2);
-        assertBackgroundPermission(true, MOCK_PACKAGE2, MOCK_UID2,
+        assertBackgroundPermission(false, MOCK_PACKAGE2, MOCK_UID2,
                 CONNECTIVITY_INTERNAL);
+        assertBackgroundPermission(true, MOCK_PACKAGE2, MOCK_UID2, NETWORK_STACK);
     }
 
     private class NetdMonitor {
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
deleted file mode 100644
index 9e5717b..0000000
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ /dev/null
@@ -1,1206 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.hardware.usb.UsbManager.USB_CONFIGURED;
-import static android.hardware.usb.UsbManager.USB_CONNECTED;
-import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
-import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
-import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY;
-import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER;
-import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER;
-import static android.net.ConnectivityManager.TETHERING_USB;
-import static android.net.ConnectivityManager.TETHERING_WIFI;
-import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
-import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
-import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
-import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
-import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
-import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY;
-import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
-import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
-import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER;
-import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.notNull;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.res.Resources;
-import android.hardware.usb.UsbManager;
-import android.net.INetd;
-import android.net.INetworkPolicyManager;
-import android.net.INetworkStatsService;
-import android.net.ITetheringEventCallback;
-import android.net.InterfaceConfiguration;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.MacAddress;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkState;
-import android.net.NetworkUtils;
-import android.net.RouteInfo;
-import android.net.dhcp.DhcpServerCallbacks;
-import android.net.dhcp.DhcpServingParamsParcel;
-import android.net.dhcp.IDhcpServer;
-import android.net.ip.IpServer;
-import android.net.ip.RouterAdvertisementDaemon;
-import android.net.util.InterfaceParams;
-import android.net.util.NetworkConstants;
-import android.net.util.SharedLog;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiManager;
-import android.net.wifi.p2p.WifiP2pGroup;
-import android.net.wifi.p2p.WifiP2pInfo;
-import android.net.wifi.p2p.WifiP2pManager;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.INetworkManagementService;
-import android.os.PersistableBundle;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.os.test.TestLooper;
-import android.provider.Settings;
-import android.telephony.CarrierConfigManager;
-import android.telephony.PhoneStateListener;
-import android.telephony.TelephonyManager;
-import android.test.mock.MockContentResolver;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.StateMachine;
-import com.android.internal.util.test.BroadcastInterceptingContext;
-import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
-import com.android.server.connectivity.tethering.OffloadHardwareInterface;
-import com.android.server.connectivity.tethering.TetheringConfiguration;
-import com.android.server.connectivity.tethering.TetheringDependencies;
-import com.android.server.connectivity.tethering.UpstreamNetworkMonitor;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Vector;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class TetheringTest {
-    private static final int IFINDEX_OFFSET = 100;
-
-    private static final String TEST_MOBILE_IFNAME = "test_rmnet_data0";
-    private static final String TEST_XLAT_MOBILE_IFNAME = "v4-test_rmnet_data0";
-    private static final String TEST_USB_IFNAME = "test_rndis0";
-    private static final String TEST_WLAN_IFNAME = "test_wlan0";
-    private static final String TEST_P2P_IFNAME = "test_p2p-p2p0-0";
-
-    private static final int DHCPSERVER_START_TIMEOUT_MS = 1000;
-
-    @Mock private ApplicationInfo mApplicationInfo;
-    @Mock private Context mContext;
-    @Mock private INetworkManagementService mNMService;
-    @Mock private INetworkStatsService mStatsService;
-    @Mock private INetworkPolicyManager mPolicyManager;
-    @Mock private MockableSystemProperties mSystemProperties;
-    @Mock private OffloadHardwareInterface mOffloadHardwareInterface;
-    @Mock private Resources mResources;
-    @Mock private TelephonyManager mTelephonyManager;
-    @Mock private UsbManager mUsbManager;
-    @Mock private WifiManager mWifiManager;
-    @Mock private CarrierConfigManager mCarrierConfigManager;
-    @Mock private UpstreamNetworkMonitor mUpstreamNetworkMonitor;
-    @Mock private IPv6TetheringCoordinator mIPv6TetheringCoordinator;
-    @Mock private RouterAdvertisementDaemon mRouterAdvertisementDaemon;
-    @Mock private IDhcpServer mDhcpServer;
-    @Mock private INetd mNetd;
-
-    private final MockIpServerDependencies mIpServerDependencies =
-            spy(new MockIpServerDependencies());
-    private final MockTetheringDependencies mTetheringDependencies =
-            new MockTetheringDependencies();
-
-    // Like so many Android system APIs, these cannot be mocked because it is marked final.
-    // We have to use the real versions.
-    private final PersistableBundle mCarrierConfig = new PersistableBundle();
-    private final TestLooper mLooper = new TestLooper();
-
-    private Vector<Intent> mIntents;
-    private BroadcastInterceptingContext mServiceContext;
-    private MockContentResolver mContentResolver;
-    private BroadcastReceiver mBroadcastReceiver;
-    private Tethering mTethering;
-    private PhoneStateListener mPhoneStateListener;
-
-    private class MockContext extends BroadcastInterceptingContext {
-        MockContext(Context base) {
-            super(base);
-        }
-
-        @Override
-        public ApplicationInfo getApplicationInfo() { return mApplicationInfo; }
-
-        @Override
-        public ContentResolver getContentResolver() { return mContentResolver; }
-
-        @Override
-        public String getPackageName() { return "TetheringTest"; }
-
-        @Override
-        public Resources getResources() { return mResources; }
-
-        @Override
-        public Object getSystemService(String name) {
-            if (Context.WIFI_SERVICE.equals(name)) return mWifiManager;
-            if (Context.USB_SERVICE.equals(name)) return mUsbManager;
-            if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager;
-            return super.getSystemService(name);
-        }
-
-        @Override
-        public String getSystemServiceName(Class<?> serviceClass) {
-            if (TelephonyManager.class.equals(serviceClass)) return Context.TELEPHONY_SERVICE;
-            return super.getSystemServiceName(serviceClass);
-        }
-    }
-
-    public class MockIpServerDependencies extends IpServer.Dependencies {
-        @Override
-        public RouterAdvertisementDaemon getRouterAdvertisementDaemon(
-                InterfaceParams ifParams) {
-            return mRouterAdvertisementDaemon;
-        }
-
-        @Override
-        public InterfaceParams getInterfaceParams(String ifName) {
-            assertTrue("Non-mocked interface " + ifName,
-                    ifName.equals(TEST_USB_IFNAME)
-                            || ifName.equals(TEST_WLAN_IFNAME)
-                            || ifName.equals(TEST_MOBILE_IFNAME)
-                            || ifName.equals(TEST_P2P_IFNAME));
-            final String[] ifaces = new String[] {
-                    TEST_USB_IFNAME, TEST_WLAN_IFNAME, TEST_MOBILE_IFNAME, TEST_P2P_IFNAME};
-            return new InterfaceParams(ifName, ArrayUtils.indexOf(ifaces, ifName) + IFINDEX_OFFSET,
-                    MacAddress.ALL_ZEROS_ADDRESS);
-        }
-
-        @Override
-        public INetd getNetdService() {
-            return mNetd;
-        }
-
-        @Override
-        public void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
-                DhcpServerCallbacks cb) {
-            new Thread(() -> {
-                try {
-                    cb.onDhcpServerCreated(STATUS_SUCCESS, mDhcpServer);
-                } catch (RemoteException e) {
-                    fail(e.getMessage());
-                }
-            }).run();
-        }
-    }
-
-    private class MockTetheringConfiguration extends TetheringConfiguration {
-        MockTetheringConfiguration(Context ctx, SharedLog log, int id) {
-            super(ctx, log, id);
-        }
-
-        @Override
-        protected Resources getResourcesForSubIdWrapper(Context ctx, int subId) {
-            return mResources;
-        }
-    }
-
-    public class MockTetheringDependencies extends TetheringDependencies {
-        StateMachine upstreamNetworkMonitorMasterSM;
-        ArrayList<IpServer> ipv6CoordinatorNotifyList;
-        int isTetheringSupportedCalls;
-
-        public void reset() {
-            upstreamNetworkMonitorMasterSM = null;
-            ipv6CoordinatorNotifyList = null;
-            isTetheringSupportedCalls = 0;
-        }
-
-        @Override
-        public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) {
-            return mOffloadHardwareInterface;
-        }
-
-        @Override
-        public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx,
-                StateMachine target, SharedLog log, int what) {
-            upstreamNetworkMonitorMasterSM = target;
-            return mUpstreamNetworkMonitor;
-        }
-
-        @Override
-        public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
-                ArrayList<IpServer> notifyList, SharedLog log) {
-            ipv6CoordinatorNotifyList = notifyList;
-            return mIPv6TetheringCoordinator;
-        }
-
-        @Override
-        public IpServer.Dependencies getIpServerDependencies() {
-            return mIpServerDependencies;
-        }
-
-        @Override
-        public boolean isTetheringSupported() {
-            isTetheringSupportedCalls++;
-            return true;
-        }
-
-        @Override
-        public TetheringConfiguration generateTetheringConfiguration(Context ctx, SharedLog log,
-                int subId) {
-            return new MockTetheringConfiguration(ctx, log, subId);
-        }
-    }
-
-    private static NetworkState buildMobileUpstreamState(boolean withIPv4, boolean withIPv6,
-            boolean with464xlat) {
-        final NetworkInfo info = new NetworkInfo(TYPE_MOBILE, 0, null, null);
-        info.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
-        final LinkProperties prop = new LinkProperties();
-        prop.setInterfaceName(TEST_MOBILE_IFNAME);
-
-        if (withIPv4) {
-            prop.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0),
-                    NetworkUtils.numericToInetAddress("10.0.0.1"), TEST_MOBILE_IFNAME));
-        }
-
-        if (withIPv6) {
-            prop.addDnsServer(NetworkUtils.numericToInetAddress("2001:db8::2"));
-            prop.addLinkAddress(
-                    new LinkAddress(NetworkUtils.numericToInetAddress("2001:db8::"),
-                            NetworkConstants.RFC7421_PREFIX_LENGTH));
-            prop.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0),
-                    NetworkUtils.numericToInetAddress("2001:db8::1"), TEST_MOBILE_IFNAME));
-        }
-
-        if (with464xlat) {
-            final LinkProperties stackedLink = new LinkProperties();
-            stackedLink.setInterfaceName(TEST_XLAT_MOBILE_IFNAME);
-            stackedLink.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0),
-                    NetworkUtils.numericToInetAddress("192.0.0.1"), TEST_XLAT_MOBILE_IFNAME));
-
-            prop.addStackedLink(stackedLink);
-        }
-
-
-        final NetworkCapabilities capabilities = new NetworkCapabilities()
-                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);;
-        return new NetworkState(info, prop, capabilities, new Network(100), null, "netid");
-    }
-
-    private static NetworkState buildMobileIPv4UpstreamState() {
-        return buildMobileUpstreamState(true, false, false);
-    }
-
-    private static NetworkState buildMobileIPv6UpstreamState() {
-        return buildMobileUpstreamState(false, true, false);
-    }
-
-    private static NetworkState buildMobileDualStackUpstreamState() {
-        return buildMobileUpstreamState(true, true, false);
-    }
-
-    private static NetworkState buildMobile464xlatUpstreamState() {
-        return buildMobileUpstreamState(false, true, true);
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        when(mResources.getStringArray(com.android.internal.R.array.config_tether_dhcp_range))
-                .thenReturn(new String[0]);
-        when(mResources.getStringArray(com.android.internal.R.array.config_tether_usb_regexs))
-                .thenReturn(new String[] { "test_rndis\\d" });
-        when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_regexs))
-                .thenReturn(new String[]{ "test_wlan\\d" });
-        when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_p2p_regexs))
-                .thenReturn(new String[]{ "test_p2p-p2p\\d-.*" });
-        when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs))
-                .thenReturn(new String[0]);
-        when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
-                .thenReturn(new int[0]);
-        when(mResources.getBoolean(com.android.internal.R.bool.config_tether_upstream_automatic))
-                .thenReturn(false);
-        when(mNMService.listInterfaces())
-                .thenReturn(new String[] {
-                        TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME, TEST_P2P_IFNAME});
-        when(mNMService.getInterfaceConfig(anyString()))
-                .thenReturn(new InterfaceConfiguration());
-        when(mRouterAdvertisementDaemon.start())
-                .thenReturn(true);
-
-        mServiceContext = new MockContext(mContext);
-        mContentResolver = new MockContentResolver(mServiceContext);
-        mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
-        Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 0);
-        mIntents = new Vector<>();
-        mBroadcastReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                mIntents.addElement(intent);
-            }
-        };
-        mServiceContext.registerReceiver(mBroadcastReceiver,
-                new IntentFilter(ACTION_TETHER_STATE_CHANGED));
-        mTetheringDependencies.reset();
-        mTethering = makeTethering();
-        verify(mNMService).registerTetheringStatsProvider(any(), anyString());
-        final ArgumentCaptor<PhoneStateListener> phoneListenerCaptor =
-                ArgumentCaptor.forClass(PhoneStateListener.class);
-        verify(mTelephonyManager).listen(phoneListenerCaptor.capture(),
-                eq(PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE));
-        mPhoneStateListener = phoneListenerCaptor.getValue();
-    }
-
-    private Tethering makeTethering() {
-        return new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
-                mLooper.getLooper(), mSystemProperties,
-                mTetheringDependencies);
-    }
-
-    @After
-    public void tearDown() {
-        mServiceContext.unregisterReceiver(mBroadcastReceiver);
-    }
-
-    private void sendWifiApStateChanged(int state) {
-        final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
-        intent.putExtra(EXTRA_WIFI_AP_STATE, state);
-        mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
-    }
-
-    private void sendWifiApStateChanged(int state, String ifname, int ipmode) {
-        final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
-        intent.putExtra(EXTRA_WIFI_AP_STATE, state);
-        intent.putExtra(EXTRA_WIFI_AP_INTERFACE_NAME, ifname);
-        intent.putExtra(EXTRA_WIFI_AP_MODE, ipmode);
-        mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
-    }
-
-    private static final String[] P2P_RECEIVER_PERMISSIONS_FOR_BROADCAST = {
-            android.Manifest.permission.ACCESS_FINE_LOCATION,
-            android.Manifest.permission.ACCESS_WIFI_STATE
-    };
-
-    private void sendWifiP2pConnectionChanged(
-            boolean isGroupFormed, boolean isGroupOwner, String ifname) {
-        WifiP2pInfo p2pInfo = new WifiP2pInfo();
-        p2pInfo.groupFormed = isGroupFormed;
-        p2pInfo.isGroupOwner = isGroupOwner;
-
-        NetworkInfo networkInfo = new NetworkInfo(TYPE_WIFI_P2P, 0, null, null);
-
-        WifiP2pGroup group = new WifiP2pGroup();
-        group.setIsGroupOwner(isGroupOwner);
-        group.setInterface(ifname);
-
-        final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
-        intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, p2pInfo);
-        intent.putExtra(WifiP2pManager.EXTRA_NETWORK_INFO, networkInfo);
-        intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, group);
-        mServiceContext.sendBroadcastAsUserMultiplePermissions(intent, UserHandle.ALL,
-                P2P_RECEIVER_PERMISSIONS_FOR_BROADCAST);
-    }
-
-    private void sendUsbBroadcast(boolean connected, boolean configured, boolean rndisFunction) {
-        final Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
-        intent.putExtra(USB_CONNECTED, connected);
-        intent.putExtra(USB_CONFIGURED, configured);
-        intent.putExtra(USB_FUNCTION_RNDIS, rndisFunction);
-        mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
-    }
-
-    private void sendConfigurationChanged() {
-        final Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
-        mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
-    }
-
-    private void verifyInterfaceServingModeStarted(String ifname) throws Exception {
-        verify(mNMService, times(1)).getInterfaceConfig(ifname);
-        verify(mNMService, times(1))
-                .setInterfaceConfig(eq(ifname), any(InterfaceConfiguration.class));
-        verify(mNMService, times(1)).tetherInterface(ifname);
-    }
-
-    private void verifyTetheringBroadcast(String ifname, String whichExtra) {
-        // Verify that ifname is in the whichExtra array of the tether state changed broadcast.
-        final Intent bcast = mIntents.get(0);
-        assertEquals(ACTION_TETHER_STATE_CHANGED, bcast.getAction());
-        final ArrayList<String> ifnames = bcast.getStringArrayListExtra(whichExtra);
-        assertTrue(ifnames.contains(ifname));
-        mIntents.remove(bcast);
-    }
-
-    public void failingLocalOnlyHotspotLegacyApBroadcast(
-            boolean emulateInterfaceStatusChanged) throws Exception {
-        // Emulate externally-visible WifiManager effects, causing the
-        // per-interface state machine to start up, and telling us that
-        // hotspot mode is to be started.
-        if (emulateInterfaceStatusChanged) {
-            mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
-        }
-        sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
-        mLooper.dispatchAll();
-
-        // If, and only if, Tethering received an interface status changed then
-        // it creates a IpServer and sends out a broadcast indicating that the
-        // interface is "available".
-        if (emulateInterfaceStatusChanged) {
-            assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls);
-            verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
-            verify(mWifiManager).updateInterfaceIpState(
-                    TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
-        }
-        verifyNoMoreInteractions(mNMService);
-        verifyNoMoreInteractions(mWifiManager);
-    }
-
-    private void prepareUsbTethering(NetworkState upstreamState) {
-        when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
-        when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
-                .thenReturn(upstreamState);
-
-        // Emulate pressing the USB tethering button in Settings UI.
-        mTethering.startTethering(TETHERING_USB, null, false);
-        mLooper.dispatchAll();
-        verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
-
-        mTethering.interfaceStatusChanged(TEST_USB_IFNAME, true);
-    }
-
-    @Test
-    public void testUsbConfiguredBroadcastStartsTethering() throws Exception {
-        NetworkState upstreamState = buildMobileIPv4UpstreamState();
-        prepareUsbTethering(upstreamState);
-
-        // This should produce no activity of any kind.
-        verifyNoMoreInteractions(mNMService);
-
-        // Pretend we then receive USB configured broadcast.
-        sendUsbBroadcast(true, true, true);
-        mLooper.dispatchAll();
-        // Now we should see the start of tethering mechanics (in this case:
-        // tetherMatchingInterfaces() which starts by fetching all interfaces).
-        verify(mNMService, times(1)).listInterfaces();
-
-        // UpstreamNetworkMonitor should receive selected upstream
-        verify(mUpstreamNetworkMonitor, times(1)).selectPreferredUpstreamType(any());
-        verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(upstreamState.network);
-    }
-
-    @Test
-    public void failingLocalOnlyHotspotLegacyApBroadcastWithIfaceStatusChanged() throws Exception {
-        failingLocalOnlyHotspotLegacyApBroadcast(true);
-    }
-
-    @Test
-    public void failingLocalOnlyHotspotLegacyApBroadcastSansIfaceStatusChanged() throws Exception {
-        failingLocalOnlyHotspotLegacyApBroadcast(false);
-    }
-
-    public void workingLocalOnlyHotspotEnrichedApBroadcast(
-            boolean emulateInterfaceStatusChanged) throws Exception {
-        // Emulate externally-visible WifiManager effects, causing the
-        // per-interface state machine to start up, and telling us that
-        // hotspot mode is to be started.
-        if (emulateInterfaceStatusChanged) {
-            mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
-        }
-        sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_LOCAL_ONLY);
-        mLooper.dispatchAll();
-
-        verifyInterfaceServingModeStarted(TEST_WLAN_IFNAME);
-        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
-        verify(mNMService, times(1)).setIpForwardingEnabled(true);
-        verify(mNMService, times(1)).startTethering(any(String[].class));
-        verifyNoMoreInteractions(mNMService);
-        verify(mWifiManager).updateInterfaceIpState(
-                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
-        verify(mWifiManager).updateInterfaceIpState(
-                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
-        verifyNoMoreInteractions(mWifiManager);
-        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY);
-        verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks();
-        // This will be called twice, one is on entering IpServer.STATE_AVAILABLE,
-        // and another one is on IpServer.STATE_TETHERED/IpServer.STATE_LOCAL_ONLY.
-        assertEquals(2, mTetheringDependencies.isTetheringSupportedCalls);
-
-        // Emulate externally-visible WifiManager effects, when hotspot mode
-        // is being torn down.
-        sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
-        mTethering.interfaceRemoved(TEST_WLAN_IFNAME);
-        mLooper.dispatchAll();
-
-        verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
-        // {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4.
-        verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME);
-        verify(mNMService, times(2))
-                .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
-        verify(mNMService, times(1)).stopTethering();
-        verify(mNMService, times(1)).setIpForwardingEnabled(false);
-        verify(mWifiManager, times(3)).updateInterfaceIpState(
-                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
-        verifyNoMoreInteractions(mNMService);
-        verifyNoMoreInteractions(mWifiManager);
-        // Asking for the last error after the per-interface state machine
-        // has been reaped yields an unknown interface error.
-        assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_WLAN_IFNAME));
-    }
-
-    /**
-     * Send CMD_IPV6_TETHER_UPDATE to IpServers as would be done by IPv6TetheringCoordinator.
-     */
-    private void sendIPv6TetherUpdates(NetworkState upstreamState) {
-        // IPv6TetheringCoordinator must have been notified of downstream
-        verify(mIPv6TetheringCoordinator, times(1)).addActiveDownstream(
-                argThat(sm -> sm.linkProperties().getInterfaceName().equals(TEST_USB_IFNAME)),
-                eq(IpServer.STATE_TETHERED));
-
-        for (IpServer ipSrv :
-                mTetheringDependencies.ipv6CoordinatorNotifyList) {
-            NetworkState ipv6OnlyState = buildMobileUpstreamState(false, true, false);
-            ipSrv.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0,
-                    upstreamState.linkProperties.isIpv6Provisioned()
-                            ? ipv6OnlyState.linkProperties
-                            : null);
-        }
-        mLooper.dispatchAll();
-    }
-
-    private void runUsbTethering(NetworkState upstreamState) {
-        prepareUsbTethering(upstreamState);
-        sendUsbBroadcast(true, true, true);
-        mLooper.dispatchAll();
-    }
-
-    @Test
-    public void workingMobileUsbTethering_IPv4() throws Exception {
-        NetworkState upstreamState = buildMobileIPv4UpstreamState();
-        runUsbTethering(upstreamState);
-
-        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
-        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
-
-        sendIPv6TetherUpdates(upstreamState);
-        verify(mRouterAdvertisementDaemon, never()).buildNewRa(any(), notNull());
-        verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
-    }
-
-    @Test
-    public void workingMobileUsbTethering_IPv4LegacyDhcp() {
-        Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 1);
-        mTethering = makeTethering();
-        final NetworkState upstreamState = buildMobileIPv4UpstreamState();
-        runUsbTethering(upstreamState);
-        sendIPv6TetherUpdates(upstreamState);
-
-        verify(mIpServerDependencies, never()).makeDhcpServer(any(), any(), any());
-    }
-
-    @Test
-    public void workingMobileUsbTethering_IPv6() throws Exception {
-        NetworkState upstreamState = buildMobileIPv6UpstreamState();
-        runUsbTethering(upstreamState);
-
-        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
-        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
-
-        sendIPv6TetherUpdates(upstreamState);
-        verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
-        verify(mNetd, times(1)).tetherApplyDnsInterfaces();
-    }
-
-    @Test
-    public void workingMobileUsbTethering_DualStack() throws Exception {
-        NetworkState upstreamState = buildMobileDualStackUpstreamState();
-        runUsbTethering(upstreamState);
-
-        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
-        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
-        verify(mRouterAdvertisementDaemon, times(1)).start();
-        verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
-
-        sendIPv6TetherUpdates(upstreamState);
-        verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
-        verify(mNetd, times(1)).tetherApplyDnsInterfaces();
-    }
-
-    @Test
-    public void workingMobileUsbTethering_MultipleUpstreams() throws Exception {
-        NetworkState upstreamState = buildMobile464xlatUpstreamState();
-        runUsbTethering(upstreamState);
-
-        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
-        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
-        verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
-        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
-        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME,
-                TEST_XLAT_MOBILE_IFNAME);
-
-        sendIPv6TetherUpdates(upstreamState);
-        verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
-        verify(mNetd, times(1)).tetherApplyDnsInterfaces();
-    }
-
-    @Test
-    public void workingMobileUsbTethering_v6Then464xlat() throws Exception {
-        // Setup IPv6
-        NetworkState upstreamState = buildMobileIPv6UpstreamState();
-        runUsbTethering(upstreamState);
-
-        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
-        verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
-        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
-
-        // Then 464xlat comes up
-        upstreamState = buildMobile464xlatUpstreamState();
-        when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
-                .thenReturn(upstreamState);
-
-        // Upstream LinkProperties changed: UpstreamNetworkMonitor sends EVENT_ON_LINKPROPERTIES.
-        mTetheringDependencies.upstreamNetworkMonitorMasterSM.sendMessage(
-                Tethering.TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
-                UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES,
-                0,
-                upstreamState);
-        mLooper.dispatchAll();
-
-        // Forwarding is added for 464xlat
-        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
-        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME,
-                TEST_XLAT_MOBILE_IFNAME);
-        // Forwarding was not re-added for v6 (still times(1))
-        verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
-        verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
-        // DHCP not restarted on downstream (still times(1))
-        verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
-    }
-
-    @Test
-    public void configTetherUpstreamAutomaticIgnoresConfigTetherUpstreamTypes() throws Exception {
-        when(mResources.getBoolean(com.android.internal.R.bool.config_tether_upstream_automatic))
-                .thenReturn(true);
-        sendConfigurationChanged();
-
-        // Setup IPv6
-        final NetworkState upstreamState = buildMobileIPv6UpstreamState();
-        runUsbTethering(upstreamState);
-
-        // UpstreamNetworkMonitor should choose upstream automatically
-        // (in this specific case: choose the default network).
-        verify(mUpstreamNetworkMonitor, times(1)).getCurrentPreferredUpstream();
-        verify(mUpstreamNetworkMonitor, never()).selectPreferredUpstreamType(any());
-
-        verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(upstreamState.network);
-    }
-
-    @Test
-    public void workingLocalOnlyHotspotEnrichedApBroadcastWithIfaceChanged() throws Exception {
-        workingLocalOnlyHotspotEnrichedApBroadcast(true);
-    }
-
-    @Test
-    public void workingLocalOnlyHotspotEnrichedApBroadcastSansIfaceChanged() throws Exception {
-        workingLocalOnlyHotspotEnrichedApBroadcast(false);
-    }
-
-    // TODO: Test with and without interfaceStatusChanged().
-    @Test
-    public void failingWifiTetheringLegacyApBroadcast() throws Exception {
-        when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
-
-        // Emulate pressing the WiFi tethering button.
-        mTethering.startTethering(TETHERING_WIFI, null, false);
-        mLooper.dispatchAll();
-        verify(mWifiManager, times(1)).startSoftAp(null);
-        verifyNoMoreInteractions(mWifiManager);
-        verifyNoMoreInteractions(mNMService);
-
-        // Emulate externally-visible WifiManager effects, causing the
-        // per-interface state machine to start up, and telling us that
-        // tethering mode is to be started.
-        mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
-        sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
-        mLooper.dispatchAll();
-
-        assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls);
-        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
-        verify(mWifiManager).updateInterfaceIpState(
-                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
-        verifyNoMoreInteractions(mNMService);
-        verifyNoMoreInteractions(mWifiManager);
-    }
-
-    // TODO: Test with and without interfaceStatusChanged().
-    @Test
-    public void workingWifiTetheringEnrichedApBroadcast() throws Exception {
-        when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
-
-        // Emulate pressing the WiFi tethering button.
-        mTethering.startTethering(TETHERING_WIFI, null, false);
-        mLooper.dispatchAll();
-        verify(mWifiManager, times(1)).startSoftAp(null);
-        verifyNoMoreInteractions(mWifiManager);
-        verifyNoMoreInteractions(mNMService);
-
-        // Emulate externally-visible WifiManager effects, causing the
-        // per-interface state machine to start up, and telling us that
-        // tethering mode is to be started.
-        mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
-        sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
-        mLooper.dispatchAll();
-
-        verifyInterfaceServingModeStarted(TEST_WLAN_IFNAME);
-        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
-        verify(mNMService, times(1)).setIpForwardingEnabled(true);
-        verify(mNMService, times(1)).startTethering(any(String[].class));
-        verifyNoMoreInteractions(mNMService);
-        verify(mWifiManager).updateInterfaceIpState(
-                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
-        verify(mWifiManager).updateInterfaceIpState(
-                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
-        verifyNoMoreInteractions(mWifiManager);
-        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_TETHER);
-        verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks();
-        // In tethering mode, in the default configuration, an explicit request
-        // for a mobile network is also made.
-        verify(mUpstreamNetworkMonitor, times(1)).registerMobileNetworkRequest();
-        // This will be called twice, one is on entering IpServer.STATE_AVAILABLE,
-        // and another one is on IpServer.STATE_TETHERED/IpServer.STATE_LOCAL_ONLY.
-        assertEquals(2, mTetheringDependencies.isTetheringSupportedCalls);
-
-        /////
-        // We do not currently emulate any upstream being found.
-        //
-        // This is why there are no calls to verify mNMService.enableNat() or
-        // mNMService.startInterfaceForwarding().
-        /////
-
-        // Emulate pressing the WiFi tethering button.
-        mTethering.stopTethering(TETHERING_WIFI);
-        mLooper.dispatchAll();
-        verify(mWifiManager, times(1)).stopSoftAp();
-        verifyNoMoreInteractions(mWifiManager);
-        verifyNoMoreInteractions(mNMService);
-
-        // Emulate externally-visible WifiManager effects, when tethering mode
-        // is being torn down.
-        sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
-        mTethering.interfaceRemoved(TEST_WLAN_IFNAME);
-        mLooper.dispatchAll();
-
-        verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
-        // {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4.
-        verify(mNMService, atLeastOnce()).getInterfaceConfig(TEST_WLAN_IFNAME);
-        verify(mNMService, atLeastOnce())
-                .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
-        verify(mNMService, times(1)).stopTethering();
-        verify(mNMService, times(1)).setIpForwardingEnabled(false);
-        verify(mWifiManager, times(3)).updateInterfaceIpState(
-                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
-        verifyNoMoreInteractions(mNMService);
-        verifyNoMoreInteractions(mWifiManager);
-        // Asking for the last error after the per-interface state machine
-        // has been reaped yields an unknown interface error.
-        assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_WLAN_IFNAME));
-    }
-
-    // TODO: Test with and without interfaceStatusChanged().
-    @Test
-    public void failureEnablingIpForwarding() throws Exception {
-        when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
-        doThrow(new RemoteException()).when(mNMService).setIpForwardingEnabled(true);
-
-        // Emulate pressing the WiFi tethering button.
-        mTethering.startTethering(TETHERING_WIFI, null, false);
-        mLooper.dispatchAll();
-        verify(mWifiManager, times(1)).startSoftAp(null);
-        verifyNoMoreInteractions(mWifiManager);
-        verifyNoMoreInteractions(mNMService);
-
-        // Emulate externally-visible WifiManager effects, causing the
-        // per-interface state machine to start up, and telling us that
-        // tethering mode is to be started.
-        mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
-        sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
-        mLooper.dispatchAll();
-
-        // We verify get/set called thrice here: twice for setup (on NMService) and once during
-        // teardown (on Netd) because all events happen over the course of the single
-        // dispatchAll() above. Note that once the IpServer IPv4 address config
-        // code is refactored the two calls during shutdown will revert to one.
-        verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME);
-        verify(mNMService, times(2))
-                .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
-        verify(mNetd, times(1)).interfaceSetCfg(argThat(p -> TEST_WLAN_IFNAME.equals(p.ifName)));
-        verify(mNMService, times(1)).tetherInterface(TEST_WLAN_IFNAME);
-        verify(mWifiManager).updateInterfaceIpState(
-                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
-        verify(mWifiManager).updateInterfaceIpState(
-                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
-        // There are 3 state change event:
-        // AVAILABLE -> STATE_TETHERED -> STATE_AVAILABLE.
-        assertEquals(3, mTetheringDependencies.isTetheringSupportedCalls);
-        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
-        // This is called, but will throw.
-        verify(mNMService, times(1)).setIpForwardingEnabled(true);
-        // This never gets called because of the exception thrown above.
-        verify(mNMService, times(0)).startTethering(any(String[].class));
-        // When the master state machine transitions to an error state it tells
-        // downstream interfaces, which causes us to tell Wi-Fi about the error
-        // so it can take down AP mode.
-        verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
-        verify(mWifiManager).updateInterfaceIpState(
-                TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR);
-
-        verifyNoMoreInteractions(mWifiManager);
-        verifyNoMoreInteractions(mNMService);
-    }
-
-    private void userRestrictionsListenerBehaviour(
-        boolean currentDisallow, boolean nextDisallow, String[] activeTetheringIfacesList,
-        int expectedInteractionsWithShowNotification) throws  Exception {
-        final int userId = 0;
-        final Bundle currRestrictions = new Bundle();
-        final Bundle newRestrictions = new Bundle();
-        Tethering tethering = mock(Tethering.class);
-        Tethering.TetheringUserRestrictionListener turl =
-                new Tethering.TetheringUserRestrictionListener(tethering);
-
-        currRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_TETHERING, currentDisallow);
-        newRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_TETHERING, nextDisallow);
-        when(tethering.getTetheredIfaces()).thenReturn(activeTetheringIfacesList);
-
-        turl.onUserRestrictionsChanged(userId, newRestrictions, currRestrictions);
-
-        verify(tethering, times(expectedInteractionsWithShowNotification))
-                .showTetheredNotification(anyInt(), eq(false));
-
-        verify(tethering, times(expectedInteractionsWithShowNotification)).untetherAll();
-    }
-
-    @Test
-    public void testDisallowTetheringWhenNoTetheringInterfaceIsActive() throws Exception {
-        final String[] emptyActiveIfacesList = new String[]{};
-        final boolean currDisallow = false;
-        final boolean nextDisallow = true;
-        final int expectedInteractionsWithShowNotification = 0;
-
-        userRestrictionsListenerBehaviour(currDisallow, nextDisallow, emptyActiveIfacesList,
-                expectedInteractionsWithShowNotification);
-    }
-
-    @Test
-    public void testDisallowTetheringWhenAtLeastOneTetheringInterfaceIsActive() throws Exception {
-        final String[] nonEmptyActiveIfacesList = new String[]{TEST_WLAN_IFNAME};
-        final boolean currDisallow = false;
-        final boolean nextDisallow = true;
-        final int expectedInteractionsWithShowNotification = 1;
-
-        userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
-                expectedInteractionsWithShowNotification);
-    }
-
-    @Test
-    public void testAllowTetheringWhenNoTetheringInterfaceIsActive() throws Exception {
-        final String[] nonEmptyActiveIfacesList = new String[]{};
-        final boolean currDisallow = true;
-        final boolean nextDisallow = false;
-        final int expectedInteractionsWithShowNotification = 0;
-
-        userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
-                expectedInteractionsWithShowNotification);
-    }
-
-    @Test
-    public void testAllowTetheringWhenAtLeastOneTetheringInterfaceIsActive() throws Exception {
-        final String[] nonEmptyActiveIfacesList = new String[]{TEST_WLAN_IFNAME};
-        final boolean currDisallow = true;
-        final boolean nextDisallow = false;
-        final int expectedInteractionsWithShowNotification = 0;
-
-        userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
-                expectedInteractionsWithShowNotification);
-    }
-
-    @Test
-    public void testDisallowTetheringUnchanged() throws Exception {
-        final String[] nonEmptyActiveIfacesList = new String[]{TEST_WLAN_IFNAME};
-        final int expectedInteractionsWithShowNotification = 0;
-        boolean currDisallow = true;
-        boolean nextDisallow = true;
-
-        userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
-                expectedInteractionsWithShowNotification);
-
-        currDisallow = false;
-        nextDisallow = false;
-
-        userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
-                expectedInteractionsWithShowNotification);
-    }
-
-    private class TestTetheringEventCallback extends ITetheringEventCallback.Stub {
-        private final ArrayList<Network> mActualUpstreams = new ArrayList<>();
-
-        public void expectUpstreamChanged(Network... networks) {
-            final ArrayList<Network> expectedUpstreams =
-                    new ArrayList<Network>(Arrays.asList(networks));
-            for (Network upstream : expectedUpstreams) {
-                // throws OOB if no expectations
-                assertEquals(mActualUpstreams.remove(0), upstream);
-            }
-            assertNoCallback();
-        }
-
-        @Override
-        public void onUpstreamChanged(Network network) {
-            mActualUpstreams.add(network);
-        }
-
-        public void assertNoCallback() {
-            assertTrue(mActualUpstreams.isEmpty());
-        }
-    }
-
-    @Test
-    public void testRegisterTetheringEventCallback() throws Exception {
-        TestTetheringEventCallback callback1 = new TestTetheringEventCallback();
-        TestTetheringEventCallback callback2 = new TestTetheringEventCallback();
-
-        // 1. Register one callback and run usb tethering.
-        mTethering.registerTetheringEventCallback(callback1);
-        mLooper.dispatchAll();
-        callback1.expectUpstreamChanged(new Network[] {null});
-        NetworkState upstreamState = buildMobileDualStackUpstreamState();
-        runUsbTethering(upstreamState);
-        callback1.expectUpstreamChanged(upstreamState.network);
-        // 2. Register second callback.
-        mTethering.registerTetheringEventCallback(callback2);
-        mLooper.dispatchAll();
-        callback2.expectUpstreamChanged(upstreamState.network);
-        // 3. Disable usb tethering.
-        mTethering.stopTethering(TETHERING_USB);
-        mLooper.dispatchAll();
-        sendUsbBroadcast(false, false, false);
-        mLooper.dispatchAll();
-        callback1.expectUpstreamChanged(new Network[] {null});
-        callback2.expectUpstreamChanged(new Network[] {null});
-        // 4. Unregister first callback and run hotspot.
-        mTethering.unregisterTetheringEventCallback(callback1);
-        mLooper.dispatchAll();
-        when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
-        when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
-                .thenReturn(upstreamState);
-        when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
-        mTethering.startTethering(TETHERING_WIFI, null, false);
-        mLooper.dispatchAll();
-        mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
-        sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
-        mLooper.dispatchAll();
-        callback1.assertNoCallback();
-        callback2.expectUpstreamChanged(upstreamState.network);
-    }
-
-    @Test
-    public void testMultiSimAware() throws Exception {
-        final TetheringConfiguration initailConfig = mTethering.getTetheringConfiguration();
-        assertEquals(INVALID_SUBSCRIPTION_ID, initailConfig.subId);
-
-        final int fakeSubId = 1234;
-        mPhoneStateListener.onActiveDataSubscriptionIdChanged(fakeSubId);
-        final TetheringConfiguration newConfig = mTethering.getTetheringConfiguration();
-        assertEquals(fakeSubId, newConfig.subId);
-    }
-
-    private void workingWifiP2pGroupOwner(
-            boolean emulateInterfaceStatusChanged) throws Exception {
-        if (emulateInterfaceStatusChanged) {
-            mTethering.interfaceStatusChanged(TEST_P2P_IFNAME, true);
-        }
-        sendWifiP2pConnectionChanged(true, true, TEST_P2P_IFNAME);
-        mLooper.dispatchAll();
-
-        verifyInterfaceServingModeStarted(TEST_P2P_IFNAME);
-        verifyTetheringBroadcast(TEST_P2P_IFNAME, EXTRA_AVAILABLE_TETHER);
-        verify(mNMService, times(1)).setIpForwardingEnabled(true);
-        verify(mNMService, times(1)).startTethering(any(String[].class));
-        verifyNoMoreInteractions(mNMService);
-        verifyTetheringBroadcast(TEST_P2P_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY);
-        verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks();
-        // This will be called twice, one is on entering IpServer.STATE_AVAILABLE,
-        // and another one is on IpServer.STATE_TETHERED/IpServer.STATE_LOCAL_ONLY.
-        assertEquals(2, mTetheringDependencies.isTetheringSupportedCalls);
-
-        assertEquals(TETHER_ERROR_NO_ERROR, mTethering.getLastTetherError(TEST_P2P_IFNAME));
-
-        // Emulate externally-visible WifiP2pManager effects, when wifi p2p group
-        // is being removed.
-        sendWifiP2pConnectionChanged(false, true, TEST_P2P_IFNAME);
-        mTethering.interfaceRemoved(TEST_P2P_IFNAME);
-        mLooper.dispatchAll();
-
-        verify(mNMService, times(1)).untetherInterface(TEST_P2P_IFNAME);
-        // {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4.
-        verify(mNMService, times(2)).getInterfaceConfig(TEST_P2P_IFNAME);
-        verify(mNMService, times(2))
-                .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
-        verify(mNMService, times(1)).stopTethering();
-        verify(mNMService, times(1)).setIpForwardingEnabled(false);
-        verify(mUpstreamNetworkMonitor, never()).getCurrentPreferredUpstream();
-        verify(mUpstreamNetworkMonitor, never()).selectPreferredUpstreamType(any());
-        verifyNoMoreInteractions(mNMService);
-        // Asking for the last error after the per-interface state machine
-        // has been reaped yields an unknown interface error.
-        assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME));
-    }
-
-    private void workingWifiP2pGroupClient(
-            boolean emulateInterfaceStatusChanged) throws Exception {
-        if (emulateInterfaceStatusChanged) {
-            mTethering.interfaceStatusChanged(TEST_P2P_IFNAME, true);
-        }
-        sendWifiP2pConnectionChanged(true, false, TEST_P2P_IFNAME);
-        mLooper.dispatchAll();
-
-        verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME);
-        verify(mNMService, never())
-                .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
-        verify(mNMService, never()).tetherInterface(TEST_P2P_IFNAME);
-        verify(mNMService, never()).setIpForwardingEnabled(true);
-        verify(mNMService, never()).startTethering(any(String[].class));
-
-        // Emulate externally-visible WifiP2pManager effects, when wifi p2p group
-        // is being removed.
-        sendWifiP2pConnectionChanged(false, false, TEST_P2P_IFNAME);
-        mTethering.interfaceRemoved(TEST_P2P_IFNAME);
-        mLooper.dispatchAll();
-
-        verify(mNMService, never()).untetherInterface(TEST_P2P_IFNAME);
-        verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME);
-        verify(mNMService, never())
-                .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
-        verify(mNMService, never()).stopTethering();
-        verify(mNMService, never()).setIpForwardingEnabled(false);
-        verifyNoMoreInteractions(mNMService);
-        // Asking for the last error after the per-interface state machine
-        // has been reaped yields an unknown interface error.
-        assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME));
-    }
-
-    @Test
-    public void workingWifiP2pGroupOwnerWithIfaceChanged() throws Exception {
-        workingWifiP2pGroupOwner(true);
-    }
-
-    @Test
-    public void workingWifiP2pGroupOwnerSansIfaceChanged() throws Exception {
-        workingWifiP2pGroupOwner(false);
-    }
-
-    private void workingWifiP2pGroupOwnerLegacyMode(
-            boolean emulateInterfaceStatusChanged) throws Exception {
-        // change to legacy mode and update tethering information by chaning SIM
-        when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_p2p_regexs))
-                .thenReturn(new String[]{});
-        final int fakeSubId = 1234;
-        mPhoneStateListener.onActiveDataSubscriptionIdChanged(fakeSubId);
-
-        if (emulateInterfaceStatusChanged) {
-            mTethering.interfaceStatusChanged(TEST_P2P_IFNAME, true);
-        }
-        sendWifiP2pConnectionChanged(true, true, TEST_P2P_IFNAME);
-        mLooper.dispatchAll();
-
-        verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME);
-        verify(mNMService, never())
-                .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
-        verify(mNMService, never()).tetherInterface(TEST_P2P_IFNAME);
-        verify(mNMService, never()).setIpForwardingEnabled(true);
-        verify(mNMService, never()).startTethering(any(String[].class));
-        assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME));
-    }
-    @Test
-    public void workingWifiP2pGroupOwnerLegacyModeWithIfaceChanged() throws Exception {
-        workingWifiP2pGroupOwnerLegacyMode(true);
-    }
-
-    @Test
-    public void workingWifiP2pGroupOwnerLegacyModeSansIfaceChanged() throws Exception {
-        workingWifiP2pGroupOwnerLegacyMode(false);
-    }
-
-    @Test
-    public void workingWifiP2pGroupClientWithIfaceChanged() throws Exception {
-        workingWifiP2pGroupClient(true);
-    }
-
-    @Test
-    public void workingWifiP2pGroupClientSansIfaceChanged() throws Exception {
-        workingWifiP2pGroupClient(false);
-    }
-
-    // TODO: Test that a request for hotspot mode doesn't interfere with an
-    // already operating tethering mode interface.
-}
diff --git a/tests/utils/testutils/Android.bp b/tests/utils/testutils/Android.bp
index f71be7b..e13f906 100644
--- a/tests/utils/testutils/Android.bp
+++ b/tests/utils/testutils/Android.bp
@@ -17,11 +17,24 @@
 java_library {
     name: "frameworks-base-testutils",
 
-    srcs: ["java/**/*.java"],
+    static_libs: [
+        "frameworks-base-testutils-minus-mockito",
+        "mockito-target-minus-junit4",
+    ]
+}
+
+java_library {
+    name: "frameworks-base-testutils-minus-mockito",
+
+    srcs: [
+        "java/**/*.java",
+        "java/**/*.kt",
+    ],
 
     static_libs: [
         "junit",
         "hamcrest-library",
+        "truth-prebuilt",
     ],
 
     libs: [
diff --git a/tests/utils/testutils/java/test/package-info.java b/tests/utils/testutils/java/test/package-info.java
new file mode 100644
index 0000000..c34d7b2
--- /dev/null
+++ b/tests/utils/testutils/java/test/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * This package separated from android. because placing classes under android.'s .test/.util
+ * may be confused with tests for that actual android subpackage.
+ **/
+package test;
diff --git a/tests/utils/testutils/java/test/util/MockitoUtils.kt b/tests/utils/testutils/java/test/util/MockitoUtils.kt
new file mode 100644
index 0000000..5151abe
--- /dev/null
+++ b/tests/utils/testutils/java/test/util/MockitoUtils.kt
@@ -0,0 +1,70 @@
+/*
+ * 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 test.util
+
+import org.mockito.Answers
+import org.mockito.Mockito
+import org.mockito.invocation.InvocationOnMock
+import org.mockito.stubbing.Answer
+import org.mockito.stubbing.Stubber
+
+object MockitoUtils {
+    val ANSWER_THROWS = Answer<Any?> {
+        when (val name = it.method.name) {
+            "toString" -> return@Answer Answers.CALLS_REAL_METHODS.answer(it)
+            else -> {
+                val arguments = it.arguments
+                        ?.takeUnless { it.isEmpty() }
+                        ?.joinToString()
+                        ?.let {
+                            "with $it"
+                        }
+                        .orEmpty()
+
+                throw UnsupportedOperationException("${it.mock::class.java.simpleName}#$name " +
+                        "$arguments should not be called")
+            }
+        }
+    }
+}
+
+inline fun <reified T> mock(block: T.() -> Unit = {}) = Mockito.mock(T::class.java).apply(block)
+
+fun <Type> Stubber.whenever(mock: Type) = Mockito.`when`(mock)
+fun <Type : Any?> whenever(mock: Type) = Mockito.`when`(mock)
+
+@Suppress("UNCHECKED_CAST")
+fun <Type : Any?> whenever(mock: Type, block: InvocationOnMock.() -> Any?) =
+        Mockito.`when`(mock).thenAnswer { block(it) }
+
+fun whenever(mock: Unit) = Mockito.`when`(mock).thenAnswer { }
+
+inline fun <reified T> mockThrowOnUnmocked(block: T.() -> Unit): T {
+    val swappingAnswer = object : Answer<Any?> {
+        var delegate: Answer<*> = Answers.RETURNS_DEFAULTS
+
+        override fun answer(invocation: InvocationOnMock?): Any? {
+            return delegate.answer(invocation)
+        }
+    }
+
+    return Mockito.mock(T::class.java, swappingAnswer).apply(block)
+            .also {
+                // To allow when() usage inside block, only swap to throwing afterwards
+                swappingAnswer.delegate = MockitoUtils.ANSWER_THROWS
+            }
+}
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 99a686b..4555caa 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -1297,7 +1297,8 @@
       return false;
     }
 
-    proguard::WriteKeepSet(keep_set, &fout, options_.generate_minimal_proguard_rules);
+    proguard::WriteKeepSet(keep_set, &fout, options_.generate_minimal_proguard_rules,
+                           options_.no_proguard_location_reference);
     fout.Flush();
 
     if (fout.HadError()) {
diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h
index 56bff8f..4722358 100644
--- a/tools/aapt2/cmd/Link.h
+++ b/tools/aapt2/cmd/Link.h
@@ -56,6 +56,7 @@
   bool generate_conditional_proguard_rules = false;
   bool generate_minimal_proguard_rules = false;
   bool generate_non_final_ids = false;
+  bool no_proguard_location_reference = false;
   std::vector<std::string> javadoc_annotations;
   Maybe<std::string> private_symbols;
 
@@ -215,6 +216,9 @@
         "Generates R.java without the final modifier. This is implied when\n"
             "--static-lib is specified.",
         &options_.generate_non_final_ids);
+    AddOptionalSwitch("--no-proguard-location-reference",
+        "Keep proguard rules files from having a reference to the source file",
+        &options_.no_proguard_location_reference);
     AddOptionalFlag("--stable-ids", "File containing a list of name to ID mapping.",
         &stable_id_file_path_);
     AddOptionalFlag("--emit-ids",
@@ -264,8 +268,8 @@
         &options_.keep_raw_values);
     AddOptionalFlag("--no-compress-regex",
         "Do not compress extensions matching the regular expression. Remember to\n"
-            " use the '$' symbol for end of line. Uses a non case-sensitive\n"
-            " ECMAScript regular expression grammar.",
+            "use the '$' symbol for end of line. Uses a case-sensitive ECMAScript"
+            "regular expression grammar.",
         &no_compress_regex);
     AddOptionalSwitch("--warn-manifest-validation",
         "Treat manifest validation errors as warnings.",
diff --git a/tools/aapt2/cmd/Util.cpp b/tools/aapt2/cmd/Util.cpp
index e2c65ba7..7214f1a 100644
--- a/tools/aapt2/cmd/Util.cpp
+++ b/tools/aapt2/cmd/Util.cpp
@@ -436,9 +436,9 @@
 }
 
 std::regex GetRegularExpression(const std::string &input) {
-  // Standard ECMAScript grammar plus case insensitive.
+  // Standard ECMAScript grammar.
   std::regex case_insensitive(
-      input, std::regex_constants::icase | std::regex_constants::ECMAScript);
+      input, std::regex_constants::ECMAScript);
   return case_insensitive;
 }
 
diff --git a/tools/aapt2/cmd/Util_test.cpp b/tools/aapt2/cmd/Util_test.cpp
index 2f090bb..ac1f981 100644
--- a/tools/aapt2/cmd/Util_test.cpp
+++ b/tools/aapt2/cmd/Util_test.cpp
@@ -383,13 +383,32 @@
   EXPECT_NE(*adjusted_contraints[1].configs.begin(), ConfigDescription::DefaultConfig());
 }
 
-// TODO(127793905): Enable test
-/*TEST(UtilTest, RegularExperssions) {
+TEST (UtilTest, RegularExperssionsSimple) {
   std::string valid(".bc$");
   std::regex expression = GetRegularExpression(valid);
   EXPECT_TRUE(std::regex_search("file.abc", expression));
   EXPECT_TRUE(std::regex_search("file.123bc", expression));
   EXPECT_FALSE(std::regex_search("abc.zip", expression));
-}*/
+}
+
+TEST (UtilTest, RegularExpressionComplex) {
+  std::string valid("\\.(d|D)(e|E)(x|X)$");
+  std::regex expression = GetRegularExpression(valid);
+  EXPECT_TRUE(std::regex_search("file.dex", expression));
+  EXPECT_TRUE(std::regex_search("file.DEX", expression));
+  EXPECT_TRUE(std::regex_search("file.dEx", expression));
+  EXPECT_FALSE(std::regex_search("file.dexx", expression));
+  EXPECT_FALSE(std::regex_search("dex.file", expression));
+  EXPECT_FALSE(std::regex_search("file.adex", expression));
+}
+
+TEST (UtilTest, RegularExpressionNonEnglish) {
+  std::string valid("\\.(k|K)(o|O)(ń|Ń)(c|C)(ó|Ó)(w|W)(k|K)(a|A)$");
+  std::regex expression = GetRegularExpression(valid);
+  EXPECT_TRUE(std::regex_search("file.końcówka", expression));
+  EXPECT_TRUE(std::regex_search("file.KOŃCÓWKA", expression));
+  EXPECT_TRUE(std::regex_search("file.kOńcÓwkA", expression));
+  EXPECT_FALSE(std::regex_search("file.koncowka", expression));
+}
 
 }  // namespace aapt
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index 31d205e..bb541fe 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -304,9 +304,11 @@
     auto documentation_remove_iter = std::remove_if(documentation_attrs.begin(),
                                                     documentation_attrs.end(),
                                                     [&](StyleableAttr entry) -> bool {
-      StringPiece attr_comment_line = entry.symbol.value().attribute->GetComment();
-      return SkipSymbol(entry.symbol) || attr_comment_line.contains("@removed")
-                                      || attr_comment_line.contains("@hide");
+      if (SkipSymbol(entry.symbol)) {
+        return true;
+      }
+      const StringPiece attr_comment_line = entry.symbol.value().attribute->GetComment();
+      return attr_comment_line.contains("@removed") || attr_comment_line.contains("@hide");
     });
     documentation_attrs.erase(documentation_remove_iter, documentation_attrs.end());
 
@@ -428,7 +430,7 @@
     out_rewrite_method->AppendStatement(
         StringPrintf("  if ((styleable.%s[i] & 0xff000000) == 0) {", array_field_name.data()));
     out_rewrite_method->AppendStatement(
-        StringPrintf("    styleable.%s[i] = (styleable.%s[i] & 0x00ffffff) | (p << 24);",
+        StringPrintf("    styleable.%s[i] = (styleable.%s[i] & 0x00ffffff) | packageIdBits;",
                      array_field_name.data(), array_field_name.data()));
     out_rewrite_method->AppendStatement("  }");
     out_rewrite_method->AppendStatement("}");
@@ -487,9 +489,9 @@
 
   if (out_rewrite_method != nullptr) {
     const StringPiece& type_str = to_string(name.type);
-    out_rewrite_method->AppendStatement(StringPrintf("%s.%s = (%s.%s & 0x00ffffff) | (p << 24);",
-                                                     type_str.data(), field_name.data(),
-                                                     type_str.data(), field_name.data()));
+    out_rewrite_method->AppendStatement(
+        StringPrintf("%s.%s = (%s.%s & 0x00ffffff) | packageIdBits;", type_str.data(),
+                     field_name.data(), type_str.data(), field_name.data()));
   }
 }
 
@@ -599,6 +601,7 @@
       rewrite_method->AppendStatement(
           StringPrintf("%s.R.onResourcesLoaded(p);", package_to_callback.data()));
     }
+    rewrite_method->AppendStatement("final int packageIdBits = p << 24;");
   }
 
   for (const auto& package : table_->packages) {
diff --git a/tools/aapt2/java/JavaClassGenerator_test.cpp b/tools/aapt2/java/JavaClassGenerator_test.cpp
index 4f51fc4..1e1fe47 100644
--- a/tools/aapt2/java/JavaClassGenerator_test.cpp
+++ b/tools/aapt2/java/JavaClassGenerator_test.cpp
@@ -522,9 +522,15 @@
   ASSERT_TRUE(generator.Generate("android", &out));
   out.Flush();
 
-  EXPECT_THAT(output, HasSubstr("void onResourcesLoaded"));
-  EXPECT_THAT(output, HasSubstr("com.foo.R.onResourcesLoaded"));
-  EXPECT_THAT(output, HasSubstr("com.boo.R.onResourcesLoaded"));
+  EXPECT_THAT(output, HasSubstr(
+          R"(  public static void onResourcesLoaded(int p) {
+    com.foo.R.onResourcesLoaded(p);
+    com.boo.R.onResourcesLoaded(p);
+    final int packageIdBits = p << 24;
+    attr.foo = (attr.foo & 0x00ffffff) | packageIdBits;
+    id.foo = (id.foo & 0x00ffffff) | packageIdBits;
+    style.foo = (style.foo & 0x00ffffff) | packageIdBits;
+  })"));
 }
 
 TEST(JavaClassGeneratorTest, OnlyGenerateRText) {
diff --git a/tools/aapt2/java/ProguardRules.cpp b/tools/aapt2/java/ProguardRules.cpp
index 806f4e3..b06607e 100644
--- a/tools/aapt2/java/ProguardRules.cpp
+++ b/tools/aapt2/java/ProguardRules.cpp
@@ -393,11 +393,15 @@
   return true;
 }
 
-void WriteKeepSet(const KeepSet& keep_set, OutputStream* out, bool minimal_keep) {
+void WriteKeepSet(const KeepSet& keep_set, OutputStream* out, bool minimal_keep,
+                  bool no_location_reference) {
+
   Printer printer(out);
   for (const auto& entry : keep_set.manifest_class_set_) {
-    for (const UsageLocation& location : entry.second) {
-      printer.Print("# Referenced at ").Println(location.source.to_string());
+    if (!no_location_reference) {
+      for (const UsageLocation& location : entry.second) {
+        printer.Print("# Referenced at ").Println(location.source.to_string());
+      }
     }
     printer.Print("-keep class ").Print(entry.first).Println(" { <init>(); }");
   }
@@ -414,7 +418,9 @@
 
     if (can_be_conditional) {
       for (const UsageLocation& location : locations) {
-        printer.Print("# Referenced at ").Println(location.source.to_string());
+        if (!no_location_reference) {
+          printer.Print("# Referenced at ").Println(location.source.to_string());
+        }
         printer.Print("-if class **.R$layout { int ")
             .Print(JavaClassGenerator::TransformToFieldName(location.name.entry))
             .Println("; }");
@@ -424,8 +430,10 @@
         printer.Println("); }");
       }
     } else {
-      for (const UsageLocation& location : entry.second) {
-        printer.Print("# Referenced at ").Println(location.source.to_string());
+      if (!no_location_reference) {
+        for (const UsageLocation& location : entry.second) {
+          printer.Print("# Referenced at ").Println(location.source.to_string());
+        }
       }
 
       printer.Print("-keep class ").Print(entry.first.name).Print(" { <init>(");
@@ -436,8 +444,10 @@
   }
 
   for (const auto& entry : keep_set.method_set_) {
-    for (const UsageLocation& location : entry.second) {
-      printer.Print("# Referenced at ").Println(location.source.to_string());
+    if (!no_location_reference) {
+      for (const UsageLocation& location : entry.second) {
+        printer.Print("# Referenced at ").Println(location.source.to_string());
+      }
     }
     printer.Print("-keepclassmembers class * { *** ").Print(entry.first.name)
         .Print("(").Print(entry.first.signature).Println("); }");
diff --git a/tools/aapt2/java/ProguardRules.h b/tools/aapt2/java/ProguardRules.h
index b15df59..a01b64d 100644
--- a/tools/aapt2/java/ProguardRules.h
+++ b/tools/aapt2/java/ProguardRules.h
@@ -70,7 +70,8 @@
   }
 
  private:
-  friend void WriteKeepSet(const KeepSet& keep_set, io::OutputStream* out, bool minimal_keep);
+  friend void WriteKeepSet(const KeepSet& keep_set, io::OutputStream* out, bool minimal_keep,
+                           bool no_location_reference);
 
   friend bool CollectLocations(const UsageLocation& location, const KeepSet& keep_set,
                                std::set<UsageLocation>* locations);
@@ -89,7 +90,8 @@
 
 bool CollectResourceReferences(IAaptContext* context, ResourceTable* table, KeepSet* keep_set);
 
-void WriteKeepSet(const KeepSet& keep_set, io::OutputStream* out, bool minimal_keep);
+void WriteKeepSet(const KeepSet& keep_set, io::OutputStream* out, bool minimal_keep,
+                  bool no_location_reference);
 
 bool CollectLocations(const UsageLocation& location, const KeepSet& keep_set,
                       std::set<UsageLocation>* locations);
diff --git a/tools/aapt2/java/ProguardRules_test.cpp b/tools/aapt2/java/ProguardRules_test.cpp
index 25b55ab..8720597 100644
--- a/tools/aapt2/java/ProguardRules_test.cpp
+++ b/tools/aapt2/java/ProguardRules_test.cpp
@@ -30,7 +30,7 @@
 std::string GetKeepSetString(const proguard::KeepSet& set, bool minimal_rules) {
   std::string out;
   StringOutputStream sout(&out);
-  proguard::WriteKeepSet(set, &sout, minimal_rules);
+  proguard::WriteKeepSet(set, &sout, minimal_rules, false);
   sout.Flush();
   return out;
 }
diff --git a/tools/processors/unsupportedappusage/Android.bp b/tools/processors/unsupportedappusage/Android.bp
deleted file mode 100644
index 1e96234..0000000
--- a/tools/processors/unsupportedappusage/Android.bp
+++ /dev/null
@@ -1,34 +0,0 @@
-
-java_library_host {
-    name: "unsupportedappusage-annotation-processor-lib",
-    srcs: [
-        "src/**/*.java",
-    ],
-    static_libs: [
-        "guava",
-        "unsupportedappusage-annotation"
-    ],
-    openjdk9: {
-        javacflags: [
-            "--add-modules=jdk.compiler",
-            "--add-exports jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
-            "--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED",
-            "--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
-            "--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
-        ],
-    },
-}
-
-java_plugin {
-    name: "unsupportedappusage-annotation-processor",
-    processor_class: "android.processor.unsupportedappusage.UnsupportedAppUsageProcessor",
-
-    java_resources: [
-        "META-INF/**/*",
-    ],
-    static_libs: [
-        "unsupportedappusage-annotation-processor-lib"
-    ],
-
-    use_tools_jar: true,
-}
diff --git a/tools/processors/unsupportedappusage/META-INF/services/javax.annotation.processing.Processor b/tools/processors/unsupportedappusage/META-INF/services/javax.annotation.processing.Processor
deleted file mode 100644
index 4a969d3..0000000
--- a/tools/processors/unsupportedappusage/META-INF/services/javax.annotation.processing.Processor
+++ /dev/null
@@ -1 +0,0 @@
-android.processor.unsupportedappusage.UnsupportedAppUsageProcessor
diff --git a/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SignatureBuilder.java b/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SignatureBuilder.java
deleted file mode 100644
index 65fc733..0000000
--- a/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SignatureBuilder.java
+++ /dev/null
@@ -1,258 +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 android.processor.unsupportedappusage;
-
-import static javax.lang.model.element.ElementKind.PACKAGE;
-import static javax.tools.Diagnostic.Kind.ERROR;
-import static javax.tools.Diagnostic.Kind.WARNING;
-
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableMap;
-import com.sun.tools.javac.code.Type;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import javax.annotation.processing.Messager;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.PackageElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.ArrayType;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * Builds a dex signature for a given method or field.
- */
-public class SignatureBuilder {
-
-    private static final Map<TypeKind, String> TYPE_MAP = ImmutableMap.<TypeKind, String>builder()
-            .put(TypeKind.BOOLEAN, "Z")
-            .put(TypeKind.BYTE, "B")
-            .put(TypeKind.CHAR, "C")
-            .put(TypeKind.DOUBLE, "D")
-            .put(TypeKind.FLOAT, "F")
-            .put(TypeKind.INT, "I")
-            .put(TypeKind.LONG, "J")
-            .put(TypeKind.SHORT, "S")
-            .put(TypeKind.VOID, "V")
-            .build();
-
-    private final Messager mMessager;
-
-    /**
-     * Exception used internally when we can't build a signature. Whenever this is thrown, an error
-     * will also be written to the Messager.
-     */
-    private class SignatureBuilderException extends Exception {
-        public SignatureBuilderException(String message) {
-            super(message);
-        }
-
-        public void report(Element offendingElement) {
-            mMessager.printMessage(ERROR, getMessage(), offendingElement);
-        }
-    }
-
-    public SignatureBuilder(Messager messager) {
-        mMessager = messager;
-    }
-
-    /**
-     * Returns a list of enclosing elements for the given element, with the package first, and
-     * excluding the element itself.
-     */
-    private List<Element> getEnclosingElements(Element e) {
-        List<Element> enclosing = new ArrayList<>();
-        e = e.getEnclosingElement(); // don't include the element itself.
-        while (e != null) {
-            enclosing.add(e);
-            e = e.getEnclosingElement();
-        }
-        Collections.reverse(enclosing);
-        return enclosing;
-    }
-
-    /**
-     * Get the dex signature for a clazz, in format "Lpackage/name/Outer$Inner;"
-     */
-    private String getClassSignature(TypeElement clazz) {
-        StringBuilder sb = new StringBuilder("L");
-        for (Element enclosing : getEnclosingElements(clazz)) {
-            switch (enclosing.getKind()) {
-                case MODULE:
-                    // ignore this.
-                    break;
-                case PACKAGE:
-                    sb.append(((PackageElement) enclosing)
-                            .getQualifiedName()
-                            .toString()
-                            .replace('.', '/'));
-                    sb.append('/');
-                    break;
-                default:
-                    sb.append(enclosing.getSimpleName()).append('$');
-                    break;
-            }
-
-        }
-        return sb
-                .append(clazz.getSimpleName())
-                .append(";")
-                .toString();
-    }
-
-    /**
-     * Returns the type signature for a given type. For primitive types, a single character.
-     * For classes, the class signature. For arrays, a "[" preceeding the component type.
-     */
-    private String getTypeSignature(TypeMirror type) throws SignatureBuilderException {
-        String sig = TYPE_MAP.get(type.getKind());
-        if (sig != null) {
-            return sig;
-        }
-        switch (type.getKind()) {
-            case ARRAY:
-                return "[" + getTypeSignature(((ArrayType) type).getComponentType());
-            case DECLARED:
-                Element declaring = ((DeclaredType) type).asElement();
-                if (!(declaring instanceof TypeElement)) {
-                    throw new SignatureBuilderException(
-                            "Can't handle declared type of kind " + declaring.getKind());
-                }
-                return getClassSignature((TypeElement) declaring);
-            case TYPEVAR:
-                Type.TypeVar typeVar = (Type.TypeVar) type;
-                if (typeVar.getLowerBound().getKind() != TypeKind.NULL) {
-                    return getTypeSignature(typeVar.getLowerBound());
-                } else if (typeVar.getUpperBound().getKind() != TypeKind.NULL) {
-                    return getTypeSignature(typeVar.getUpperBound());
-                } else {
-                    throw new SignatureBuilderException("Can't handle typevar with no bound");
-                }
-
-            default:
-                throw new SignatureBuilderException("Can't handle type of kind " + type.getKind());
-        }
-    }
-
-    /**
-     * Get the signature for an executable, either a method or a constructor.
-     *
-     * @param name   "<init>" for  constructor, else the method name
-     * @param method The executable element in question.
-     */
-    private String getExecutableSignature(CharSequence name, ExecutableElement method)
-            throws SignatureBuilderException {
-        StringBuilder sig = new StringBuilder();
-        sig.append(getClassSignature((TypeElement) method.getEnclosingElement()))
-                .append("->")
-                .append(name)
-                .append("(");
-        for (VariableElement param : method.getParameters()) {
-            sig.append(getTypeSignature(param.asType()));
-        }
-        sig.append(")")
-                .append(getTypeSignature(method.getReturnType()));
-        return sig.toString();
-    }
-
-    private String buildMethodSignature(ExecutableElement method) throws SignatureBuilderException {
-        return getExecutableSignature(method.getSimpleName(), method);
-    }
-
-    private String buildConstructorSignature(ExecutableElement cons)
-            throws SignatureBuilderException {
-        return getExecutableSignature("<init>", cons);
-    }
-
-    private String buildFieldSignature(VariableElement field) throws SignatureBuilderException {
-        StringBuilder sig = new StringBuilder();
-        sig.append(getClassSignature((TypeElement) field.getEnclosingElement()))
-                .append("->")
-                .append(field.getSimpleName())
-                .append(":")
-                .append(getTypeSignature(field.asType()))
-        ;
-        return sig.toString();
-    }
-
-    /**
-     * Creates the signature for an annotated element.
-     *
-     * @param annotationType type of annotation being processed.
-     * @param element        element for which we want to create a signature.
-     */
-    public String buildSignature(Class<? extends Annotation> annotationType, Element element) {
-        try {
-            String signature;
-            switch (element.getKind()) {
-                case METHOD:
-                    signature = buildMethodSignature((ExecutableElement) element);
-                    break;
-                case CONSTRUCTOR:
-                    signature = buildConstructorSignature((ExecutableElement) element);
-                    break;
-                case FIELD:
-                    signature = buildFieldSignature((VariableElement) element);
-                    break;
-                default:
-                    return null;
-            }
-            // Obtain annotation objects
-            Annotation annotation = element.getAnnotation(annotationType);
-            if (annotation == null) {
-                throw new IllegalStateException(
-                        "Element doesn't have any UnsupportedAppUsage annotation");
-            }
-            try {
-                Method expectedSignatureMethod = annotationType.getMethod("expectedSignature");
-                // If we have an expected signature on the annotation, warn if it doesn't match.
-                String expectedSignature = expectedSignatureMethod.invoke(annotation).toString();
-                if (!Strings.isNullOrEmpty(expectedSignature)) {
-                    if (!signature.equals(expectedSignature)) {
-                        mMessager.printMessage(
-                                WARNING,
-                                String.format(
-                                        "Expected signature doesn't match generated signature.\n"
-                                                + " Expected:  %s\n Generated: %s",
-                                        expectedSignature, signature),
-                                element);
-                    }
-                }
-                return signature;
-            } catch (NoSuchMethodException e) {
-                throw new IllegalStateException(
-                        "Annotation type does not have expectedSignature parameter", e);
-            } catch (IllegalAccessException | InvocationTargetException e) {
-                throw new IllegalStateException(
-                        "Could not get expectedSignature parameter for annotation", e);
-            }
-        } catch (SignatureBuilderException problem) {
-            problem.report(element);
-            return null;
-        }
-    }
-}
diff --git a/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessor.java b/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessor.java
deleted file mode 100644
index 5bb956a..0000000
--- a/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessor.java
+++ /dev/null
@@ -1,204 +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 android.processor.unsupportedappusage;
-
-import static javax.tools.StandardLocation.CLASS_OUTPUT;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableSet;
-import com.sun.tools.javac.model.JavacElements;
-import com.sun.tools.javac.tree.JCTree;
-import com.sun.tools.javac.util.Pair;
-import com.sun.tools.javac.util.Position;
-
-import java.io.IOException;
-import java.io.PrintStream;
-import java.lang.annotation.Annotation;
-import java.net.URLEncoder;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.stream.Stream;
-
-import javax.annotation.processing.AbstractProcessor;
-import javax.annotation.processing.RoundEnvironment;
-import javax.annotation.processing.SupportedAnnotationTypes;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-
-/**
- * Annotation processor for {@link UnsupportedAppUsage} annotations.
- *
- * This processor currently outputs a CSV file with a mapping of dex signatures to corresponding
- * source positions.
- *
- * This is used for automating updates to the annotations themselves.
- */
-@SupportedAnnotationTypes({"android.annotation.UnsupportedAppUsage",
-        "dalvik.annotation.compat.UnsupportedAppUsage"
-})
-public class UnsupportedAppUsageProcessor extends AbstractProcessor {
-
-    // Package name for writing output. Output will be written to the "class output" location within
-    // this package.
-    private static final String PACKAGE = "unsupportedappusage";
-    private static final String INDEX_CSV = "unsupportedappusage_index.csv";
-
-    private static final ImmutableSet<Class<? extends Annotation>> SUPPORTED_ANNOTATIONS =
-            ImmutableSet.of(android.annotation.UnsupportedAppUsage.class,
-                    dalvik.annotation.compat.UnsupportedAppUsage.class);
-    private static final ImmutableSet<String> SUPPORTED_ANNOTATION_NAMES =
-            SUPPORTED_ANNOTATIONS.stream().map(annotation -> annotation.getCanonicalName()).collect(
-                    ImmutableSet.toImmutableSet());
-
-    @Override
-    public SourceVersion getSupportedSourceVersion() {
-        return SourceVersion.latest();
-    }
-
-    /**
-     * Write the contents of a stream to a text file, with one line per item.
-     */
-    private void writeToFile(String name,
-            String headerLine,
-            Stream<?> contents) throws IOException {
-        PrintStream out = new PrintStream(processingEnv.getFiler().createResource(
-                CLASS_OUTPUT,
-                PACKAGE,
-                name)
-                .openOutputStream());
-        out.println(headerLine);
-        contents.forEach(o -> out.println(o));
-        if (out.checkError()) {
-            throw new IOException("Error when writing to " + name);
-        }
-        out.close();
-    }
-
-    /**
-     * Find the annotation mirror for the @UnsupportedAppUsage annotation on the given element.
-     */
-    private AnnotationMirror getUnsupportedAppUsageAnnotationMirror(Element e) {
-        for (AnnotationMirror m : e.getAnnotationMirrors()) {
-            TypeElement type = (TypeElement) m.getAnnotationType().asElement();
-            if (SUPPORTED_ANNOTATION_NAMES.contains(type.getQualifiedName().toString())) {
-                return m;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Returns a CSV header line for the columns returned by
-     * {@link #getAnnotationIndex(String, Element)}.
-     */
-    private String getCsvHeaders() {
-        return Joiner.on(',').join(
-                "signature",
-                "file",
-                "startline",
-                "startcol",
-                "endline",
-                "endcol",
-                "properties"
-        );
-    }
-
-    private String encodeAnnotationProperties(AnnotationMirror annotation) {
-        StringBuilder sb = new StringBuilder();
-        for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> e
-                : annotation.getElementValues().entrySet()) {
-            if (sb.length() > 0) {
-                sb.append("&");
-            }
-            sb.append(e.getKey().getSimpleName())
-                    .append("=")
-                    .append(URLEncoder.encode(e.getValue().toString()));
-        }
-        return sb.toString();
-    }
-
-    /**
-     * Maps an annotated element to the source position of the @UnsupportedAppUsage annotation
-     * attached to it. It returns CSV in the format:
-     * dex-signature,filename,start-line,start-col,end-line,end-col
-     *
-     * The positions refer to the annotation itself, *not* the annotated member. This can therefore
-     * be used to read just the annotation from the file, and to perform in-place edits on it.
-     *
-     * @param signature        the dex signature for the element.
-     * @param annotatedElement The annotated element
-     * @return A single line of CSV text
-     */
-    private String getAnnotationIndex(String signature, Element annotatedElement) {
-        JavacElements javacElem = (JavacElements) processingEnv.getElementUtils();
-        AnnotationMirror unsupportedAppUsage =
-                getUnsupportedAppUsageAnnotationMirror(annotatedElement);
-        Pair<JCTree, JCTree.JCCompilationUnit> pair =
-                javacElem.getTreeAndTopLevel(annotatedElement, unsupportedAppUsage, null);
-        Position.LineMap lines = pair.snd.lineMap;
-        return Joiner.on(",").join(
-                signature,
-                pair.snd.getSourceFile().getName(),
-                lines.getLineNumber(pair.fst.pos().getStartPosition()),
-                lines.getColumnNumber(pair.fst.pos().getStartPosition()),
-                lines.getLineNumber(pair.fst.pos().getEndPosition(pair.snd.endPositions)),
-                lines.getColumnNumber(pair.fst.pos().getEndPosition(pair.snd.endPositions)),
-                encodeAnnotationProperties(unsupportedAppUsage));
-    }
-
-    /**
-     * This is the main entry point in the processor, called by the compiler.
-     */
-    @Override
-    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
-        Map<String, Element> signatureMap = new TreeMap<>();
-        SignatureBuilder sb = new SignatureBuilder(processingEnv.getMessager());
-        for (Class<? extends Annotation> supportedAnnotation : SUPPORTED_ANNOTATIONS) {
-            Set<? extends Element> annotated = roundEnv.getElementsAnnotatedWith(
-                    supportedAnnotation);
-            if (annotated.size() == 0) {
-                continue;
-            }
-            // Build signatures for each annotated member and put them in a map from signature to
-            // member.
-            for (Element e : annotated) {
-                String sig = sb.buildSignature(supportedAnnotation, e);
-                if (sig != null) {
-                    signatureMap.put(sig, e);
-                }
-            }
-        }
-
-        if (!signatureMap.isEmpty()) {
-            try {
-                writeToFile(INDEX_CSV,
-                        getCsvHeaders(),
-                        signatureMap.entrySet()
-                                .stream()
-                                .map(e -> getAnnotationIndex(e.getKey(), e.getValue())));
-            } catch (IOException e) {
-                throw new RuntimeException("Failed to write output", e);
-            }
-        }
-        return true;
-    }
-}
diff --git a/tools/processors/unsupportedappusage/test/Android.bp b/tools/processors/unsupportedappusage/test/Android.bp
deleted file mode 100644
index 49ea3d4..0000000
--- a/tools/processors/unsupportedappusage/test/Android.bp
+++ /dev/null
@@ -1,28 +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_test_host {
-    name: "unsupportedappusage-processor-test",
-
-    srcs: ["src/**/*.java"],
-
-    static_libs: [
-        "libjavac",
-        "unsupportedappusage-annotation-processor-lib",
-        "truth-host-prebuilt",
-        "mockito-host",
-        "junit-host",
-        "objenesis",
-    ],
-}
diff --git a/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/CsvReader.java b/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/CsvReader.java
deleted file mode 100644
index 23db99e..0000000
--- a/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/CsvReader.java
+++ /dev/null
@@ -1,61 +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.processor.unsupportedappusage;
-
-import com.google.common.base.Splitter;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class CsvReader {
-
-    private final Splitter mSplitter;
-    private final List<String> mColumns;
-    private final List<Map<String, String>> mContents;
-
-    public CsvReader(InputStream in) throws IOException {
-        mSplitter = Splitter.on(",");
-        BufferedReader br = new BufferedReader(new InputStreamReader(in));
-        mColumns = mSplitter.splitToList(br.readLine());
-        mContents = new ArrayList<>();
-        String line = br.readLine();
-        while (line != null) {
-            List<String> contents = mSplitter.splitToList(line);
-            Map<String, String> contentMap = new HashMap<>();
-            for (int i = 0; i < Math.min(contents.size(), mColumns.size()); ++i) {
-                contentMap.put(mColumns.get(i), contents.get(i));
-            }
-            mContents.add(contentMap);
-            line = br.readLine();
-        }
-        br.close();
-    }
-
-    public List<String> getColumns() {
-        return mColumns;
-    }
-
-    public List<Map<String, String>> getContents() {
-        return mContents;
-    }
-}
diff --git a/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessorTest.java b/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessorTest.java
deleted file mode 100644
index 012e88f..0000000
--- a/tools/processors/unsupportedappusage/test/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessorTest.java
+++ /dev/null
@@ -1,96 +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.processor.unsupportedappusage;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.android.javac.Javac;
-
-import com.google.common.base.Joiner;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.io.IOException;
-import java.util.Map;
-
-public class UnsupportedAppUsageProcessorTest {
-
-    private Javac mJavac;
-
-    @Before
-    public void setup() throws IOException {
-        mJavac = new Javac();
-        mJavac.addSource("dalvik.annotation.compat.UnsupportedAppUsage", Joiner.on('\n').join(
-                "package dalvik.annotation.compat;",
-                "public @interface UnsupportedAppUsage {",
-                "    String expectedSignature() default \"\";\n",
-                "    String someProperty() default \"\";",
-                "}"));
-    }
-
-    private CsvReader compileAndReadCsv() throws IOException {
-        mJavac.compileWithAnnotationProcessor(new UnsupportedAppUsageProcessor());
-        return new CsvReader(
-                mJavac.getOutputFile("unsupportedappusage/unsupportedappusage_index.csv"));
-    }
-
-    @Test
-    public void testSignatureFormat() throws Exception {
-        mJavac.addSource("a.b.Class", Joiner.on('\n').join(
-                "package a.b;",
-                "import dalvik.annotation.compat.UnsupportedAppUsage;",
-                "public class Class {",
-                "  @UnsupportedAppUsage",
-                "  public void method() {}",
-                "}"));
-        assertThat(compileAndReadCsv().getContents().get(0)).containsEntry(
-                "signature", "La/b/Class;->method()V"
-        );
-    }
-
-    @Test
-    public void testSourcePosition() throws Exception {
-        mJavac.addSource("a.b.Class", Joiner.on('\n').join(
-                "package a.b;", // 1
-                "import dalvik.annotation.compat.UnsupportedAppUsage;", // 2
-                "public class Class {", // 3
-                "  @UnsupportedAppUsage", // 4
-                "  public void method() {}", // 5
-                "}"));
-        Map<String, String> row = compileAndReadCsv().getContents().get(0);
-        assertThat(row).containsEntry("startline", "4");
-        assertThat(row).containsEntry("startcol", "3");
-        assertThat(row).containsEntry("endline", "4");
-        assertThat(row).containsEntry("endcol", "23");
-    }
-
-    @Test
-    public void testAnnotationProperties() throws Exception {
-        mJavac.addSource("a.b.Class", Joiner.on('\n').join(
-                "package a.b;", // 1
-                "import dalvik.annotation.compat.UnsupportedAppUsage;", // 2
-                "public class Class {", // 3
-                "  @UnsupportedAppUsage(someProperty=\"value\")", // 4
-                "  public void method() {}", // 5
-                "}"));
-        assertThat(compileAndReadCsv().getContents().get(0)).containsEntry(
-                "properties", "someProperty=%22value%22");
-    }
-
-
-}
diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp
index 4899fbd..d45c4e7 100644
--- a/tools/stats_log_api_gen/java_writer.cpp
+++ b/tools/stats_log_api_gen/java_writer.cpp
@@ -83,7 +83,7 @@
         // Print method body.
         string indent("");
         if (DEFAULT_MODULE_NAME != moduleName) {
-            fprintf(out, "        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n");
+            fprintf(out, "        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {\n");
             indent = "    ";
         }
 
@@ -116,16 +116,19 @@
                 fprintf(out, "%s        builder.writeString(arg%d);\n", indent.c_str(), argIndex);
                 break;
             case JAVA_TYPE_BYTE_ARRAY:
-                fprintf(out, "%s        builder.writeByteArray(arg%d);\n",
-                        indent.c_str(), argIndex);
+                fprintf(out, "%s        builder.writeByteArray(null == arg%d ? new byte[0] : arg%d);\n",
+                        indent.c_str(), argIndex, argIndex);
                 break;
             case JAVA_TYPE_ATTRIBUTION_CHAIN:
             {
                 const char* uidName = attributionDecl.fields.front().name.c_str();
                 const char* tagName = attributionDecl.fields.back().name.c_str();
 
-                fprintf(out, "%s        builder.writeAttributionChain(%s, %s);\n",
-                        indent.c_str(), uidName, tagName);
+                fprintf(out, "%s        builder.writeAttributionChain(\n", indent.c_str());
+                fprintf(out, "%s                null == %s ? new int[0] : %s,\n",
+                        indent.c_str(), uidName, uidName);
+                fprintf(out, "%s                null == %s ? new String[0] : %s);\n",
+                        indent.c_str(), tagName, tagName);
                 break;
             }
             case JAVA_TYPE_KEY_VALUE_PAIR:
diff --git a/wifi/java/android/net/wifi/IOnWifiActivityEnergyInfoListener.aidl b/wifi/java/android/net/wifi/IOnWifiActivityEnergyInfoListener.aidl
new file mode 100644
index 0000000..7e25fd8a
--- /dev/null
+++ b/wifi/java/android/net/wifi/IOnWifiActivityEnergyInfoListener.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.os.connectivity.WifiActivityEnergyInfo;
+
+/**
+ * Interface for Wi-Fi activity energy info listener.
+ *
+ * @hide
+ */
+oneway interface IOnWifiActivityEnergyInfoListener
+{
+    /**
+     * Service to manager callback providing current Wi-Fi activity energy info.
+     * @param info the Wi-Fi activity energy info
+     */
+    void onWifiActivityEnergyInfo(in WifiActivityEnergyInfo info);
+}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 4a89c66..b52880e 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -28,15 +28,15 @@
 import android.net.wifi.IDppCallback;
 import android.net.wifi.ILocalOnlyHotspotCallback;
 import android.net.wifi.INetworkRequestMatchCallback;
+import android.net.wifi.IOnWifiActivityEnergyInfoListener;
+import android.net.wifi.IOnWifiUsabilityStatsListener;
 import android.net.wifi.IScanResultsCallback;
 import android.net.wifi.ISoftApCallback;
 import android.net.wifi.ISuggestionConnectionStatusListener;
 import android.net.wifi.ITrafficStateCallback;
 import android.net.wifi.ITxPacketCountListener;
-import android.net.wifi.IOnWifiUsabilityStatsListener;
 import android.net.wifi.ScanResult;
 import android.net.wifi.SoftApConfiguration;
-import android.net.wifi.WifiActivityEnergyInfo;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiNetworkSuggestion;
@@ -54,15 +54,7 @@
 {
     long getSupportedFeatures();
 
-    WifiActivityEnergyInfo reportActivityInfo();
-
-    /**
-     * Requests the controller activity info asynchronously.
-     * The implementor is expected to reply with the
-     * {@link android.net.wifi.WifiActivityEnergyInfo} object placed into the Bundle with the key
-     * {@link android.os.BatteryStats#RESULT_RECEIVER_CONTROLLER_KEY}. The result code is ignored.
-     */
-    oneway void requestActivityInfo(in ResultReceiver result);
+    oneway void getWifiActivityEnergyInfoAsync(in IOnWifiActivityEnergyInfoListener listener);
 
     ParceledListSlice getConfiguredNetworks(String packageName, String featureId);
 
@@ -142,6 +134,8 @@
 
     boolean startSoftAp(in WifiConfiguration wifiConfig);
 
+    boolean startTetheredHotspot(in SoftApConfiguration softApConfig);
+
     boolean stopSoftAp();
 
     int startLocalOnlyHotspot(in ILocalOnlyHotspotCallback callback, String packageName,
@@ -159,8 +153,14 @@
     @UnsupportedAppUsage
     WifiConfiguration getWifiApConfiguration();
 
+    SoftApConfiguration getSoftApConfiguration();
+
     boolean setWifiApConfiguration(in WifiConfiguration wifiConfig, String packageName);
 
+    boolean setSoftApConfiguration(in SoftApConfiguration softApConfig, String packageName);
+
+    void notifyUserOfApBandConversion(String packageName);
+
     void enableTdls(String remoteIPAddress, boolean enable);
 
     void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable);
@@ -184,6 +184,10 @@
 
     void restoreBackupData(in byte[] data);
 
+    byte[] retrieveSoftApBackupData();
+
+    void restoreSoftApBackupData(in byte[] data);
+
     void restoreSupplicantBackupData(in byte[] supplicantData, in byte[] ipConfigData);
 
     void startSubscriptionProvisioning(in OsuProvider provider, in IProvisioningCallback callback);
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 9956901..729ef61 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -499,6 +499,13 @@
 
     /**
      * @hide
+     */
+    public boolean is6GHz() {
+        return ScanResult.is6GHz(frequency);
+    }
+
+    /**
+     * @hide
      * TODO: makes real freq boundaries
      */
     public static boolean is5GHz(int freq) {
@@ -506,6 +513,13 @@
     }
 
     /**
+     * @hide
+     */
+    public static boolean is6GHz(int freq) {
+        return freq > 5925 && freq < 7125;
+    }
+
+    /**
      *  @hide
      * anqp lines from supplicant BSS response
      */
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
index 4cc8653..d755053 100644
--- a/wifi/java/android/net/wifi/SoftApConfiguration.java
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -16,28 +16,34 @@
 
 package android.net.wifi;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.net.MacAddress;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.TextUtils;
 
 import com.android.internal.util.Preconditions;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.charset.CharsetEncoder;
 import java.nio.charset.StandardCharsets;
 import java.util.Objects;
 import java.util.concurrent.Executor;
 
 /**
- * WiFi configuration for a soft access point (a.k.a. Soft AP, SAP, Hotspot).
+ * Configuration for a soft access point (a.k.a. Soft AP, SAP, Hotspot).
  *
  * This is input for the framework provided by a client app, i.e. it exposes knobs to instruct the
- * framework how it should open a hotspot.  It is not meant to describe the network as it will be
- * seen by clients; this role is currently served by {@link WifiConfiguration} (see
- * {@link WifiManager.LocalOnlyHotspotReservation#getWifiConfiguration()}).
+ * framework how it should configure a hotspot.
  *
- * System apps can use this to configure a local-only hotspot using
+ * System apps can use this to configure a tethered hotspot using
+ * {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} and
+ * {@link WifiManager#setSoftApConfiguration(SoftApConfiguration)}
+ * or local-only hotspot using
  * {@link WifiManager#startLocalOnlyHotspot(SoftApConfiguration, Executor,
  * WifiManager.LocalOnlyHotspotCallback)}.
  *
@@ -48,25 +54,106 @@
  */
 @SystemApi
 public final class SoftApConfiguration implements Parcelable {
+
+    /**
+     * 2GHz band.
+     * @hide
+     */
+    @SystemApi
+    public static final int BAND_2GHZ = 0;
+
+    /**
+     * 5GHz band.
+     * @hide
+     */
+    @SystemApi
+    public static final int BAND_5GHZ = 1;
+
+    /**
+     * Device is allowed to choose the optimal band (2Ghz or 5Ghz) based on device capability,
+     * operating country code and current radio conditions.
+     * @hide
+     */
+    @SystemApi
+    public static final int BAND_ANY = -1;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "BAND_TYPE_" }, value = {
+            BAND_2GHZ,
+            BAND_5GHZ,
+            BAND_ANY,
+    })
+    public @interface BandType {}
+
     /**
      * SSID for the AP, or null for a framework-determined SSID.
      */
     private final @Nullable String mSsid;
+
     /**
      * BSSID for the AP, or null to use a framework-determined BSSID.
      */
     private final @Nullable MacAddress mBssid;
+
     /**
      * Pre-shared key for WPA2-PSK encryption (non-null enables WPA2-PSK).
      */
     private final @Nullable String mWpa2Passphrase;
 
+    /**
+     * This is a network that does not broadcast its SSID, so an
+     * SSID-specific probe request must be used for scans.
+     */
+    private final boolean mHiddenSsid;
+
+    /**
+     * The operating band of the AP.
+     * One of the band types from {@link @BandType}.
+     */
+    private final @BandType int mBand;
+
+    /**
+     * The operating channel of the AP.
+     */
+    private final int mChannel;
+
+    /**
+     * The operating security type of the AP.
+     * One of the security types from {@link @SecurityType}
+     */
+    private final @SecurityType int mSecurityType;
+
+    /**
+     * Security types we support.
+     */
+    /** @hide */
+    @SystemApi
+    public static final int SECURITY_TYPE_OPEN = 0;
+
+    /** @hide */
+    @SystemApi
+    public static final int SECURITY_TYPE_WPA2_PSK = 1;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "SECURITY_TYPE" }, value = {
+        SECURITY_TYPE_OPEN,
+        SECURITY_TYPE_WPA2_PSK,
+    })
+    public @interface SecurityType {}
+
     /** Private constructor for Builder and Parcelable implementation. */
-    private SoftApConfiguration(
-            @Nullable String ssid, @Nullable MacAddress bssid, String wpa2Passphrase) {
+    private SoftApConfiguration(@Nullable String ssid, @Nullable MacAddress bssid,
+            @Nullable String wpa2Passphrase, boolean hiddenSsid, @BandType int band, int channel,
+            @SecurityType int securityType) {
         mSsid = ssid;
         mBssid = bssid;
         mWpa2Passphrase = wpa2Passphrase;
+        mHiddenSsid = hiddenSsid;
+        mBand = band;
+        mChannel = channel;
+        mSecurityType = securityType;
     }
 
     @Override
@@ -80,12 +167,31 @@
         SoftApConfiguration other = (SoftApConfiguration) otherObj;
         return Objects.equals(mSsid, other.mSsid)
                 && Objects.equals(mBssid, other.mBssid)
-                && Objects.equals(mWpa2Passphrase, other.mWpa2Passphrase);
+                && Objects.equals(mWpa2Passphrase, other.mWpa2Passphrase)
+                && mHiddenSsid == other.mHiddenSsid
+                && mBand == other.mBand
+                && mChannel == other.mChannel
+                && mSecurityType == other.mSecurityType;
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mSsid, mBssid, mWpa2Passphrase);
+        return Objects.hash(mSsid, mBssid, mWpa2Passphrase, mHiddenSsid,
+                mBand, mChannel, mSecurityType);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sbuf = new StringBuilder();
+        sbuf.append("ssid=").append(mSsid);
+        if (mBssid != null) sbuf.append(" \n bssid=").append(mBssid.toString());
+        sbuf.append(" \n Wpa2Passphrase =").append(
+                TextUtils.isEmpty(mWpa2Passphrase) ? "<empty>" : "<non-empty>");
+        sbuf.append(" \n HiddenSsid =").append(mHiddenSsid);
+        sbuf.append(" \n Band =").append(mBand);
+        sbuf.append(" \n Channel =").append(mChannel);
+        sbuf.append(" \n SecurityType=").append(getSecurityType());
+        return sbuf.toString();
     }
 
     @Override
@@ -93,6 +199,10 @@
         dest.writeString(mSsid);
         dest.writeParcelable(mBssid, flags);
         dest.writeString(mWpa2Passphrase);
+        dest.writeBoolean(mHiddenSsid);
+        dest.writeInt(mBand);
+        dest.writeInt(mChannel);
+        dest.writeInt(mSecurityType);
     }
 
     @Override
@@ -107,7 +217,7 @@
             return new SoftApConfiguration(
                     in.readString(),
                     in.readParcelable(MacAddress.class.getClassLoader()),
-                    in.readString());
+                    in.readString(), in.readBoolean(), in.readInt(), in.readInt(), in.readInt());
         }
 
         @Override
@@ -116,22 +226,68 @@
         }
     };
 
+    /**
+     * Return String set to be the SSID for the AP.
+     * {@link #setSsid(String)}.
+     */
     @Nullable
     public String getSsid() {
         return mSsid;
     }
 
+    /**
+     * Returns MAC address set to be BSSID for the AP.
+     * {@link #setBssid(MacAddress)}.
+     */
     @Nullable
     public MacAddress getBssid() {
         return mBssid;
     }
 
+    /**
+     * Returns String set to be passphrase for the WPA2-PSK AP.
+     * {@link #setWpa2Passphrase(String)}.
+     */
     @Nullable
     public String getWpa2Passphrase() {
         return mWpa2Passphrase;
     }
 
     /**
+     * Returns Boolean set to be indicate hidden (true: doesn't broadcast its SSID) or
+     * not (false: broadcasts its SSID) for the AP.
+     * {@link #setHiddenSsid(boolean)}.
+     */
+    public boolean isHiddenSsid() {
+        return mHiddenSsid;
+    }
+
+    /**
+     * Returns {@link BandType} set to be the band for the AP.
+     * {@link #setBand(@BandType int)}.
+     */
+    public @BandType int getBand() {
+        return mBand;
+    }
+
+    /**
+     * Returns Integer set to be the channel for the AP.
+     * {@link #setChannel(int)}.
+     */
+    public int getChannel() {
+        return mChannel;
+    }
+
+    /**
+     * Get security type params which depends on which security passphrase to set.
+     *
+     * @return One of the security types from {@link SecurityType}.
+     */
+    public @SecurityType int getSecurityType() {
+        return mSecurityType;
+    }
+
+    /**
      * Builds a {@link SoftApConfiguration}, which allows an app to configure various aspects of a
      * Soft AP.
      *
@@ -142,6 +298,21 @@
         private String mSsid;
         private MacAddress mBssid;
         private String mWpa2Passphrase;
+        private boolean mHiddenSsid;
+        private int mBand;
+        private int mChannel;
+
+        private int setSecurityType() {
+            int securityType = SECURITY_TYPE_OPEN;
+            if (!TextUtils.isEmpty(mWpa2Passphrase)) { // WPA2-PSK network.
+                securityType = SECURITY_TYPE_WPA2_PSK;
+            }
+            return securityType;
+        }
+
+        private void clearAllPassphrase() {
+            mWpa2Passphrase = null;
+        }
 
         /**
          * Constructs a Builder with default values (see {@link Builder}).
@@ -150,6 +321,9 @@
             mSsid = null;
             mBssid = null;
             mWpa2Passphrase = null;
+            mHiddenSsid = false;
+            mBand = BAND_2GHZ;
+            mChannel = 0;
         }
 
         /**
@@ -161,6 +335,9 @@
             mSsid = other.mSsid;
             mBssid = other.mBssid;
             mWpa2Passphrase = other.mWpa2Passphrase;
+            mHiddenSsid = other.mHiddenSsid;
+            mBand = other.mBand;
+            mChannel = other.mChannel;
         }
 
         /**
@@ -170,11 +347,16 @@
          */
         @NonNull
         public SoftApConfiguration build() {
-            return new SoftApConfiguration(mSsid, mBssid, mWpa2Passphrase);
+            return new SoftApConfiguration(mSsid, mBssid, mWpa2Passphrase,
+                mHiddenSsid, mBand, mChannel, setSecurityType());
         }
 
         /**
          * Specifies an SSID for the AP.
+         * <p>
+         * Null SSID only support when configure a local-only hotspot.
+         * <p>
+         * <li>If not set, defaults to null.</li>
          *
          * @param ssid SSID of valid Unicode characters, or null to have the SSID automatically
          *             chosen by the framework.
@@ -193,7 +375,10 @@
 
         /**
          * Specifies a BSSID for the AP.
-         *
+         * <p>
+         * Only supported when configuring a local-only hotspot.
+         * <p>
+         * <li>If not set, defaults to null.</li>
          * @param bssid BSSID, or null to have the BSSID chosen by the framework. The caller is
          *              responsible for avoiding collisions.
          * @return Builder for chaining.
@@ -203,7 +388,7 @@
         @NonNull
         public Builder setBssid(@Nullable MacAddress bssid) {
             if (bssid != null) {
-                Preconditions.checkArgument(!bssid.equals(MacAddress.ALL_ZEROS_ADDRESS));
+                Preconditions.checkArgument(!bssid.equals(WifiManager.ALL_ZEROS_MAC_ADDRESS));
                 Preconditions.checkArgument(!bssid.equals(MacAddress.BROADCAST_ADDRESS));
             }
             mBssid = bssid;
@@ -211,8 +396,9 @@
         }
 
         /**
-         * Specifies that this AP should use WPA2-PSK with the given passphrase.  When set to null
-         * and no other encryption method is configured, an open network is created.
+         * Specifies that this AP should use WPA2-PSK with the given ASCII WPA2 passphrase.
+         * When set to null, an open network is created.
+         * <p>
          *
          * @param passphrase The passphrase to use, or null to unset a previously-set WPA2-PSK
          *                   configuration.
@@ -222,10 +408,72 @@
         @NonNull
         public Builder setWpa2Passphrase(@Nullable String passphrase) {
             if (passphrase != null) {
+                final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder();
+                if (!asciiEncoder.canEncode(passphrase)) {
+                    throw new IllegalArgumentException("passphrase not ASCII encodable");
+                }
                 Preconditions.checkStringNotEmpty(passphrase);
             }
+            clearAllPassphrase();
             mWpa2Passphrase = passphrase;
             return this;
         }
+
+        /**
+         * Specifies whether the AP is hidden (doesn't broadcast its SSID) or
+         * not (broadcasts its SSID).
+         * <p>
+         * <li>If not set, defaults to false (i.e not a hidden network).</li>
+         *
+         * @param hiddenSsid true for a hidden SSID, false otherwise.
+         * @return Builder for chaining.
+         */
+        @NonNull
+        public Builder setHiddenSsid(boolean hiddenSsid) {
+            mHiddenSsid = hiddenSsid;
+            return this;
+        }
+
+        /**
+         * Specifies the band for the AP.
+         * <p>
+         * <li>If not set, defaults to BAND_2GHZ {@link @BandType}.</li>
+         *
+         * @param band One of the band types from {@link @BandType}.
+         * @return Builder for chaining.
+         */
+        @NonNull
+        public Builder setBand(@BandType int band) {
+            switch (band) {
+                case BAND_2GHZ:
+                    break;
+                case BAND_5GHZ:
+                    break;
+                case BAND_ANY:
+                    break;
+                default:
+                    throw new IllegalArgumentException("Invalid band type");
+            }
+            mBand = band;
+            return this;
+        }
+
+        /**
+         * Specifies the channel for the AP.
+         *
+         * The channel which AP resides on. Valid channels are country dependent.
+         * Use the special channel value 0 to have the framework auto-select a valid channel
+         * from the band configured with {@link #setBand(@BandType int)}.
+         *
+         * <p>
+         * <li>If not set, defaults to 0.</li>
+         * @param channel operating channel of the AP.
+         * @return Builder for chaining.
+         */
+        @NonNull
+        public Builder setChannel(int channel) {
+            mChannel = channel;
+            return this;
+        }
     }
 }
diff --git a/wifi/java/android/net/wifi/SynchronousExecutor.java b/wifi/java/android/net/wifi/SynchronousExecutor.java
new file mode 100644
index 0000000..9926b1b
--- /dev/null
+++ b/wifi/java/android/net/wifi/SynchronousExecutor.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net.wifi;
+
+import java.util.concurrent.Executor;
+
+/**
+ * An executor implementation that runs synchronously on the current thread.
+ * @hide
+ */
+public class SynchronousExecutor implements Executor {
+    @Override
+    public void execute(Runnable r) {
+        r.run();
+    }
+}
diff --git a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.aidl b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.aidl
deleted file mode 100644
index 007ec94..0000000
--- a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi;
-
-parcelable WifiActivityEnergyInfo;
diff --git a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
deleted file mode 100644
index 0f7fc2d..0000000
--- a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Arrays;
-
-/**
- * Record of energy and activity information from controller and
- * underlying wifi stack state. Timestamp the record with elapsed
- * real-time.
- * @hide
- */
-public final class WifiActivityEnergyInfo implements Parcelable {
-    /**
-     * @hide
-     */
-    public long mTimestamp;
-
-    /**
-     * @hide
-     */
-    public int mStackState;
-
-    /**
-     * @hide
-     */
-    public long mControllerTxTimeMs;
-
-    /**
-     * @hide
-     */
-    public long[] mControllerTxTimePerLevelMs;
-
-    /**
-     * @hide
-     */
-    public long mControllerRxTimeMs;
-
-    /**
-     * @hide
-     */
-    public long mControllerScanTimeMs;
-
-    /**
-     * @hide
-     */
-    public long mControllerIdleTimeMs;
-
-    /**
-     * @hide
-     */
-    public long mControllerEnergyUsed;
-
-    public static final int STACK_STATE_INVALID = 0;
-    public static final int STACK_STATE_STATE_ACTIVE = 1;
-    public static final int STACK_STATE_STATE_SCANNING = 2;
-    public static final int STACK_STATE_STATE_IDLE = 3;
-
-    public WifiActivityEnergyInfo(long timestamp, int stackState,
-                                  long txTime, long[] txTimePerLevel, long rxTime, long scanTime,
-                                  long idleTime, long energyUsed) {
-        mTimestamp = timestamp;
-        mStackState = stackState;
-        mControllerTxTimeMs = txTime;
-        mControllerTxTimePerLevelMs = txTimePerLevel;
-        mControllerRxTimeMs = rxTime;
-        mControllerScanTimeMs = scanTime;
-        mControllerIdleTimeMs = idleTime;
-        mControllerEnergyUsed = energyUsed;
-    }
-
-    @Override
-    public String toString() {
-        return "WifiActivityEnergyInfo{"
-            + " timestamp=" + mTimestamp
-            + " mStackState=" + mStackState
-            + " mControllerTxTimeMs=" + mControllerTxTimeMs
-            + " mControllerTxTimePerLevelMs=" + Arrays.toString(mControllerTxTimePerLevelMs)
-            + " mControllerRxTimeMs=" + mControllerRxTimeMs
-            + " mControllerScanTimeMs=" + mControllerScanTimeMs
-            + " mControllerIdleTimeMs=" + mControllerIdleTimeMs
-            + " mControllerEnergyUsed=" + mControllerEnergyUsed
-            + " }";
-    }
-
-    public static final @android.annotation.NonNull Parcelable.Creator<WifiActivityEnergyInfo> CREATOR =
-            new Parcelable.Creator<WifiActivityEnergyInfo>() {
-        public WifiActivityEnergyInfo createFromParcel(Parcel in) {
-            long timestamp = in.readLong();
-            int stackState = in.readInt();
-            long txTime = in.readLong();
-            long[] txTimePerLevel = in.createLongArray();
-            long rxTime = in.readLong();
-            long scanTime = in.readLong();
-            long idleTime = in.readLong();
-            long energyUsed = in.readLong();
-            return new WifiActivityEnergyInfo(timestamp, stackState,
-                    txTime, txTimePerLevel, rxTime, scanTime, idleTime, energyUsed);
-        }
-        public WifiActivityEnergyInfo[] newArray(int size) {
-            return new WifiActivityEnergyInfo[size];
-        }
-    };
-
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeLong(mTimestamp);
-        out.writeInt(mStackState);
-        out.writeLong(mControllerTxTimeMs);
-        out.writeLongArray(mControllerTxTimePerLevelMs);
-        out.writeLong(mControllerRxTimeMs);
-        out.writeLong(mControllerScanTimeMs);
-        out.writeLong(mControllerIdleTimeMs);
-        out.writeLong(mControllerEnergyUsed);
-    }
-
-    public int describeContents() {
-        return 0;
-    }
-
-    /**
-     * @return bt stack reported state
-     */
-    public int getStackState() {
-        return mStackState;
-    }
-
-    /**
-     * @return tx time in ms
-     */
-    public long getControllerTxTimeMillis() {
-        return mControllerTxTimeMs;
-    }
-
-    /**
-     * @return tx time at power level provided in ms
-     */
-    public long getControllerTxTimeMillisAtLevel(int level) {
-        if (level < mControllerTxTimePerLevelMs.length) {
-            return mControllerTxTimePerLevelMs[level];
-        }
-        return 0;
-    }
-
-    /**
-     * @return rx time in ms
-     */
-    public long getControllerRxTimeMillis() {
-        return mControllerRxTimeMs;
-    }
-
-    /**
-     * @return scan time in ms
-     */
-    public long getControllerScanTimeMillis() {
-        return mControllerScanTimeMs;
-    }
-
-    /**
-     * @return idle time in ms
-     */
-    public long getControllerIdleTimeMillis() {
-        return mControllerIdleTimeMs;
-    }
-
-    /**
-     * product of current(mA), voltage(V) and time(ms)
-     * @return energy used
-     */
-    public long getControllerEnergyUsed() {
-        return mControllerEnergyUsed;
-    }
-    /**
-     * @return timestamp(wall clock) of record creation
-     */
-    public long getTimeStamp() {
-        return mTimestamp;
-    }
-
-    /**
-     * @return if the record is valid
-     */
-    public boolean isValid() {
-        return ((mControllerTxTimeMs >=0) &&
-                (mControllerRxTimeMs >=0) &&
-                (mControllerScanTimeMs >=0) &&
-                (mControllerIdleTimeMs >=0));
-    }
-}
\ No newline at end of file
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index dfdc075..d068fc6 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -39,7 +39,6 @@
 import android.util.BackupUtils;
 import android.util.Log;
 import android.util.SparseArray;
-import android.util.TimeUtils;
 
 import java.io.ByteArrayOutputStream;
 import java.io.DataInputStream;
@@ -49,6 +48,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
 import java.util.BitSet;
+import java.util.Calendar;
 import java.util.HashMap;
 
 /**
@@ -1984,8 +1984,8 @@
     public boolean isLinked(WifiConfiguration config) {
         if (config != null) {
             if (config.linkedConfigurations != null && linkedConfigurations != null) {
-                if (config.linkedConfigurations.get(configKey()) != null
-                        && linkedConfigurations.get(config.configKey()) != null) {
+                if (config.linkedConfigurations.get(getKey()) != null
+                        && linkedConfigurations.get(config.getKey()) != null) {
                     return true;
                 }
             }
@@ -2006,6 +2006,16 @@
                 && enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE;
     }
 
+    private static String logTimeOfDay(long millis) {
+        Calendar c = Calendar.getInstance();
+        if (millis >= 0) {
+            c.setTimeInMillis(millis);
+            return String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c);
+        } else {
+            return Long.toString(millis);
+        }
+    }
+
     @Override
     public String toString() {
         StringBuilder sbuf = new StringBuilder();
@@ -2042,7 +2052,7 @@
         if (mNetworkSelectionStatus.getConnectChoice() != null) {
             sbuf.append(" connect choice: ").append(mNetworkSelectionStatus.getConnectChoice());
             sbuf.append(" connect choice set time: ")
-                    .append(TimeUtils.logTimeOfDay(
+                    .append(logTimeOfDay(
                             mNetworkSelectionStatus.getConnectChoiceTimestamp()));
         }
         sbuf.append(" hasEverConnected: ")
@@ -2081,7 +2091,7 @@
         sbuf.append(" mRandomizedMacAddress: ").append(mRandomizedMacAddress).append("\n");
         sbuf.append(" randomizedMacExpirationTimeMs: ")
                 .append(randomizedMacExpirationTimeMs == 0 ? "<none>"
-                        : TimeUtils.logTimeOfDay(randomizedMacExpirationTimeMs)).append("\n");
+                        : logTimeOfDay(randomizedMacExpirationTimeMs)).append("\n");
         sbuf.append(" KeyMgmt:");
         for (int k = 0; k < this.allowedKeyManagement.size(); k++) {
             if (this.allowedKeyManagement.get(k)) {
@@ -2205,7 +2215,7 @@
 
         if (this.lastConnected != 0) {
             sbuf.append('\n');
-            sbuf.append("lastConnected: ").append(TimeUtils.logTimeOfDay(this.lastConnected));
+            sbuf.append("lastConnected: ").append(logTimeOfDay(this.lastConnected));
             sbuf.append(" ");
         }
         sbuf.append('\n');
@@ -2344,31 +2354,18 @@
         return KeyMgmt.NONE;
     }
 
-    /* @hide
-     * Cache the config key, this seems useful as a speed up since a lot of
-     * lookups in the config store are done and based on this key.
+    /**
+     * Return a String that can be used to uniquely identify this WifiConfiguration.
+     * <br />
+     * Note: Do not persist this value! This value is not guaranteed to remain backwards compatible.
      */
-    String mCachedConfigKey;
-
-    /** @hide
-     *  return the string used to calculate the hash in WifiConfigStore
-     *  and uniquely identify this WifiConfiguration
-     */
-    public String configKey(boolean allowCached) {
-        String key;
-        if (allowCached && mCachedConfigKey != null) {
-            key = mCachedConfigKey;
-        } else if (providerFriendlyName != null) {
-            key = FQDN + KeyMgmt.strings[KeyMgmt.WPA_EAP];
-            if (!shared) {
-                key += "-" + Integer.toString(UserHandle.getUserId(creatorUid));
-            }
-        } else {
-            key = getSsidAndSecurityTypeString();
-            if (!shared) {
-                key += "-" + Integer.toString(UserHandle.getUserId(creatorUid));
-            }
-            mCachedConfigKey = key;
+    @NonNull
+    public String getKey() {
+        String key = providerFriendlyName == null
+                ? getSsidAndSecurityTypeString()
+                : FQDN + KeyMgmt.strings[KeyMgmt.WPA_EAP];
+        if (!shared) {
+            key += "-" + UserHandle.getUserHandleForUid(creatorUid).getIdentifier();
         }
         return key;
     }
@@ -2397,13 +2394,6 @@
         return key;
     }
 
-    /** @hide
-     * get configKey, force calculating the config string
-     */
-    public String configKey() {
-        return configKey(false);
-    }
-
     /** @hide */
     @UnsupportedAppUsage
     public IpConfiguration getIpConfiguration() {
@@ -2446,13 +2436,13 @@
     @NonNull
     @SystemApi
     public IpConfiguration.IpAssignment getIpAssignment() {
-        return mIpConfiguration.ipAssignment;
+        return mIpConfiguration.getIpAssignment();
     }
 
     /** @hide */
     @UnsupportedAppUsage
     public void setIpAssignment(IpConfiguration.IpAssignment ipAssignment) {
-        mIpConfiguration.ipAssignment = ipAssignment;
+        mIpConfiguration.setIpAssignment(ipAssignment);
     }
 
     /**
@@ -2462,13 +2452,13 @@
     @NonNull
     @SystemApi
     public IpConfiguration.ProxySettings getProxySettings() {
-        return mIpConfiguration.proxySettings;
+        return mIpConfiguration.getProxySettings();
     }
 
     /** @hide */
     @UnsupportedAppUsage
     public void setProxySettings(IpConfiguration.ProxySettings proxySettings) {
-        mIpConfiguration.proxySettings = proxySettings;
+        mIpConfiguration.setProxySettings(proxySettings);
     }
 
     /**
@@ -2477,10 +2467,10 @@
      *                  WifiConfiguration, or {@code null} if no proxy is specified.
      */
     public ProxyInfo getHttpProxy() {
-        if (mIpConfiguration.proxySettings == IpConfiguration.ProxySettings.NONE) {
+        if (mIpConfiguration.getProxySettings() == IpConfiguration.ProxySettings.NONE) {
             return null;
         }
-        return new ProxyInfo(mIpConfiguration.httpProxy);
+        return new ProxyInfo(mIpConfiguration.getHttpProxy());
     }
 
     /**
@@ -2505,12 +2495,12 @@
         if (!Uri.EMPTY.equals(httpProxy.getPacFileUrl())) {
             proxySettingCopy = IpConfiguration.ProxySettings.PAC;
             // Construct a new PAC URL Proxy
-            httpProxyCopy = new ProxyInfo(httpProxy.getPacFileUrl(), httpProxy.getPort());
+            httpProxyCopy = ProxyInfo.buildPacProxy(httpProxy.getPacFileUrl(), httpProxy.getPort());
         } else {
             proxySettingCopy = IpConfiguration.ProxySettings.STATIC;
             // Construct a new HTTP Proxy
-            httpProxyCopy = new ProxyInfo(httpProxy.getHost(), httpProxy.getPort(),
-                    httpProxy.getExclusionListAsString());
+            httpProxyCopy = ProxyInfo.buildDirectProxy(httpProxy.getHost(), httpProxy.getPort(),
+                    Arrays.asList(httpProxy.getExclusionList()));
         }
         if (!httpProxyCopy.isValid()) {
             throw new IllegalArgumentException("Invalid ProxyInfo: " + httpProxyCopy.toString());
@@ -2525,8 +2515,8 @@
      */
     @SystemApi
     public void setProxy(@NonNull ProxySettings settings, @NonNull ProxyInfo proxy) {
-        mIpConfiguration.proxySettings = settings;
-        mIpConfiguration.httpProxy = proxy;
+        mIpConfiguration.setProxySettings(settings);
+        mIpConfiguration.setHttpProxy(proxy);
     }
 
     /** Implement the Parcelable interface {@hide} */
@@ -2589,7 +2579,6 @@
                 linkedConfigurations = new HashMap<String, Integer>();
                 linkedConfigurations.putAll(source.linkedConfigurations);
             }
-            mCachedConfigKey = null; //force null configKey
             validatedInternetAccess = source.validatedInternetAccess;
             isLegacyPasspointConfig = source.isLegacyPasspointConfig;
             ephemeral = source.ephemeral;
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index f3f873b..f728491 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -21,7 +21,7 @@
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkUtils;
+import android.net.shared.Inet4AddressUtils;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -708,7 +708,7 @@
     public int getIpAddress() {
         int result = 0;
         if (mIpAddress instanceof Inet4Address) {
-            result = NetworkUtils.inetAddressToInt((Inet4Address)mIpAddress);
+            result = Inet4AddressUtils.inet4AddressToIntHTL((Inet4Address) mIpAddress);
         }
         return result;
     }
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 9f866f7..86c398b 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -35,29 +35,27 @@
 import android.content.pm.ParceledListSlice;
 import android.net.ConnectivityManager;
 import android.net.DhcpInfo;
+import android.net.MacAddress;
 import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
 import android.net.NetworkStack;
 import android.net.wifi.hotspot2.IProvisioningCallback;
 import android.net.wifi.hotspot2.OsuProvider;
 import android.net.wifi.hotspot2.PasspointConfiguration;
 import android.net.wifi.hotspot2.ProvisioningCallback;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerExecutor;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.WorkSource;
+import android.os.connectivity.WifiActivityEnergyInfo;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.net.NetworkPinner;
 
 import dalvik.system.CloseGuard;
 
@@ -150,12 +148,11 @@
     @Deprecated
     public static final int ERROR_AUTH_FAILURE_EAP_FAILURE = 3;
 
-    /**
-     * Maximum number of active network suggestions allowed per app.
-     * @hide
-     */
-    public static final int NETWORK_SUGGESTIONS_MAX_PER_APP =
-            ActivityManager.isLowRamDeviceStatic() ? 256 : 1024;
+    /** @hide */
+    public static final int NETWORK_SUGGESTIONS_MAX_PER_APP_LOW_RAM = 256;
+
+    /** @hide */
+    public static final int NETWORK_SUGGESTIONS_MAX_PER_APP_HIGH_RAM = 1024;
 
     /**
      * Reason code if all of the network suggestions were successfully added or removed.
@@ -728,7 +725,9 @@
      * had been reset.
      * @hide
      */
-    public static final String WIFI_NETWORK_SETTINGS_RESET_ACTION =
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING)
+    public static final String ACTION_NETWORK_SETTINGS_RESET =
             "android.net.wifi.action.NETWORK_SETTINGS_RESET";
 
     /**
@@ -1189,6 +1188,10 @@
     /** Indicates an invalid SSID. */
     public static final String UNKNOWN_SSID = "<unknown ssid>";
 
+    /** @hide */
+    public static final MacAddress ALL_ZEROS_MAC_ADDRESS =
+            MacAddress.fromString("00:00:00:00:00:00");
+
     /* Number of currently active WifiLocks and MulticastLocks */
     @UnsupportedAppUsage
     private int mActiveLockCount;
@@ -1244,6 +1247,7 @@
      * <li>allowedAuthAlgorithms</li>
      * <li>allowedPairwiseCiphers</li>
      * <li>allowedGroupCiphers</li>
+     * <li>status</li>
      * </ul>
      * @return a list of network configurations in the form of a list
      * of {@link WifiConfiguration} objects.
@@ -1790,8 +1794,9 @@
 
     /**
      * Remove some or all of the network suggestions that were previously provided by the app.
-     * If the current network is a suggestion being removed and if it was only provided by this app
-     * and is not a saved network then the framework will immediately disconnect.
+     * If one of the suggestions being removed was used to establish connection to the current
+     * network, then the device will immediately disconnect from that network.
+     *
      * See {@link WifiNetworkSuggestion} for a detailed explanation of the parameters.
      * See {@link WifiNetworkSuggestion#equals(Object)} for the equivalence evaluation used.
      *
@@ -1833,7 +1838,15 @@
      * @see #removeNetworkSuggestions(List)
      */
     public int getMaxNumberOfNetworkSuggestionsPerApp() {
-        return NETWORK_SUGGESTIONS_MAX_PER_APP;
+        return getMaxNumberOfNetworkSuggestionsPerApp(
+                mContext.getSystemService(ActivityManager.class).isLowRamDevice());
+    }
+
+    /** @hide */
+    public static int getMaxNumberOfNetworkSuggestionsPerApp(boolean isLowRamDevice) {
+        return isLowRamDevice
+                ? NETWORK_SUGGESTIONS_MAX_PER_APP_LOW_RAM
+                : NETWORK_SUGGESTIONS_MAX_PER_APP_HIGH_RAM;
     }
 
     /**
@@ -2021,28 +2034,11 @@
      */
     @Deprecated
     public boolean enableNetwork(int netId, boolean attemptConnect) {
-        final boolean pin = attemptConnect && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP;
-        if (pin) {
-            NetworkRequest request = new NetworkRequest.Builder()
-                    .clearCapabilities()
-                    .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
-                    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
-                    .build();
-            NetworkPinner.pin(mContext, request);
-        }
-
-        boolean success;
         try {
-            success = mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName());
+            return mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
-
-        if (pin && !success) {
-            NetworkPinner.unpin();
-        }
-
-        return success;
     }
 
     /**
@@ -2383,19 +2379,76 @@
     }
 
     /**
-     * Return the record of {@link WifiActivityEnergyInfo} object that
-     * has the activity and energy info. This can be used to ascertain what
-     * the controller has been up to, since the last sample.
+     * Interface for Wi-Fi activity energy info listener. Should be implemented by applications and
+     * set when calling {@link WifiManager#getWifiActivityEnergyInfoAsync}.
      *
-     * @return a record with {@link WifiActivityEnergyInfo} or null if
-     * report is unavailable or unsupported
      * @hide
      */
-    public WifiActivityEnergyInfo getControllerActivityEnergyInfo() {
-        try {
-            synchronized(this) {
-                return mService.reportActivityInfo();
+    @SystemApi
+    public interface OnWifiActivityEnergyInfoListener {
+        /**
+         * Called when Wi-Fi activity energy info is available.
+         * Note: this listener is triggered at most once for each call to
+         * {@link #getWifiActivityEnergyInfoAsync}.
+         *
+         * @param info the latest {@link WifiActivityEnergyInfo}, or null if unavailable.
+         */
+        void onWifiActivityEnergyInfo(@Nullable WifiActivityEnergyInfo info);
+    }
+
+    private static class OnWifiActivityEnergyInfoProxy
+            extends IOnWifiActivityEnergyInfoListener.Stub {
+        private final Object mLock = new Object();
+        @Nullable @GuardedBy("mLock") private Executor mExecutor;
+        @Nullable @GuardedBy("mLock") private OnWifiActivityEnergyInfoListener mListener;
+
+        OnWifiActivityEnergyInfoProxy(Executor executor,
+                OnWifiActivityEnergyInfoListener listener) {
+            mExecutor = executor;
+            mListener = listener;
+        }
+
+        @Override
+        public void onWifiActivityEnergyInfo(WifiActivityEnergyInfo info) {
+            Executor executor;
+            OnWifiActivityEnergyInfoListener listener;
+            synchronized (mLock) {
+                if (mExecutor == null || mListener == null) {
+                    return;
+                }
+                executor = mExecutor;
+                listener = mListener;
+                // null out to allow garbage collection, prevent triggering listener more than once
+                mExecutor = null;
+                mListener = null;
             }
+            Binder.clearCallingIdentity();
+            executor.execute(() -> listener.onWifiActivityEnergyInfo(info));
+        }
+    }
+
+    /**
+     * Request to get the current {@link WifiActivityEnergyInfo} asynchronously.
+     * Note: This method will return null if {@link #isEnhancedPowerReportingSupported()} returns
+     * false.
+     *
+     * @param executor the executor that the listener will be invoked on
+     * @param listener the listener that will receive the {@link WifiActivityEnergyInfo} object
+     *                 when it becomes available. The listener will be triggered at most once for
+     *                 each call to this method.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(ACCESS_WIFI_STATE)
+    public void getWifiActivityEnergyInfoAsync(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnWifiActivityEnergyInfoListener listener) {
+        if (executor == null) throw new IllegalArgumentException("executor cannot be null");
+        if (listener == null) throw new IllegalArgumentException("listener cannot be null");
+        try {
+            mService.getWifiActivityEnergyInfoAsync(
+                    new OnWifiActivityEnergyInfoProxy(executor, listener));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2759,7 +2812,6 @@
      *
      * @hide
      */
-    @SystemApi
     @RequiresPermission(anyOf = {
             android.Manifest.permission.NETWORK_STACK,
             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
@@ -2773,6 +2825,31 @@
     }
 
     /**
+     * Start Soft AP (hotspot) mode for tethering purposes with the specified configuration.
+     * Note that starting Soft AP mode may disable station mode operation if the device does not
+     * support concurrency.
+     * @param softApConfig A valid SoftApConfiguration specifying the configuration of the SAP,
+     *                     or null to use the persisted Soft AP configuration that was previously
+     *                     set using {@link #setSoftApConfiguration(softApConfiguration)}.
+     * @return {@code true} if the operation succeeded, {@code false} otherwise
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_STACK,
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
+    })
+    public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig) {
+        try {
+            return mService.startTetheredHotspot(softApConfig);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+
+    /**
      * Stop SoftAp mode.
      * Note that stopping softap mode will restore the previous wifi mode.
      * @return {@code true} if the operation succeeds, {@code false} otherwise
@@ -3056,10 +3133,12 @@
      * Gets the Wi-Fi AP Configuration.
      * @return AP details in WifiConfiguration
      *
+     * @deprecated This API is deprecated. Use {@link #getSoftApConfiguration()} instead.
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
+    @Deprecated
     public WifiConfiguration getWifiApConfiguration() {
         try {
             return mService.getWifiApConfiguration();
@@ -3069,17 +3148,56 @@
     }
 
     /**
-     * Sets the Wi-Fi AP Configuration.  The AP configuration must either be open or
-     * WPA2 PSK networks.
+     * Gets the Wi-Fi AP Configuration.
+     * @return AP details in {@link SoftApConfiguration}
+     *
+     * @hide
+     */
+    @NonNull
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
+    public SoftApConfiguration getSoftApConfiguration() {
+        try {
+            return mService.getSoftApConfiguration();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Sets the Wi-Fi AP Configuration.
+     * @return {@code true} if the operation succeeded, {@code false} otherwise
+     *
+     * @deprecated This API is deprecated. Use {@link #setSoftApConfiguration(SoftApConfiguration)}
+     * instead.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
+    @Deprecated
+    public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
+        try {
+            return mService.setWifiApConfiguration(wifiConfig, mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Sets the Wi-Fi AP Configuration.
+     *
+     * @param softApConfig  A valid SoftApConfiguration specifying the configuration of the SAP.
+
      * @return {@code true} if the operation succeeded, {@code false} otherwise
      *
      * @hide
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
-    public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
+    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+    public boolean setSoftApConfiguration(@NonNull SoftApConfiguration softApConfig) {
         try {
-            return mService.setWifiApConfiguration(wifiConfig, mContext.getOpPackageName());
+            return mService.setSoftApConfiguration(
+                    softApConfig, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -4568,6 +4686,36 @@
     }
 
     /**
+     * Retrieve the soft ap config data to be backed to save current config data.
+     * @hide
+     */
+    @Nullable
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+    public byte[] retrieveSoftApBackupData() {
+        try {
+            return mService.retrieveSoftApBackupData();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Restore soft ap config from the backed up data.
+     * @hide
+     */
+    @Nullable
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+    public void restoreSoftApBackupData(@NonNull byte[] data) {
+        try {
+            mService.restoreSoftApBackupData(data);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Restore state from the older version of back up data.
      * The old backup data was essentially a backup of wpa_supplicant.conf
      * and ipconfig.txt file.
@@ -5104,9 +5252,9 @@
                                 Log.v(TAG, "OnWifiUsabilityStatsListener: "
                                         + "onWifiUsabilityStats: seqNum=" + seqNum);
                             }
-                            Binder.withCleanCallingIdentity(() ->
-                                    executor.execute(() -> listener.onWifiUsabilityStats(seqNum,
-                                            isSameBssidAndFreq, stats)));
+                            Binder.clearCallingIdentity();
+                            executor.execute(() -> listener.onWifiUsabilityStats(
+                                    seqNum, isSameBssidAndFreq, stats));
                         }
                     },
                     listener.hashCode()
diff --git a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
index 5a212a8..be37c22 100755
--- a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
+++ b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
@@ -22,7 +22,6 @@
 import android.content.Context;
 import android.net.INetworkScoreCache;
 import android.net.NetworkKey;
-import android.net.NetworkScoreManager;
 import android.net.ScoredNetwork;
 import android.os.Handler;
 import android.os.Process;
@@ -39,10 +38,10 @@
 /**
  * {@link INetworkScoreCache} implementation for Wifi Networks.
  *
+ * TODO: This should not be part of wifi mainline module.
  * @hide
  */
-public class WifiNetworkScoreCache extends INetworkScoreCache.Stub
-        implements NetworkScoreManager.NetworkScoreCallback {
+public class WifiNetworkScoreCache extends INetworkScoreCache.Stub {
     private static final String TAG = "WifiNetworkScoreCache";
     private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -248,17 +247,6 @@
     }
 
     @Override protected final void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
-        WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
-        dumpWithLatestScanResults(fd, writer, args, wifiManager.getScanResults());
-    }
-
-    /**
-     * This is directly invoked from within Wifi-Service (on it's instance of this class), hence
-     * avoid making the WifiManager.getScanResults() call to avoid a deadlock.
-     */
-    public final void dumpWithLatestScanResults(
-            FileDescriptor fd, PrintWriter writer, String[] args,
-            List<ScanResult> latestScanResults) {
         mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG);
         String header = String.format("WifiNetworkScoreCache (%s/%d)",
                 mContext.getPackageName(), Process.myUid());
@@ -269,7 +257,8 @@
                 writer.println("    " + score);
             }
             writer.println("  Network scores for latest ScanResults:");
-            for (ScanResult scanResult : latestScanResults) {
+            WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+            for (ScanResult scanResult : wifiManager.getScanResults()) {
                 writer.println(
                         "    " + buildNetworkKey(scanResult) + ": " + getNetworkScore(scanResult));
             }
diff --git a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
index ba9dd37..07afd7f 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
@@ -49,11 +49,11 @@
         private static final String MATCH_ALL_SSID_PATTERN_PATH = ".*";
         private static final String MATCH_EMPTY_SSID_PATTERN_PATH = "";
         private static final Pair<MacAddress, MacAddress> MATCH_NO_BSSID_PATTERN1 =
-                new Pair(MacAddress.BROADCAST_ADDRESS, MacAddress.BROADCAST_ADDRESS);
+                new Pair<>(MacAddress.BROADCAST_ADDRESS, MacAddress.BROADCAST_ADDRESS);
         private static final Pair<MacAddress, MacAddress> MATCH_NO_BSSID_PATTERN2 =
-                new Pair(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.BROADCAST_ADDRESS);
+                new Pair<>(WifiManager.ALL_ZEROS_MAC_ADDRESS, MacAddress.BROADCAST_ADDRESS);
         private static final Pair<MacAddress, MacAddress> MATCH_ALL_BSSID_PATTERN =
-                new Pair(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+                new Pair<>(WifiManager.ALL_ZEROS_MAC_ADDRESS, WifiManager.ALL_ZEROS_MAC_ADDRESS);
         private static final MacAddress MATCH_EXACT_BSSID_PATTERN_MASK =
                 MacAddress.BROADCAST_ADDRESS;
 
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 246e96f..9fd29ae 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -23,12 +23,10 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
-import android.app.ActivityThread;
 import android.net.MacAddress;
 import android.net.wifi.hotspot2.PasspointConfiguration;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.Process;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 
@@ -46,7 +44,6 @@
  * {@link WifiManager#addNetworkSuggestions(List)}.
  */
 public final class WifiNetworkSuggestion implements Parcelable {
-
     /**
      * Builder used to create {@link WifiNetworkSuggestion} objects.
      */
@@ -116,6 +113,16 @@
          */
         private int mCarrierId;
 
+        /**
+         * Whether this network is shared credential with user to allow user manually connect.
+         */
+        private boolean mIsUserAllowed;
+
+        /**
+         * Whether the setIsUserAllowedToManuallyConnect have been called.
+         */
+        private boolean mIsUserAllowedBeenSet;
+
         public Builder() {
             mSsid = null;
             mBssid =  null;
@@ -129,6 +136,8 @@
             mIsAppInteractionRequired = false;
             mIsUserInteractionRequired = false;
             mIsMetered = false;
+            mIsUserAllowed = true;
+            mIsUserAllowedBeenSet = false;
             mPriority = UNASSIGNED_PRIORITY;
             mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
         }
@@ -365,6 +374,27 @@
             return this;
         }
 
+        /**
+         * Specifies whether the network credentials provided with this suggestion can be used by
+         * the user to explicitly (manually) connect to this network. If true this network will
+         * appear in the Wi-Fi Picker (in Settings) and the user will be able to select and connect
+         * to it with the provided credentials. If false, the user will need to enter network
+         * credentials and the resulting configuration will become a user saved network.
+         * <p>
+         * <li>Note: Only valid for secure (non-open) networks.
+         * <li>If not set, defaults to true (i.e. allow user to manually connect) for secure
+         * networks and false for open networks.</li>
+         *
+         * @param isAllowed {@code true} to indicate that the credentials may be used by the user to
+         *                              manually connect to the network, {@code false} otherwise.
+         * @return Instance of {@link Builder} to enable chaining of the builder method.
+         */
+        public @NonNull Builder setIsUserAllowedToManuallyConnect(boolean isAllowed) {
+            mIsUserAllowed = isAllowed;
+            mIsUserAllowedBeenSet = true;
+            return this;
+        }
+
         private void setSecurityParamsInWifiConfiguration(
                 @NonNull WifiConfiguration configuration) {
             if (!TextUtils.isEmpty(mWpa2PskPassphrase)) { // WPA-PSK network.
@@ -512,10 +542,17 @@
                 }
                 if (mBssid != null
                         && (mBssid.equals(MacAddress.BROADCAST_ADDRESS)
-                        || mBssid.equals(MacAddress.ALL_ZEROS_ADDRESS))) {
+                        || mBssid.equals(WifiManager.ALL_ZEROS_MAC_ADDRESS))) {
                     throw new IllegalStateException("invalid bssid for suggestion");
                 }
                 wifiConfiguration = buildWifiConfiguration();
+                if (wifiConfiguration.isOpenNetwork()) {
+                    if (mIsUserAllowedBeenSet && mIsUserAllowed) {
+                        throw new IllegalStateException("Open network should not be "
+                                + "setIsUserAllowedToManuallyConnect to true");
+                    }
+                    mIsUserAllowed = false;
+                }
             }
 
             return new WifiNetworkSuggestion(
@@ -523,8 +560,7 @@
                     mPasspointConfiguration,
                     mIsAppInteractionRequired,
                     mIsUserInteractionRequired,
-                    Process.myUid(),
-                    ActivityThread.currentApplication().getApplicationContext().getOpPackageName());
+                    mIsUserAllowed);
         }
     }
 
@@ -551,18 +587,12 @@
      * @hide
      */
     public final boolean isUserInteractionRequired;
-
     /**
-     * The UID of the process initializing this network suggestion.
+     * Whether app share credential with the user, allow user use provided credential to
+     * connect network manually.
      * @hide
      */
-    public final int suggestorUid;
-
-    /**
-     * The package name of the process initializing this network suggestion.
-     * @hide
-     */
-    public final String suggestorPackageName;
+    public final boolean isUserAllowedToManuallyConnect;
 
     /** @hide */
     public WifiNetworkSuggestion() {
@@ -570,8 +600,7 @@
         this.passpointConfiguration = null;
         this.isAppInteractionRequired = false;
         this.isUserInteractionRequired = false;
-        this.suggestorUid = -1;
-        this.suggestorPackageName = null;
+        this.isUserAllowedToManuallyConnect = true;
     }
 
     /** @hide */
@@ -579,16 +608,14 @@
                                  @Nullable PasspointConfiguration passpointConfiguration,
                                  boolean isAppInteractionRequired,
                                  boolean isUserInteractionRequired,
-                                 int suggestorUid, @NonNull String suggestorPackageName) {
+                                 boolean isUserAllowedToManuallyConnect) {
         checkNotNull(networkConfiguration);
-        checkNotNull(suggestorPackageName);
         this.wifiConfiguration = networkConfiguration;
         this.passpointConfiguration = passpointConfiguration;
 
         this.isAppInteractionRequired = isAppInteractionRequired;
         this.isUserInteractionRequired = isUserInteractionRequired;
-        this.suggestorUid = suggestorUid;
-        this.suggestorPackageName = suggestorPackageName;
+        this.isUserAllowedToManuallyConnect = isUserAllowedToManuallyConnect;
     }
 
     public static final @NonNull Creator<WifiNetworkSuggestion> CREATOR =
@@ -600,8 +627,7 @@
                             in.readParcelable(null), // PasspointConfiguration
                             in.readBoolean(), // isAppInteractionRequired
                             in.readBoolean(), // isUserInteractionRequired
-                            in.readInt(), // suggestorUid
-                            in.readString() // suggestorPackageName
+                            in.readBoolean()  // isSharedCredentialWithUser
                     );
                 }
 
@@ -622,15 +648,13 @@
         dest.writeParcelable(passpointConfiguration, flags);
         dest.writeBoolean(isAppInteractionRequired);
         dest.writeBoolean(isUserInteractionRequired);
-        dest.writeInt(suggestorUid);
-        dest.writeString(suggestorPackageName);
+        dest.writeBoolean(isUserAllowedToManuallyConnect);
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(wifiConfiguration.SSID, wifiConfiguration.BSSID,
-                wifiConfiguration.allowedKeyManagement, wifiConfiguration.FQDN,
-                suggestorUid, suggestorPackageName);
+                wifiConfiguration.allowedKeyManagement, wifiConfiguration.FQDN);
     }
 
     /**
@@ -653,22 +677,19 @@
                 && TextUtils.equals(this.wifiConfiguration.BSSID, lhs.wifiConfiguration.BSSID)
                 && Objects.equals(this.wifiConfiguration.allowedKeyManagement,
                 lhs.wifiConfiguration.allowedKeyManagement)
-                && TextUtils.equals(this.wifiConfiguration.FQDN, lhs.wifiConfiguration.FQDN)
-                && this.suggestorUid == lhs.suggestorUid
-                && TextUtils.equals(this.suggestorPackageName, lhs.suggestorPackageName);
+                && TextUtils.equals(this.wifiConfiguration.FQDN, lhs.wifiConfiguration.FQDN);
     }
 
     @Override
     public String toString() {
-        StringBuilder sb = new StringBuilder("WifiNetworkSuggestion [")
-                .append(", SSID=").append(wifiConfiguration.SSID)
+        StringBuilder sb = new StringBuilder("WifiNetworkSuggestion[ ")
+                .append("SSID=").append(wifiConfiguration.SSID)
                 .append(", BSSID=").append(wifiConfiguration.BSSID)
                 .append(", FQDN=").append(wifiConfiguration.FQDN)
                 .append(", isAppInteractionRequired=").append(isAppInteractionRequired)
                 .append(", isUserInteractionRequired=").append(isUserInteractionRequired)
-                .append(", suggestorUid=").append(suggestorUid)
-                .append(", suggestorPackageName=").append(suggestorPackageName)
-                .append("]");
+                .append(", isUserAllowedToManuallyConnect=").append(isUserAllowedToManuallyConnect)
+                .append(" ]");
         return sb.toString();
     }
 }
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 0de5066..760497b 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -17,13 +17,16 @@
 package android.net.wifi;
 
 import android.Manifest;
+import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -45,6 +48,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 /**
  * This class provides a way to scan the Wifi universe around the device
@@ -55,6 +59,71 @@
 public class WifiScanner {
 
     /** @hide */
+    public static final int WIFI_BAND_INDEX_24_GHZ = 0;
+    /** @hide */
+    public static final int WIFI_BAND_INDEX_5_GHZ = 1;
+    /** @hide */
+    public static final int WIFI_BAND_INDEX_5_GHZ_DFS_ONLY = 2;
+    /** @hide */
+    public static final int WIFI_BAND_INDEX_6_GHZ = 3;
+    /** @hide */
+    public static final int WIFI_BAND_COUNT = 4;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"WIFI_BAND_INDEX_"}, value = {
+            WIFI_BAND_INDEX_24_GHZ,
+            WIFI_BAND_INDEX_5_GHZ,
+            WIFI_BAND_INDEX_5_GHZ_DFS_ONLY,
+            WIFI_BAND_INDEX_6_GHZ})
+    public @interface WifiBandIndex {}
+
+    /** no band specified; use channel list instead */
+    public static final int WIFI_BAND_UNSPECIFIED = 0;
+    /** 2.4 GHz band */
+    public static final int WIFI_BAND_24_GHZ = 1 << WIFI_BAND_INDEX_24_GHZ;
+    /** 5 GHz band excluding DFS channels */
+    public static final int WIFI_BAND_5_GHZ = 1 << WIFI_BAND_INDEX_5_GHZ;
+    /** DFS channels from 5 GHz band only */
+    public static final int WIFI_BAND_5_GHZ_DFS_ONLY  = 1 << WIFI_BAND_INDEX_5_GHZ_DFS_ONLY;
+    /** 6 GHz band */
+    public static final int WIFI_BAND_6_GHZ = 1 << WIFI_BAND_INDEX_6_GHZ;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"WIFI_BAND_"}, value = {
+            WIFI_BAND_UNSPECIFIED,
+            WIFI_BAND_24_GHZ,
+            WIFI_BAND_5_GHZ,
+            WIFI_BAND_5_GHZ_DFS_ONLY,
+            WIFI_BAND_6_GHZ})
+    public @interface WifiBandBasic {}
+
+    /**
+     * Combination of bands
+     * Note that those are only the common band combinations,
+     * other combinations can be created by combining any of the basic bands above
+     */
+    /** Both 2.4 GHz band and 5 GHz band; no DFS channels */
+    public static final int WIFI_BAND_BOTH = WIFI_BAND_24_GHZ | WIFI_BAND_5_GHZ;
+    /**
+     * 2.4Ghz band + DFS channels from 5 GHz band only
+     * @hide
+     */
+    public static final int WIFI_BAND_24_GHZ_WITH_5GHZ_DFS  =
+            WIFI_BAND_24_GHZ | WIFI_BAND_5_GHZ_DFS_ONLY;
+    /** 5 GHz band including DFS channels */
+    public static final int WIFI_BAND_5_GHZ_WITH_DFS  = WIFI_BAND_5_GHZ | WIFI_BAND_5_GHZ_DFS_ONLY;
+    /** Both 2.4 GHz band and 5 GHz band; with DFS channels */
+    public static final int WIFI_BAND_BOTH_WITH_DFS =
+            WIFI_BAND_24_GHZ | WIFI_BAND_5_GHZ | WIFI_BAND_5_GHZ_DFS_ONLY;
+    /** 2.4 GHz band and 5 GHz band (no DFS channels) and 6 GHz */
+    public static final int WIFI_BAND_24_5_6_GHZ = WIFI_BAND_BOTH | WIFI_BAND_6_GHZ;
+    /** 2.4 GHz band and 5 GHz band; with DFS channels and 6 GHz */
+    public static final int WIFI_BAND_24_5_WITH_DFS_6_GHZ =
+            WIFI_BAND_BOTH_WITH_DFS | WIFI_BAND_6_GHZ;
+
+    /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"WIFI_BAND_"}, value = {
             WIFI_BAND_UNSPECIFIED,
@@ -64,33 +133,17 @@
             WIFI_BAND_5_GHZ_DFS_ONLY,
             WIFI_BAND_24_GHZ_WITH_5GHZ_DFS,
             WIFI_BAND_5_GHZ_WITH_DFS,
-            WIFI_BAND_BOTH_WITH_DFS})
+            WIFI_BAND_BOTH_WITH_DFS,
+            WIFI_BAND_6_GHZ,
+            WIFI_BAND_24_5_6_GHZ,
+            WIFI_BAND_24_5_WITH_DFS_6_GHZ})
     public @interface WifiBand {}
 
-    /** no band specified; use channel list instead */
-    public static final int WIFI_BAND_UNSPECIFIED = 0;
-    /** 2.4 GHz band */
-    public static final int WIFI_BAND_24_GHZ = 1;
-    /** 5 GHz band excluding DFS channels */
-    public static final int WIFI_BAND_5_GHZ = 2;
-    /** Both 2.4 GHz band and 5 GHz band; no DFS channels */
-    public static final int WIFI_BAND_BOTH = 3;
-    /** DFS channels from 5 GHz band only */
-    public static final int WIFI_BAND_5_GHZ_DFS_ONLY  = 4;
-    /**
-     * 2.4Ghz band + DFS channels from 5 GHz band only
-     * @hide
-     */
-    public static final int WIFI_BAND_24_GHZ_WITH_5GHZ_DFS  = 5;
-    /** 5 GHz band including DFS channels */
-    public static final int WIFI_BAND_5_GHZ_WITH_DFS  = 6;
-    /** Both 2.4 GHz band and 5 GHz band; with DFS channels */
-    public static final int WIFI_BAND_BOTH_WITH_DFS = 7;
     /**
      * Max band value
      * @hide
      */
-    public static final int WIFI_BAND_MAX = 8;
+    public static final int WIFI_BAND_MAX = 0x10;
 
     /** Minimum supported scanning period */
     public static final int MIN_SCAN_PERIOD_MS = 1000;
@@ -135,7 +188,7 @@
     @SystemApi
     @NonNull
     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
-    public List<Integer> getAvailableChannels(@WifiBand int band) {
+    public List<Integer> getAvailableChannels(int band) {
         try {
             Bundle bundle = mService.getAvailableChannels(band, mContext.getOpPackageName(),
                     mContext.getFeatureId());
@@ -196,24 +249,29 @@
      */
     public static final int REPORT_EVENT_NO_BATCH = (1 << 2);
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"SCAN_TYPE_"}, value = {
+            SCAN_TYPE_LOW_LATENCY,
+            SCAN_TYPE_LOW_POWER,
+            SCAN_TYPE_HIGH_ACCURACY})
+    public @interface ScanType {}
+
     /**
-     * This is used to indicate the purpose of the scan to the wifi chip in
-     * {@link ScanSettings#type}.
-     * On devices with multiple hardware radio chains (and hence different modes of scan),
-     * this type serves as an indication to the hardware on what mode of scan to perform.
-     * Only apps holding android.Manifest.permission.NETWORK_STACK permission can set this value.
-     *
-     * Note: This serves as an intent and not as a stipulation, the wifi chip
-     * might honor or ignore the indication based on the current radio conditions. Always
-     * use the {@link ScanResult#radioChainInfos} to figure out the radio chain configuration used
-     * to receive the corresponding scan result.
+     * Optimize the scan for lower latency.
+     * @see ScanSettings#type
      */
-    /** {@hide} */
-    public static final int TYPE_LOW_LATENCY = 0;
-    /** {@hide} */
-    public static final int TYPE_LOW_POWER = 1;
-    /** {@hide} */
-    public static final int TYPE_HIGH_ACCURACY = 2;
+    public static final int SCAN_TYPE_LOW_LATENCY = 0;
+    /**
+     * Optimize the scan for lower power usage.
+     * @see ScanSettings#type
+     */
+    public static final int SCAN_TYPE_LOW_POWER = 1;
+    /**
+     * Optimize the scan for higher accuracy.
+     * @see ScanSettings#type
+     */
+    public static final int SCAN_TYPE_HIGH_ACCURACY = 2;
 
     /** {@hide} */
     public static final String SCAN_PARAMS_SCAN_SETTINGS_KEY = "ScanSettings";
@@ -228,18 +286,14 @@
      * scan configuration parameters to be sent to {@link #startBackgroundScan}
      */
     public static class ScanSettings implements Parcelable {
-        /**
-         * Hidden network to be scanned for.
-         * {@hide}
-         */
+        /** Hidden network to be scanned for. */
         public static class HiddenNetwork {
             /** SSID of the network */
-            public String ssid;
+            @NonNull
+            public final String ssid;
 
-            /**
-             * Default constructor for HiddenNetwork.
-             */
-            public HiddenNetwork(String ssid) {
+            /** Default constructor for HiddenNetwork. */
+            public HiddenNetwork(@NonNull String ssid) {
                 this.ssid = ssid;
             }
         }
@@ -249,12 +303,12 @@
         /** list of channels; used when band is set to WIFI_BAND_UNSPECIFIED */
         public ChannelSpec[] channels;
         /**
-         * list of hidden networks to scan for. Explicit probe requests are sent out for such
+         * List of hidden networks to scan for. Explicit probe requests are sent out for such
          * networks during scan. Only valid for single scan requests.
-         * {@hide}
          */
+        @NonNull
         @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
-        public HiddenNetwork[] hiddenNetworks;
+        public final List<HiddenNetwork> hiddenNetworks = new ArrayList<>();
         /** period of background scan; in millisecond, 0 => single shot scan */
         public int periodInMs;
         /** must have a valid REPORT_EVENT value */
@@ -285,11 +339,24 @@
         public boolean isPnoScan;
         /**
          * Indicate the type of scan to be performed by the wifi chip.
-         * Default value: {@link #TYPE_LOW_LATENCY}.
-         * {@hide}
+         *
+         * On devices with multiple hardware radio chains (and hence different modes of scan),
+         * this type serves as an indication to the hardware on what mode of scan to perform.
+         * Only apps holding {@link android.Manifest.permission.NETWORK_STACK} permission can set
+         * this value.
+         *
+         * Note: This serves as an intent and not as a stipulation, the wifi chip
+         * might honor or ignore the indication based on the current radio conditions. Always
+         * use the {@link ScanResult#radioChainInfos} to figure out the radio chain configuration
+         * used to receive the corresponding scan result.
+         *
+         * One of {@link #SCAN_TYPE_LOW_LATENCY}, {@link #SCAN_TYPE_LOW_POWER},
+         * {@link #SCAN_TYPE_HIGH_ACCURACY}.
+         * Default value: {@link #SCAN_TYPE_LOW_LATENCY}.
          */
+        @ScanType
         @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
-        public int type = TYPE_LOW_LATENCY;
+        public int type = SCAN_TYPE_LOW_LATENCY;
         /**
          * This scan request may ignore location settings while receiving scans. This should only
          * be used in emergency situations.
@@ -336,13 +403,9 @@
             } else {
                 dest.writeInt(0);
             }
-            if (hiddenNetworks != null) {
-                dest.writeInt(hiddenNetworks.length);
-                for (int i = 0; i < hiddenNetworks.length; i++) {
-                    dest.writeString(hiddenNetworks[i].ssid);
-                }
-            } else {
-                dest.writeInt(0);
+            dest.writeInt(hiddenNetworks.size());
+            for (HiddenNetwork hiddenNetwork : hiddenNetworks) {
+                dest.writeString(hiddenNetwork.ssid);
             }
         }
 
@@ -372,10 +435,10 @@
                             settings.channels[i] = spec;
                         }
                         int numNetworks = in.readInt();
-                        settings.hiddenNetworks = new HiddenNetwork[numNetworks];
+                        settings.hiddenNetworks.clear();
                         for (int i = 0; i < numNetworks; i++) {
                             String ssid = in.readString();
-                            settings.hiddenNetworks[i] = new HiddenNetwork(ssid);;
+                            settings.hiddenNetworks.add(new HiddenNetwork(ssid));
                         }
                         return settings;
                     }
@@ -384,7 +447,6 @@
                         return new ScanSettings[size];
                     }
                 };
-
     }
 
     /**
@@ -678,6 +740,8 @@
         public int min5GHzRssi;
         /** Minimum 2.4GHz RSSI for a BSSID to be considered */
         public int min24GHzRssi;
+        /** Minimum 6GHz RSSI for a BSSID to be considered */
+        public int min6GHzRssi;
         /** Maximum score that a network can have before bonuses */
         public int initialScoreMax;
         /**
@@ -691,6 +755,8 @@
         public int secureBonus;
         /** 5GHz RSSI score bonus (applied to all 5GHz networks) */
         public int band5GHzBonus;
+        /** 6GHz RSSI score bonus (applied to all 5GHz networks) */
+        public int band6GHzBonus;
         /** Pno Network filter list */
         public PnoNetwork[] networkList;
 
@@ -704,11 +770,13 @@
             dest.writeInt(isConnected ? 1 : 0);
             dest.writeInt(min5GHzRssi);
             dest.writeInt(min24GHzRssi);
+            dest.writeInt(min6GHzRssi);
             dest.writeInt(initialScoreMax);
             dest.writeInt(currentConnectionBonus);
             dest.writeInt(sameNetworkBonus);
             dest.writeInt(secureBonus);
             dest.writeInt(band5GHzBonus);
+            dest.writeInt(band6GHzBonus);
             if (networkList != null) {
                 dest.writeInt(networkList.length);
                 for (int i = 0; i < networkList.length; i++) {
@@ -730,11 +798,13 @@
                         settings.isConnected = in.readInt() == 1;
                         settings.min5GHzRssi = in.readInt();
                         settings.min24GHzRssi = in.readInt();
+                        settings.min6GHzRssi = in.readInt();
                         settings.initialScoreMax = in.readInt();
                         settings.currentConnectionBonus = in.readInt();
                         settings.sameNetworkBonus = in.readInt();
                         settings.secureBonus = in.readInt();
                         settings.band5GHzBonus = in.readInt();
+                        settings.band6GHzBonus = in.readInt();
                         int numNetworks = in.readInt();
                         settings.networkList = new PnoNetwork[numNetworks];
                         for (int i = 0; i < numNetworks; i++) {
@@ -801,33 +871,44 @@
     }
 
     /**
-     * Register a listener that will receive results from all single scans
-     * Either the onSuccess/onFailure will be called once when the listener is registered. After
-     * (assuming onSuccess was called) all subsequent single scan results will be delivered to the
-     * listener. It is possible that onFullResult will not be called for all results of the first
-     * scan if the listener was registered during the scan.
+     * Register a listener that will receive results from all single scans.
+     * Either the {@link ScanListener#onSuccess()} or  {@link ScanListener#onFailure(int, String)}
+     * method will be called once when the listener is registered.
+     * Afterwards (assuming onSuccess was called), all subsequent single scan results will be
+     * delivered to the listener. It is possible that onFullResult will not be called for all
+     * results of the first scan if the listener was registered during the scan.
      *
      * @param listener specifies the object to report events to. This object is also treated as a
      *                 key for this request, and must also be specified to cancel the request.
      *                 Multiple requests should also not share this object.
-     * {@hide}
      */
     @RequiresPermission(Manifest.permission.NETWORK_STACK)
-    public void registerScanListener(ScanListener listener) {
+    public void registerScanListener(@NonNull @CallbackExecutor Executor executor,
+            @NonNull ScanListener listener) {
+        Preconditions.checkNotNull(executor, "executor cannot be null");
         Preconditions.checkNotNull(listener, "listener cannot be null");
-        int key = addListener(listener);
+        int key = addListener(listener, executor);
         if (key == INVALID_KEY) return;
         validateChannel();
         mAsyncChannel.sendMessage(CMD_REGISTER_SCAN_LISTENER, 0, key);
     }
 
     /**
+     * Overload of {@link #registerScanListener(Executor, ScanListener)} that executes the callback
+     * synchronously.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.NETWORK_STACK)
+    public void registerScanListener(@NonNull ScanListener listener) {
+        registerScanListener(new SynchronousExecutor(), listener);
+    }
+
+    /**
      * Deregister a listener for ongoing single scans
      * @param listener specifies which scan to cancel; must be same object as passed in {@link
      *  #registerScanListener}
-     * {@hide}
      */
-    public void deregisterScanListener(ScanListener listener) {
+    public void unregisterScanListener(@NonNull ScanListener listener) {
         Preconditions.checkNotNull(listener, "listener cannot be null");
         int key = removeListener(listener);
         if (key == INVALID_KEY) return;
@@ -1280,6 +1361,7 @@
     private int mListenerKey = 1;
 
     private final SparseArray mListenerMap = new SparseArray();
+    private final SparseArray<Executor> mExecutorMap = new SparseArray<>();
     private final Object mListenerMapLock = new Object();
 
     private AsyncChannel mAsyncChannel;
@@ -1327,10 +1409,14 @@
                 "No permission to access and change wifi or a bad initialization");
     }
 
+    private int addListener(ActionListener listener) {
+        return addListener(listener, null);
+    }
+
     // Add a listener into listener map. If the listener already exists, return INVALID_KEY and
     // send an error message to internal handler; Otherwise add the listener to the listener map and
     // return the key of the listener.
-    private int addListener(ActionListener listener) {
+    private int addListener(ActionListener listener, Executor executor) {
         synchronized (mListenerMapLock) {
             boolean keyExists = (getListenerKey(listener) != INVALID_KEY);
             // Note we need to put the listener into listener map even if it's a duplicate as the
@@ -1346,6 +1432,7 @@
                 message.sendToTarget();
                 return INVALID_KEY;
             } else {
+                mExecutorMap.put(key, executor);
                 return key;
             }
         }
@@ -1363,11 +1450,22 @@
         return key;
     }
 
-    private Object getListener(int key) {
-        if (key == INVALID_KEY) return null;
+    private static class ListenerWithExecutor {
+        @Nullable final Object mListener;
+        @Nullable final Executor mExecutor;
+
+        ListenerWithExecutor(@Nullable Object listener, @Nullable Executor executor) {
+            mListener = listener;
+            mExecutor = executor;
+        }
+    }
+
+    private ListenerWithExecutor getListenerWithExecutor(int key) {
+        if (key == INVALID_KEY) return new ListenerWithExecutor(null, null);
         synchronized (mListenerMapLock) {
             Object listener = mListenerMap.get(key);
-            return listener;
+            Executor executor = mExecutorMap.get(key);
+            return new ListenerWithExecutor(listener, executor);
         }
     }
 
@@ -1388,6 +1486,7 @@
         synchronized (mListenerMapLock) {
             Object listener = mListenerMap.get(key);
             mListenerMap.remove(key);
+            mExecutorMap.remove(key);
             return listener;
         }
     }
@@ -1400,6 +1499,7 @@
         }
         synchronized (mListenerMapLock) {
             mListenerMap.remove(key);
+            mExecutorMap.remove(key);
             return key;
         }
     }
@@ -1458,7 +1558,8 @@
                     return;
             }
 
-            Object listener = getListener(msg.arg2);
+            ListenerWithExecutor listenerWithExecutor = getListenerWithExecutor(msg.arg2);
+            Object listener = listenerWithExecutor.mListener;
 
             if (listener == null) {
                 if (DBG) Log.d(TAG, "invalid listener key = " + msg.arg2);
@@ -1467,36 +1568,52 @@
                 if (DBG) Log.d(TAG, "listener key = " + msg.arg2);
             }
 
+            Executor executor = listenerWithExecutor.mExecutor;
+            if (executor == null) {
+                executor = new SynchronousExecutor();
+            }
+
             switch (msg.what) {
-                    /* ActionListeners grouped together */
-                case CMD_OP_SUCCEEDED :
-                    ((ActionListener) listener).onSuccess();
-                    break;
-                case CMD_OP_FAILED : {
-                        OperationResult result = (OperationResult)msg.obj;
-                        ((ActionListener) listener).onFailure(result.reason, result.description);
-                        removeListener(msg.arg2);
-                    }
-                    break;
-                case CMD_SCAN_RESULT :
-                    ((ScanListener) listener).onResults(
-                            ((ParcelableScanData) msg.obj).getResults());
-                    return;
-                case CMD_FULL_SCAN_RESULT :
+                /* ActionListeners grouped together */
+                case CMD_OP_SUCCEEDED: {
+                    ActionListener actionListener = (ActionListener) listener;
+                    Binder.clearCallingIdentity();
+                    executor.execute(actionListener::onSuccess);
+                } break;
+                case CMD_OP_FAILED: {
+                    OperationResult result = (OperationResult) msg.obj;
+                    ActionListener actionListener = (ActionListener) listener;
+                    removeListener(msg.arg2);
+                    Binder.clearCallingIdentity();
+                    executor.execute(() ->
+                            actionListener.onFailure(result.reason, result.description));
+                } break;
+                case CMD_SCAN_RESULT: {
+                    ScanListener scanListener = (ScanListener) listener;
+                    ParcelableScanData parcelableScanData = (ParcelableScanData) msg.obj;
+                    Binder.clearCallingIdentity();
+                    executor.execute(() -> scanListener.onResults(parcelableScanData.getResults()));
+                } break;
+                case CMD_FULL_SCAN_RESULT: {
                     ScanResult result = (ScanResult) msg.obj;
-                    ((ScanListener) listener).onFullResult(result);
-                    return;
-                case CMD_SINGLE_SCAN_COMPLETED:
+                    ScanListener scanListener = ((ScanListener) listener);
+                    Binder.clearCallingIdentity();
+                    executor.execute(() -> scanListener.onFullResult(result));
+                } break;
+                case CMD_SINGLE_SCAN_COMPLETED: {
                     if (DBG) Log.d(TAG, "removing listener for single scan");
                     removeListener(msg.arg2);
-                    break;
-                case CMD_PNO_NETWORK_FOUND:
-                    ((PnoScanListener) listener).onPnoNetworkFound(
-                            ((ParcelableScanResults) msg.obj).getResults());
-                    return;
-                default:
+                } break;
+                case CMD_PNO_NETWORK_FOUND: {
+                    PnoScanListener pnoScanListener = (PnoScanListener) listener;
+                    ParcelableScanResults parcelableScanResults = (ParcelableScanResults) msg.obj;
+                    Binder.clearCallingIdentity();
+                    executor.execute(() ->
+                            pnoScanListener.onPnoNetworkFound(parcelableScanResults.getResults()));
+                } break;
+                default: {
                     if (DBG) Log.d(TAG, "Ignoring message " + msg.what);
-                    return;
+                } break;
             }
         }
     }
diff --git a/wifi/java/android/net/wifi/aware/ConfigRequest.java b/wifi/java/android/net/wifi/aware/ConfigRequest.java
index b07d8ed..61ab92c 100644
--- a/wifi/java/android/net/wifi/aware/ConfigRequest.java
+++ b/wifi/java/android/net/wifi/aware/ConfigRequest.java
@@ -47,6 +47,7 @@
      */
     public static final int NAN_BAND_24GHZ = 0;
     public static final int NAN_BAND_5GHZ = 1;
+    public static final int NAN_BAND_6GHZ = 2;
 
     /**
      * Magic values for Discovery Window (DW) interval configuration
@@ -60,6 +61,11 @@
     public final boolean mSupport5gBand;
 
     /**
+     * Indicates whether 6G band support is requested.
+     */
+    public final boolean mSupport6gBand;
+
+    /**
      * Specifies the desired master preference.
      */
     public final int mMasterPreference;
@@ -81,9 +87,10 @@
      */
     public final int mDiscoveryWindowInterval[];
 
-    private ConfigRequest(boolean support5gBand, int masterPreference, int clusterLow,
-            int clusterHigh, int discoveryWindowInterval[]) {
+    private ConfigRequest(boolean support5gBand, boolean support6gBand, int masterPreference,
+            int clusterLow, int clusterHigh, int[] discoveryWindowInterval) {
         mSupport5gBand = support5gBand;
+        mSupport6gBand = support6gBand;
         mMasterPreference = masterPreference;
         mClusterLow = clusterLow;
         mClusterHigh = clusterHigh;
@@ -92,10 +99,12 @@
 
     @Override
     public String toString() {
-        return "ConfigRequest [mSupport5gBand=" + mSupport5gBand + ", mMasterPreference="
-                + mMasterPreference + ", mClusterLow=" + mClusterLow + ", mClusterHigh="
-                + mClusterHigh + ", mDiscoveryWindowInterval="
-                + Arrays.toString(mDiscoveryWindowInterval) + "]";
+        return "ConfigRequest [mSupport5gBand=" + mSupport5gBand
+                + ", mSupport6gBand=" + mSupport6gBand
+                + ", mMasterPreference=" + mMasterPreference
+                + ", mClusterLow=" + mClusterLow
+                + ", mClusterHigh=" + mClusterHigh
+                + ", mDiscoveryWindowInterval=" + Arrays.toString(mDiscoveryWindowInterval) + "]";
     }
 
     @Override
@@ -106,6 +115,7 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mSupport5gBand ? 1 : 0);
+        dest.writeInt(mSupport6gBand ? 1 : 0);
         dest.writeInt(mMasterPreference);
         dest.writeInt(mClusterLow);
         dest.writeInt(mClusterHigh);
@@ -121,13 +131,14 @@
         @Override
         public ConfigRequest createFromParcel(Parcel in) {
             boolean support5gBand = in.readInt() != 0;
+            boolean support6gBand = in.readInt() != 0;
             int masterPreference = in.readInt();
             int clusterLow = in.readInt();
             int clusterHigh = in.readInt();
             int discoveryWindowInterval[] = in.createIntArray();
 
-            return new ConfigRequest(support5gBand, masterPreference, clusterLow, clusterHigh,
-                    discoveryWindowInterval);
+            return new ConfigRequest(support5gBand, support6gBand, masterPreference, clusterLow,
+                    clusterHigh, discoveryWindowInterval);
         }
     };
 
@@ -143,7 +154,9 @@
 
         ConfigRequest lhs = (ConfigRequest) o;
 
-        return mSupport5gBand == lhs.mSupport5gBand && mMasterPreference == lhs.mMasterPreference
+        return mSupport5gBand == lhs.mSupport5gBand
+                && mSupport6gBand == lhs.mSupport6gBand
+                && mMasterPreference == lhs.mMasterPreference
                 && mClusterLow == lhs.mClusterLow && mClusterHigh == lhs.mClusterHigh
                 && Arrays.equals(mDiscoveryWindowInterval, lhs.mDiscoveryWindowInterval);
     }
@@ -153,6 +166,7 @@
         int result = 17;
 
         result = 31 * result + (mSupport5gBand ? 1 : 0);
+        result = 31 * result + (mSupport6gBand ? 1 : 0);
         result = 31 * result + mMasterPreference;
         result = 31 * result + mClusterLow;
         result = 31 * result + mClusterHigh;
@@ -190,9 +204,9 @@
             throw new IllegalArgumentException(
                     "Invalid argument combination - must have Cluster Low <= Cluster High");
         }
-        if (mDiscoveryWindowInterval.length != 2) {
+        if (mDiscoveryWindowInterval.length != 3) {
             throw new IllegalArgumentException(
-                    "Invalid discovery window interval: must have 2 elements (2.4 & 5");
+                    "Invalid discovery window interval: must have 3 elements (2.4 & 5 & 6");
         }
         if (mDiscoveryWindowInterval[NAN_BAND_24GHZ] != DW_INTERVAL_NOT_INIT &&
                 (mDiscoveryWindowInterval[NAN_BAND_24GHZ] < 1 // valid for 2.4GHz: [1-5]
@@ -206,7 +220,12 @@
             throw new IllegalArgumentException(
                 "Invalid discovery window interval for 5GHz: valid is UNSET or [0,5]");
         }
-
+        if (mDiscoveryWindowInterval[NAN_BAND_6GHZ] != DW_INTERVAL_NOT_INIT
+                && (mDiscoveryWindowInterval[NAN_BAND_6GHZ] < 0 // valid for 6GHz: [0-5]
+                || mDiscoveryWindowInterval[NAN_BAND_6GHZ] > 5)) {
+            throw new IllegalArgumentException(
+                "Invalid discovery window interval for 6GHz: valid is UNSET or [0,5]");
+        }
     }
 
     /**
@@ -214,10 +233,12 @@
      */
     public static final class Builder {
         private boolean mSupport5gBand = true;
+        private boolean mSupport6gBand = false;
         private int mMasterPreference = 0;
         private int mClusterLow = CLUSTER_ID_MIN;
         private int mClusterHigh = CLUSTER_ID_MAX;
-        private int mDiscoveryWindowInterval[] = {DW_INTERVAL_NOT_INIT, DW_INTERVAL_NOT_INIT};
+        private int[] mDiscoveryWindowInterval = {DW_INTERVAL_NOT_INIT, DW_INTERVAL_NOT_INIT,
+                DW_INTERVAL_NOT_INIT};
 
         /**
          * Specify whether 5G band support is required in this request. Disabled by default.
@@ -233,6 +254,19 @@
         }
 
         /**
+         * Specify whether 6G band support is required in this request. Disabled by default.
+         *
+         * @param support6gBand Support for 6G band is required.
+         *
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setSupport6gBand(boolean support6gBand) {
+            mSupport6gBand = support6gBand;
+            return this;
+        }
+
+        /**
          * Specify the Master Preference requested. The permitted range is 0 (the default) to
          * 255 with 1 and 255 excluded (reserved).
          *
@@ -310,7 +344,8 @@
          * awake. The configuration enables trading off latency vs. power (higher interval means
          * higher discovery latency but lower power).
          *
-         * @param band Either {@link #NAN_BAND_24GHZ} or {@link #NAN_BAND_5GHZ}.
+         * @param band Either {@link #NAN_BAND_24GHZ} or {@link #NAN_BAND_5GHZ} or
+         *        {@link #NAN_BAND_6GHZ}.
          * @param interval A value of 1, 2, 3, 4, or 5 indicating an interval of 2^(interval-1). For
          *                 the 5GHz band a value of 0 indicates that the device will not be awake
          *                 for any discovery windows.
@@ -319,13 +354,14 @@
          *         {@code builder.setDiscoveryWindowInterval(...).setMasterPreference(...)}.
          */
         public Builder setDiscoveryWindowInterval(int band, int interval) {
-            if (band != NAN_BAND_24GHZ && band != NAN_BAND_5GHZ) {
+            if (band != NAN_BAND_24GHZ && band != NAN_BAND_5GHZ && band != NAN_BAND_6GHZ) {
                 throw new IllegalArgumentException("Invalid band value");
             }
             if ((band == NAN_BAND_24GHZ && (interval < 1 || interval > 5))
-                    || (band == NAN_BAND_5GHZ && (interval < 0 || interval > 5))) {
+                    || (band == NAN_BAND_5GHZ && (interval < 0 || interval > 5))
+                    || (band == NAN_BAND_6GHZ && (interval < 0 || interval > 5))) {
                 throw new IllegalArgumentException(
-                        "Invalid interval value: 2.4 GHz [1,5] or 5GHz [0,5]");
+                        "Invalid interval value: 2.4 GHz [1,5] or 5GHz/6GHz [0,5]");
             }
 
             mDiscoveryWindowInterval[band] = interval;
@@ -342,8 +378,8 @@
                         "Invalid argument combination - must have Cluster Low <= Cluster High");
             }
 
-            return new ConfigRequest(mSupport5gBand, mMasterPreference, mClusterLow, mClusterHigh,
-                    mDiscoveryWindowInterval);
+            return new ConfigRequest(mSupport5gBand, mSupport6gBand, mMasterPreference, mClusterLow,
+                    mClusterHigh, mDiscoveryWindowInterval);
         }
     }
 }
diff --git a/wifi/java/android/net/wifi/aware/PublishConfig.java b/wifi/java/android/net/wifi/aware/PublishConfig.java
index 1886b7e..a8844c1 100644
--- a/wifi/java/android/net/wifi/aware/PublishConfig.java
+++ b/wifi/java/android/net/wifi/aware/PublishConfig.java
@@ -19,11 +19,10 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.net.wifi.util.HexEncoding;
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import libcore.util.HexEncoding;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.nio.charset.StandardCharsets;
diff --git a/wifi/java/android/net/wifi/aware/SubscribeConfig.java b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
index f0f7581..76780f4 100644
--- a/wifi/java/android/net/wifi/aware/SubscribeConfig.java
+++ b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
@@ -19,11 +19,10 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.net.wifi.util.HexEncoding;
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import libcore.util.HexEncoding;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.nio.charset.StandardCharsets;
diff --git a/wifi/java/android/net/wifi/aware/TlvBufferUtils.java b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
index b3b5b29..2d3cc1e 100644
--- a/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
+++ b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
@@ -18,8 +18,6 @@
 
 import android.annotation.Nullable;
 
-import libcore.io.Memory;
-
 import java.nio.BufferOverflowException;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
@@ -266,7 +264,7 @@
         public TlvConstructor putShort(int type, short data) {
             checkLength(2);
             addHeader(type, 2);
-            Memory.pokeShort(mArray, mPosition, data, mByteOrder);
+            pokeShort(mArray, mPosition, data, mByteOrder);
             mPosition += 2;
             return this;
         }
@@ -284,7 +282,7 @@
         public TlvConstructor putInt(int type, int data) {
             checkLength(4);
             addHeader(type, 4);
-            Memory.pokeInt(mArray, mPosition, data, mByteOrder);
+            pokeInt(mArray, mPosition, data, mByteOrder);
             mPosition += 4;
             return this;
         }
@@ -349,14 +347,14 @@
             if (mTypeSize == 1) {
                 mArray[mPosition] = (byte) type;
             } else if (mTypeSize == 2) {
-                Memory.pokeShort(mArray, mPosition, (short) type, mByteOrder);
+                pokeShort(mArray, mPosition, (short) type, mByteOrder);
             }
             mPosition += mTypeSize;
 
             if (mLengthSize == 1) {
                 mArray[mPosition] = (byte) length;
             } else if (mLengthSize == 2) {
-                Memory.pokeShort(mArray, mPosition, (short) length, mByteOrder);
+                pokeShort(mArray, mPosition, (short) length, mByteOrder);
             }
             mPosition += mLengthSize;
         }
@@ -445,7 +443,7 @@
                 throw new IllegalArgumentException(
                         "Accesing a short from a TLV element of length " + length);
             }
-            return Memory.peekShort(mRefArray, offset, byteOrder);
+            return peekShort(mRefArray, offset, byteOrder);
         }
 
         /**
@@ -460,7 +458,7 @@
                 throw new IllegalArgumentException(
                         "Accesing an int from a TLV element of length " + length);
             }
-            return Memory.peekInt(mRefArray, offset, byteOrder);
+            return peekInt(mRefArray, offset, byteOrder);
         }
 
         /**
@@ -590,7 +588,7 @@
                     if (mTypeSize == 1) {
                         type = mArray[mOffset];
                     } else if (mTypeSize == 2) {
-                        type = Memory.peekShort(mArray, mOffset, mByteOrder);
+                        type = peekShort(mArray, mOffset, mByteOrder);
                     }
                     mOffset += mTypeSize;
 
@@ -598,7 +596,7 @@
                     if (mLengthSize == 1) {
                         length = mArray[mOffset];
                     } else if (mLengthSize == 2) {
-                        length = Memory.peekShort(mArray, mOffset, mByteOrder);
+                        length = peekShort(mArray, mOffset, mByteOrder);
                     }
                     mOffset += mLengthSize;
 
@@ -661,10 +659,56 @@
             if (lengthSize == 1) {
                 nextTlvIndex += lengthSize + array[nextTlvIndex];
             } else {
-                nextTlvIndex += lengthSize + Memory.peekShort(array, nextTlvIndex, byteOrder);
+                nextTlvIndex += lengthSize + peekShort(array, nextTlvIndex, byteOrder);
             }
         }
 
         return nextTlvIndex == array.length;
     }
+
+    private static void pokeShort(byte[] dst, int offset, short value, ByteOrder order) {
+        if (order == ByteOrder.BIG_ENDIAN) {
+            dst[offset++] = (byte) ((value >> 8) & 0xff);
+            dst[offset  ] = (byte) ((value >> 0) & 0xff);
+        } else {
+            dst[offset++] = (byte) ((value >> 0) & 0xff);
+            dst[offset  ] = (byte) ((value >> 8) & 0xff);
+        }
+    }
+
+    private static void pokeInt(byte[] dst, int offset, int value, ByteOrder order) {
+        if (order == ByteOrder.BIG_ENDIAN) {
+            dst[offset++] = (byte) ((value >> 24) & 0xff);
+            dst[offset++] = (byte) ((value >> 16) & 0xff);
+            dst[offset++] = (byte) ((value >>  8) & 0xff);
+            dst[offset  ] = (byte) ((value >>  0) & 0xff);
+        } else {
+            dst[offset++] = (byte) ((value >>  0) & 0xff);
+            dst[offset++] = (byte) ((value >>  8) & 0xff);
+            dst[offset++] = (byte) ((value >> 16) & 0xff);
+            dst[offset  ] = (byte) ((value >> 24) & 0xff);
+        }
+    }
+
+    private static short peekShort(byte[] src, int offset, ByteOrder order) {
+        if (order == ByteOrder.BIG_ENDIAN) {
+            return (short) ((src[offset] << 8) | (src[offset + 1] & 0xff));
+        } else {
+            return (short) ((src[offset + 1] << 8) | (src[offset] & 0xff));
+        }
+    }
+
+    private static int peekInt(byte[] src, int offset, ByteOrder order) {
+        if (order == ByteOrder.BIG_ENDIAN) {
+            return ((src[offset++] & 0xff) << 24)
+                    | ((src[offset++] & 0xff) << 16)
+                    | ((src[offset++] & 0xff) <<  8)
+                    | ((src[offset  ] & 0xff) <<  0);
+        } else {
+            return ((src[offset++] & 0xff) <<  0)
+                    | ((src[offset++] & 0xff) <<  8)
+                    | ((src[offset++] & 0xff) << 16)
+                    | ((src[offset  ] & 0xff) << 24);
+        }
+    }
 }
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java
index 9164d04..c667334 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java
@@ -17,12 +17,11 @@
 package android.net.wifi.aware;
 
 import android.net.NetworkSpecifier;
+import android.net.wifi.util.HexEncoding;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
 
-import libcore.util.HexEncoding;
-
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.Arrays;
@@ -207,14 +206,14 @@
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeBlob(mData);
+            dest.writeByteArray(mData);
         }
 
         public static final @android.annotation.NonNull Creator<ByteArrayWrapper> CREATOR =
                 new Creator<ByteArrayWrapper>() {
                     @Override
                     public ByteArrayWrapper createFromParcel(Parcel in) {
-                        return new ByteArrayWrapper(in.readBlob());
+                        return new ByteArrayWrapper(in.createByteArray());
                     }
 
                     @Override
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 7b37d65..81bf81e 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemService;
@@ -26,6 +27,7 @@
 import android.net.ConnectivityManager;
 import android.net.NetworkRequest;
 import android.net.NetworkSpecifier;
+import android.net.wifi.util.HexEncoding;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -36,8 +38,6 @@
 import android.os.RemoteException;
 import android.util.Log;
 
-import libcore.util.HexEncoding;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
@@ -397,6 +397,17 @@
     }
 
     /** @hide */
+    @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
+    public void requestMacAddresses(int uid, List<Integer> peerIds,
+            IWifiAwareMacAddressProvider callback) {
+        try {
+            mService.requestMacAddresses(uid, peerIds, callback);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /** @hide */
     public NetworkSpecifier createNetworkSpecifier(int clientId, int role, int sessionId,
             @NonNull PeerHandle peerHandle, @Nullable byte[] pmk, @Nullable String passphrase) {
         if (VDBG) {
diff --git a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
index 3bef502..f0a0607 100644
--- a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
+++ b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
@@ -19,7 +19,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.net.wifi.WifiSsid;
 import android.os.Bundle;
@@ -86,23 +85,16 @@
      */
     private final List<Integer> mMethodList;
 
-    /**
-     * Icon data for the OSU (Online Sign-Up) provider.
-     */
-    private final Icon mIcon;
-
     /** @hide */
     public OsuProvider(String osuSsid, Map<String, String> friendlyNames,
-            String serviceDescription, Uri serverUri, String nai, List<Integer> methodList,
-            Icon icon) {
+            String serviceDescription, Uri serverUri, String nai, List<Integer> methodList) {
         this(WifiSsid.createFromByteArray(osuSsid.getBytes(StandardCharsets.UTF_8)),
-                friendlyNames, serviceDescription, serverUri, nai, methodList, icon);
+                friendlyNames, serviceDescription, serverUri, nai, methodList);
     }
 
     /** @hide */
     public OsuProvider(WifiSsid osuSsid, Map<String, String> friendlyNames,
-            String serviceDescription, Uri serverUri, String nai, List<Integer> methodList,
-            Icon icon) {
+            String serviceDescription, Uri serverUri, String nai, List<Integer> methodList) {
         mOsuSsid = osuSsid;
         mFriendlyNames = friendlyNames;
         mServiceDescription = serviceDescription;
@@ -113,7 +105,6 @@
         } else {
             mMethodList = new ArrayList<>(methodList);
         }
-        mIcon = icon;
     }
 
     /**
@@ -130,7 +121,6 @@
             mServerUri = null;
             mNetworkAccessIdentifier = null;
             mMethodList = new ArrayList<>();
-            mIcon = null;
             return;
         }
 
@@ -144,7 +134,6 @@
         } else {
             mMethodList = new ArrayList<>(source.mMethodList);
         }
-        mIcon = source.mIcon;
     }
 
     /** @hide */
@@ -205,11 +194,6 @@
         return mMethodList;
     }
 
-    /** @hide */
-    public Icon getIcon() {
-        return mIcon;
-    }
-
     @Override
     public int describeContents() {
         return 0;
@@ -222,7 +206,6 @@
         dest.writeParcelable(mServerUri, flags);
         dest.writeString(mNetworkAccessIdentifier);
         dest.writeList(mMethodList);
-        dest.writeParcelable(mIcon, flags);
         Bundle bundle = new Bundle();
         bundle.putSerializable("friendlyNameMap", (HashMap<String, String>) mFriendlyNames);
         dest.writeBundle(bundle);
@@ -237,21 +220,16 @@
             return false;
         }
         OsuProvider that = (OsuProvider) thatObject;
-        return (mOsuSsid == null ? that.mOsuSsid == null : mOsuSsid.equals(that.mOsuSsid))
-                && (mFriendlyNames == null) ? that.mFriendlyNames == null
-                            : mFriendlyNames.equals(that.mFriendlyNames)
+        return Objects.equals(mOsuSsid, that.mOsuSsid)
+                && Objects.equals(mFriendlyNames, that.mFriendlyNames)
                 && TextUtils.equals(mServiceDescription, that.mServiceDescription)
-                && (mServerUri == null ? that.mServerUri == null
-                            : mServerUri.equals(that.mServerUri))
+                && Objects.equals(mServerUri, that.mServerUri)
                 && TextUtils.equals(mNetworkAccessIdentifier, that.mNetworkAccessIdentifier)
-                && (mMethodList == null ? that.mMethodList == null
-                            : mMethodList.equals(that.mMethodList))
-                && (mIcon == null ? that.mIcon == null : mIcon.sameAs(that.mIcon));
+                && Objects.equals(mMethodList, that.mMethodList);
     }
 
     @Override
     public int hashCode() {
-        // mIcon is not hashable, skip the variable.
         return Objects.hash(mOsuSsid, mServiceDescription, mFriendlyNames,
                 mServerUri, mNetworkAccessIdentifier, mMethodList);
     }
@@ -264,8 +242,7 @@
                 + " mServiceDescription=" + mServiceDescription
                 + " mServerUri=" + mServerUri
                 + " mNetworkAccessIdentifier=" + mNetworkAccessIdentifier
-                + " mMethodList=" + mMethodList
-                + " mIcon=" + mIcon;
+                + " mMethodList=" + mMethodList;
     }
 
     public static final @android.annotation.NonNull Creator<OsuProvider> CREATOR =
@@ -278,12 +255,11 @@
                     String nai = in.readString();
                     List<Integer> methodList = new ArrayList<>();
                     in.readList(methodList, null);
-                    Icon icon = in.readParcelable(null);
                     Bundle bundle = in.readBundle();
                     Map<String, String> friendlyNamesMap = (HashMap) bundle.getSerializable(
                             "friendlyNameMap");
                     return new OsuProvider(osuSsid, friendlyNamesMap, serviceDescription,
-                            serverUri, nai, methodList, icon);
+                            serverUri, nai, methodList);
                 }
 
             @Override
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
index 13b2520..98ec208 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
@@ -286,14 +286,12 @@
     }
 
     /**
-     * Update device details. This will throw an exception if the device address does not match.
+     * Update this device's details using another {@link WifiP2pDevice} instance.
+     * This will throw an exception if the device address does not match.
      *
-     * @param device to be updated
+     * @param device another instance of {@link WifiP2pDevice} used to update this instance.
      * @throws IllegalArgumentException if the device is null or the device address does not match
-     *
-     * @hide
      */
-    @UnsupportedAppUsage
     public void update(@NonNull WifiP2pDevice device) {
         updateSupplicantDetails(device);
         status = device.status;
diff --git a/wifi/java/android/net/wifi/rtt/package.html b/wifi/java/android/net/wifi/rtt/package.html
index e639282..4a32f52 100644
--- a/wifi/java/android/net/wifi/rtt/package.html
+++ b/wifi/java/android/net/wifi/rtt/package.html
@@ -37,5 +37,9 @@
 <pre>
     getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)
 </pre>
+
+<p>For an example of this functionality, see
+<a href="{@docRoot}guide/topics/connectivity/wifi-rtt" class="external">Wi-Fi location: ranging
+with RTT</a>.</p>
 </BODY>
 </HTML>
diff --git a/wifi/java/android/net/wifi/util/HexEncoding.java b/wifi/java/android/net/wifi/util/HexEncoding.java
new file mode 100644
index 0000000..9ebf947
--- /dev/null
+++ b/wifi/java/android/net/wifi/util/HexEncoding.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.util;
+
+/**
+ * Hexadecimal encoding where each byte is represented by two hexadecimal digits.
+ *
+ * Note: this is copied from {@link libcore.util.HexEncoding}.
+ *
+ * @hide
+ */
+public class HexEncoding {
+
+    private static final char[] LOWER_CASE_DIGITS = {
+            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+    };
+
+    private static final char[] UPPER_CASE_DIGITS = {
+            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+    };
+
+    /** Hidden constructor to prevent instantiation. */
+    private HexEncoding() {}
+
+    /**
+     * Encodes the provided byte as a two-digit hexadecimal String value.
+     */
+    public static String encodeToString(byte b, boolean upperCase) {
+        char[] digits = upperCase ? UPPER_CASE_DIGITS : LOWER_CASE_DIGITS;
+        char[] buf = new char[2]; // We always want two digits.
+        buf[0] = digits[(b >> 4) & 0xf];
+        buf[1] = digits[b & 0xf];
+        return new String(buf, 0, 2);
+    }
+
+    /**
+     * Encodes the provided data as a sequence of hexadecimal characters.
+     */
+    public static char[] encode(byte[] data) {
+        return encode(data, 0, data.length, true /* upperCase */);
+    }
+
+    /**
+     * Encodes the provided data as a sequence of hexadecimal characters.
+     */
+    public static char[] encode(byte[] data, boolean upperCase) {
+        return encode(data, 0, data.length, upperCase);
+    }
+
+    /**
+     * Encodes the provided data as a sequence of hexadecimal characters.
+     */
+    public static char[] encode(byte[] data, int offset, int len) {
+        return encode(data, offset, len, true /* upperCase */);
+    }
+
+    /**
+     * Encodes the provided data as a sequence of hexadecimal characters.
+     */
+    private static char[] encode(byte[] data, int offset, int len, boolean upperCase) {
+        char[] digits = upperCase ? UPPER_CASE_DIGITS : LOWER_CASE_DIGITS;
+        char[] result = new char[len * 2];
+        for (int i = 0; i < len; i++) {
+            byte b = data[offset + i];
+            int resultIndex = 2 * i;
+            result[resultIndex] = (digits[(b >> 4) & 0x0f]);
+            result[resultIndex + 1] = (digits[b & 0x0f]);
+        }
+
+        return result;
+    }
+
+    /**
+     * Encodes the provided data as a sequence of hexadecimal characters.
+     */
+    public static String encodeToString(byte[] data) {
+        return encodeToString(data, true /* upperCase */);
+    }
+
+    /**
+     * Encodes the provided data as a sequence of hexadecimal characters.
+     */
+    public static String encodeToString(byte[] data, boolean upperCase) {
+        return new String(encode(data, upperCase));
+    }
+
+    /**
+     * Decodes the provided hexadecimal string into a byte array.  Odd-length inputs
+     * are not allowed.
+     *
+     * Throws an {@code IllegalArgumentException} if the input is malformed.
+     */
+    public static byte[] decode(String encoded) throws IllegalArgumentException {
+        return decode(encoded.toCharArray());
+    }
+
+    /**
+     * Decodes the provided hexadecimal string into a byte array. If {@code allowSingleChar}
+     * is {@code true} odd-length inputs are allowed and the first character is interpreted
+     * as the lower bits of the first result byte.
+     *
+     * Throws an {@code IllegalArgumentException} if the input is malformed.
+     */
+    public static byte[] decode(String encoded, boolean allowSingleChar)
+            throws IllegalArgumentException {
+        return decode(encoded.toCharArray(), allowSingleChar);
+    }
+
+    /**
+     * Decodes the provided hexadecimal string into a byte array.  Odd-length inputs
+     * are not allowed.
+     *
+     * Throws an {@code IllegalArgumentException} if the input is malformed.
+     */
+    public static byte[] decode(char[] encoded) throws IllegalArgumentException {
+        return decode(encoded, false);
+    }
+
+    /**
+     * Decodes the provided hexadecimal string into a byte array. If {@code allowSingleChar}
+     * is {@code true} odd-length inputs are allowed and the first character is interpreted
+     * as the lower bits of the first result byte.
+     *
+     * Throws an {@code IllegalArgumentException} if the input is malformed.
+     */
+    public static byte[] decode(char[] encoded, boolean allowSingleChar)
+            throws IllegalArgumentException {
+        int encodedLength = encoded.length;
+        int resultLengthBytes = (encodedLength + 1) / 2;
+        byte[] result = new byte[resultLengthBytes];
+
+        int resultOffset = 0;
+        int i = 0;
+        if (allowSingleChar) {
+            if ((encodedLength % 2) != 0) {
+                // Odd number of digits -- the first digit is the lower 4 bits of the first result
+                // byte.
+                result[resultOffset++] = (byte) toDigit(encoded, i);
+                i++;
+            }
+        } else {
+            if ((encodedLength % 2) != 0) {
+                throw new IllegalArgumentException("Invalid input length: " + encodedLength);
+            }
+        }
+
+        for (; i < encodedLength; i += 2) {
+            result[resultOffset++] = (byte) ((toDigit(encoded, i) << 4) | toDigit(encoded, i + 1));
+        }
+
+        return result;
+    }
+
+    private static int toDigit(char[] str, int offset) throws IllegalArgumentException {
+        // NOTE: that this isn't really a code point in the traditional sense, since we're
+        // just rejecting surrogate pairs outright.
+        int pseudoCodePoint = str[offset];
+
+        if ('0' <= pseudoCodePoint && pseudoCodePoint <= '9') {
+            return pseudoCodePoint - '0';
+        } else if ('a' <= pseudoCodePoint && pseudoCodePoint <= 'f') {
+            return 10 + (pseudoCodePoint - 'a');
+        } else if ('A' <= pseudoCodePoint && pseudoCodePoint <= 'F') {
+            return 10 + (pseudoCodePoint - 'A');
+        }
+
+        throw new IllegalArgumentException("Illegal char: " + str[offset] + " at offset " + offset);
+    }
+}
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
index 534e609..524a53c 100644
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ b/wifi/java/com/android/server/wifi/BaseWifiService.java
@@ -25,6 +25,7 @@
 import android.net.wifi.IDppCallback;
 import android.net.wifi.ILocalOnlyHotspotCallback;
 import android.net.wifi.INetworkRequestMatchCallback;
+import android.net.wifi.IOnWifiActivityEnergyInfoListener;
 import android.net.wifi.IOnWifiUsabilityStatsListener;
 import android.net.wifi.IScanResultsCallback;
 import android.net.wifi.IScanResultsListener;
@@ -35,7 +36,6 @@
 import android.net.wifi.IWifiManager;
 import android.net.wifi.ScanResult;
 import android.net.wifi.SoftApConfiguration;
-import android.net.wifi.WifiActivityEnergyInfo;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiNetworkSuggestion;
@@ -46,6 +46,7 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.WorkSource;
+import android.os.connectivity.WifiActivityEnergyInfo;
 
 import java.util.List;
 import java.util.Map;
@@ -75,17 +76,24 @@
         throw new UnsupportedOperationException();
     }
 
-    @Override
+    /** @deprecated use {@link #getWifiActivityEnergyInfoAsync} instead */
+    @Deprecated
     public WifiActivityEnergyInfo reportActivityInfo() {
         throw new UnsupportedOperationException();
     }
 
-    @Override
+    /** @deprecated use {@link #getWifiActivityEnergyInfoAsync} instead */
+    @Deprecated
     public void requestActivityInfo(ResultReceiver result) {
         throw new UnsupportedOperationException();
     }
 
     @Override
+    public void getWifiActivityEnergyInfoAsync(IOnWifiActivityEnergyInfoListener listener) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public ParceledListSlice getConfiguredNetworks(String packageName, String featureId) {
         throw new UnsupportedOperationException();
     }
@@ -285,6 +293,11 @@
     }
 
     @Override
+    public boolean startTetheredHotspot(SoftApConfiguration softApConfig) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public boolean stopSoftAp() {
         throw new UnsupportedOperationException();
     }
@@ -321,10 +334,21 @@
     }
 
     @Override
+    public SoftApConfiguration getSoftApConfiguration() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public boolean setWifiApConfiguration(WifiConfiguration wifiConfig, String packageName) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
+    public boolean setSoftApConfiguration(SoftApConfiguration softApConfig, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public void notifyUserOfApBandConversion(String packageName) {
         throw new UnsupportedOperationException();
     }
@@ -385,6 +409,16 @@
     }
 
     @Override
+    public byte[] retrieveSoftApBackupData() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void restoreSoftApBackupData(byte[] data) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
         throw new UnsupportedOperationException();
     }
@@ -513,19 +547,6 @@
         throw new UnsupportedOperationException();
     }
 
-    /** @deprecated replaced by {@link #registerScanResultsCallback(IScanResultsCallback)} */
-    @Deprecated
-    public void registerScanResultsListener(
-            IBinder binder, IScanResultsListener listener, int listenerIdentifier) {
-        throw new UnsupportedOperationException();
-    }
-
-    /** @deprecated replaced by {@link #unregisterScanResultsCallback(IScanResultsCallback)} */
-    @Deprecated
-    public void unregisterScanResultsListener(int listenerIdentifier) {
-        throw new UnsupportedOperationException();
-    }
-
     @Override
     public void registerScanResultsCallback(IScanResultsCallback callback) {
         throw new UnsupportedOperationException();
diff --git a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
index 949b479..b8d3e41 100644
--- a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
@@ -46,6 +46,10 @@
         assertThat(original.getSsid()).isEqualTo("ssid");
         assertThat(original.getBssid()).isEqualTo(MacAddress.fromString("11:22:33:44:55:66"));
         assertThat(original.getWpa2Passphrase()).isNull();
+        assertThat(original.getSecurityType()).isEqualTo(SoftApConfiguration.SECURITY_TYPE_OPEN);
+        assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
+        assertThat(original.getChannel()).isEqualTo(0);
+        assertThat(original.isHiddenSsid()).isEqualTo(false);
 
         SoftApConfiguration unparceled = parcelUnparcel(original);
         assertThat(unparceled).isNotSameAs(original);
@@ -64,6 +68,39 @@
                 .setWpa2Passphrase("secretsecret")
                 .build();
         assertThat(original.getWpa2Passphrase()).isEqualTo("secretsecret");
+        assertThat(original.getSecurityType()).isEqualTo(
+                SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+        assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
+        assertThat(original.getChannel()).isEqualTo(0);
+        assertThat(original.isHiddenSsid()).isEqualTo(false);
+
+
+        SoftApConfiguration unparceled = parcelUnparcel(original);
+        assertThat(unparceled).isNotSameAs(original);
+        assertThat(unparceled).isEqualTo(original);
+        assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
+
+        SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
+        assertThat(copy).isNotSameAs(original);
+        assertThat(copy).isEqualTo(original);
+        assertThat(copy.hashCode()).isEqualTo(original.hashCode());
+    }
+
+    @Test
+    public void testWpa2WithBandAndChannelAndHiddenNetwork() {
+        SoftApConfiguration original = new SoftApConfiguration.Builder()
+                .setWpa2Passphrase("secretsecret")
+                .setBand(SoftApConfiguration.BAND_ANY)
+                .setChannel(149)
+                .setHiddenSsid(true)
+                .build();
+        assertThat(original.getWpa2Passphrase()).isEqualTo("secretsecret");
+        assertThat(original.getSecurityType()).isEqualTo(
+                SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+        assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_ANY);
+        assertThat(original.getChannel()).isEqualTo(149);
+        assertThat(original.isHiddenSsid()).isEqualTo(true);
+
 
         SoftApConfiguration unparceled = parcelUnparcel(original);
         assertThat(unparceled).isNotSameAs(original);
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 8cdcba6..f92d38c 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -16,15 +16,31 @@
 
 package android.net.wifi;
 
+import static android.net.wifi.WifiManager.ActionListener;
+import static android.net.wifi.WifiManager.BUSY;
+import static android.net.wifi.WifiManager.ERROR;
 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC;
 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_NO_CHANNEL;
 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_TETHERING_DISALLOWED;
 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.REQUEST_REGISTERED;
+import static android.net.wifi.WifiManager.NOT_AUTHORIZED;
+import static android.net.wifi.WifiManager.OnWifiActivityEnergyInfoListener;
 import static android.net.wifi.WifiManager.SAP_START_FAILURE_GENERAL;
+import static android.net.wifi.WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS;
+import static android.net.wifi.WifiManager.STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION;
+import static android.net.wifi.WifiManager.TxPacketCountListener;
 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
 import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
+import static android.net.wifi.WifiManager.WIFI_FEATURE_DPP;
+import static android.net.wifi.WifiManager.WIFI_FEATURE_OWE;
+import static android.net.wifi.WifiManager.WIFI_FEATURE_P2P;
+import static android.net.wifi.WifiManager.WIFI_FEATURE_PASSPOINT;
+import static android.net.wifi.WifiManager.WIFI_FEATURE_SCANNER;
+import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SAE;
+import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SUITE_B;
+import static android.net.wifi.WifiManager.WpsCallback;
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
@@ -50,6 +66,7 @@
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
+import android.app.ActivityManager;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.net.DhcpInfo;
@@ -70,6 +87,7 @@
 import android.os.HandlerExecutor;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.connectivity.WifiActivityEnergyInfo;
 import android.os.test.TestLooper;
 
 import androidx.test.filters.SmallTest;
@@ -112,16 +130,19 @@
     @Mock TrafficStateCallback mTrafficStateCallback;
     @Mock NetworkRequestMatchCallback mNetworkRequestMatchCallback;
     @Mock OnWifiUsabilityStatsListener mOnWifiUsabilityStatsListener;
+    @Mock OnWifiActivityEnergyInfoListener mOnWifiActivityEnergyInfoListener;
     @Mock SuggestionConnectionStatusListener mListener;
     @Mock Runnable mRunnable;
     @Mock Executor mExecutor;
     @Mock Executor mAnotherExecutor;
+    @Mock ActivityManager mActivityManager;
 
     private Handler mHandler;
     private TestLooper mLooper;
     private WifiManager mWifiManager;
     private WifiNetworkSuggestion mWifiNetworkSuggestion;
     private ScanResultsCallback mScanResultsCallback;
+    private WifiActivityEnergyInfo mWifiActivityEnergyInfo;
 
     @Before
     public void setUp() throws Exception {
@@ -140,6 +161,7 @@
                 mRunnable.run();
             }
         };
+        mWifiActivityEnergyInfo = new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0);
     }
 
     /**
@@ -181,6 +203,33 @@
     }
 
     /**
+     * Check the call to startSoftAp calls WifiService to startSoftAp with the provided
+     * WifiConfiguration.  Verify that the return value is propagated to the caller.
+     */
+    @Test
+    public void testStartTetheredHotspotCallsServiceWithSoftApConfig() throws Exception {
+        SoftApConfiguration mSoftApConfig = new SoftApConfiguration.Builder().build();
+        when(mWifiService.startTetheredHotspot(eq(mSoftApConfig))).thenReturn(true);
+        assertTrue(mWifiManager.startTetheredHotspot(mSoftApConfig));
+
+        when(mWifiService.startTetheredHotspot(eq(mSoftApConfig))).thenReturn(false);
+        assertFalse(mWifiManager.startTetheredHotspot(mSoftApConfig));
+    }
+
+    /**
+     * Check the call to startSoftAp calls WifiService to startSoftAp with a null config.  Verify
+     * that the return value is propagated to the caller.
+     */
+    @Test
+    public void testStartTetheredHotspotCallsServiceWithNullConfig() throws Exception {
+        when(mWifiService.startTetheredHotspot(eq(null))).thenReturn(true);
+        assertTrue(mWifiManager.startTetheredHotspot(null));
+
+        when(mWifiService.startTetheredHotspot(eq(null))).thenReturn(false);
+        assertFalse(mWifiManager.startTetheredHotspot(null));
+    }
+
+    /**
      * Test creation of a LocalOnlyHotspotReservation and verify that close properly calls
      * WifiService.stopLocalOnlyHotspot.
      */
@@ -1040,7 +1089,7 @@
     }
 
 
-    class WpsCallbackTester extends WifiManager.WpsCallback {
+    class WpsCallbackTester extends WpsCallback {
         public boolean mStarted = false;
         public boolean mSucceeded = false;
         public boolean mFailed = false;
@@ -1072,7 +1121,7 @@
         WpsCallbackTester wpsCallback = new WpsCallbackTester();
         mWifiManager.startWps(null, wpsCallback);
         assertTrue(wpsCallback.mFailed);
-        assertEquals(WifiManager.ERROR, wpsCallback.mFailureCode);
+        assertEquals(ERROR, wpsCallback.mFailureCode);
         assertFalse(wpsCallback.mStarted);
         assertFalse(wpsCallback.mSucceeded);
         verifyNoMoreInteractions(mWifiService);
@@ -1095,7 +1144,7 @@
         WpsCallbackTester wpsCallback = new WpsCallbackTester();
         mWifiManager.cancelWps(wpsCallback);
         assertTrue(wpsCallback.mFailed);
-        assertEquals(WifiManager.ERROR, wpsCallback.mFailureCode);
+        assertEquals(ERROR, wpsCallback.mFailureCode);
         assertFalse(wpsCallback.mStarted);
         assertFalse(wpsCallback.mSucceeded);
         verifyNoMoreInteractions(mWifiService);
@@ -1148,6 +1197,43 @@
     }
 
     /**
+     * Verify that a successful call properly returns true.
+     */
+    @Test
+    public void testSetSoftApConfigurationSuccessReturnsTrue() throws Exception {
+        SoftApConfiguration apConfig = new SoftApConfiguration.Builder().build();
+
+        when(mWifiService.setSoftApConfiguration(eq(apConfig), eq(TEST_PACKAGE_NAME)))
+                .thenReturn(true);
+        assertTrue(mWifiManager.setSoftApConfiguration(apConfig));
+    }
+
+    /**
+     * Verify that a failed call properly returns false.
+     */
+    @Test
+    public void testSetSoftApConfigurationFailureReturnsFalse() throws Exception {
+        SoftApConfiguration apConfig = new SoftApConfiguration.Builder().build();
+
+        when(mWifiService.setSoftApConfiguration(eq(apConfig), eq(TEST_PACKAGE_NAME)))
+                .thenReturn(false);
+        assertFalse(mWifiManager.setSoftApConfiguration(apConfig));
+    }
+
+    /**
+     * Verify Exceptions are rethrown when underlying calls to WifiService throw exceptions.
+     */
+    @Test
+    public void testSetSoftApConfigurationRethrowsException() throws Exception {
+        doThrow(new SecurityException()).when(mWifiService).setSoftApConfiguration(any(), any());
+
+        try {
+            mWifiManager.setSoftApConfiguration(new SoftApConfiguration.Builder().build());
+            fail("setWifiApConfiguration should rethrow Exceptions from WifiService");
+        } catch (SecurityException e) { }
+    }
+
+    /**
      * Check the call to startScan calls WifiService.
      */
     @Test
@@ -1371,13 +1457,13 @@
     public void addGetRemoveNetworkSuggestions() throws Exception {
         List<WifiNetworkSuggestion> testList = new ArrayList<>();
         when(mWifiService.addNetworkSuggestions(any(List.class), anyString(),
-                nullable(String.class))).thenReturn(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS);
+                nullable(String.class))).thenReturn(STATUS_NETWORK_SUGGESTIONS_SUCCESS);
         when(mWifiService.removeNetworkSuggestions(any(List.class), anyString())).thenReturn(
-                WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS);
+                STATUS_NETWORK_SUGGESTIONS_SUCCESS);
         when(mWifiService.getNetworkSuggestions(anyString()))
                 .thenReturn(testList);
 
-        assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
+        assertEquals(STATUS_NETWORK_SUGGESTIONS_SUCCESS,
                 mWifiManager.addNetworkSuggestions(testList));
         verify(mWifiService).addNetworkSuggestions(anyList(), eq(TEST_PACKAGE_NAME),
                 nullable(String.class));
@@ -1385,7 +1471,7 @@
         assertEquals(testList, mWifiManager.getNetworkSuggestions());
         verify(mWifiService).getNetworkSuggestions(eq(TEST_PACKAGE_NAME));
 
-        assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
+        assertEquals(STATUS_NETWORK_SUGGESTIONS_SUCCESS,
                 mWifiManager.removeNetworkSuggestions(new ArrayList<>()));
         verify(mWifiService).removeNetworkSuggestions(anyList(), eq(TEST_PACKAGE_NAME));
     }
@@ -1395,8 +1481,15 @@
      */
     @Test
     public void getMaxNumberOfNetworkSuggestionsPerApp() {
-        assertEquals(WifiManager.NETWORK_SUGGESTIONS_MAX_PER_APP,
-                mWifiManager.getMaxNumberOfNetworkSuggestionsPerApp());
+        when(mContext.getSystemServiceName(ActivityManager.class))
+                .thenReturn(Context.ACTIVITY_SERVICE);
+        when(mContext.getSystemService(Context.ACTIVITY_SERVICE))
+                .thenReturn(mActivityManager);
+        when(mActivityManager.isLowRamDevice()).thenReturn(true);
+        assertEquals(256, mWifiManager.getMaxNumberOfNetworkSuggestionsPerApp());
+
+        when(mActivityManager.isLowRamDevice()).thenReturn(false);
+        assertEquals(1024, mWifiManager.getMaxNumberOfNetworkSuggestionsPerApp());
     }
 
     /**
@@ -1437,24 +1530,15 @@
     }
 
     /**
-     * Defined for testing purpose.
-     */
-    class SynchronousExecutor implements Executor {
-        public void execute(Runnable r) {
-            r.run();
-        }
-    }
-
-    /**
      * Test behavior of isEnhancedOpenSupported
      */
     @Test
     public void testIsEnhancedOpenSupported() throws Exception {
         when(mWifiService.getSupportedFeatures())
-                .thenReturn(new Long(WifiManager.WIFI_FEATURE_OWE));
+                .thenReturn(new Long(WIFI_FEATURE_OWE));
         assertTrue(mWifiManager.isEnhancedOpenSupported());
         when(mWifiService.getSupportedFeatures())
-                .thenReturn(new Long(~WifiManager.WIFI_FEATURE_OWE));
+                .thenReturn(new Long(~WIFI_FEATURE_OWE));
         assertFalse(mWifiManager.isEnhancedOpenSupported());
     }
 
@@ -1464,10 +1548,10 @@
     @Test
     public void testIsWpa3SaeSupported() throws Exception {
         when(mWifiService.getSupportedFeatures())
-                .thenReturn(new Long(WifiManager.WIFI_FEATURE_WPA3_SAE));
+                .thenReturn(new Long(WIFI_FEATURE_WPA3_SAE));
         assertTrue(mWifiManager.isWpa3SaeSupported());
         when(mWifiService.getSupportedFeatures())
-                .thenReturn(new Long(~WifiManager.WIFI_FEATURE_WPA3_SAE));
+                .thenReturn(new Long(~WIFI_FEATURE_WPA3_SAE));
         assertFalse(mWifiManager.isWpa3SaeSupported());
     }
 
@@ -1477,10 +1561,10 @@
     @Test
     public void testIsWpa3SuiteBSupported() throws Exception {
         when(mWifiService.getSupportedFeatures())
-                .thenReturn(new Long(WifiManager.WIFI_FEATURE_WPA3_SUITE_B));
+                .thenReturn(new Long(WIFI_FEATURE_WPA3_SUITE_B));
         assertTrue(mWifiManager.isWpa3SuiteBSupported());
         when(mWifiService.getSupportedFeatures())
-                .thenReturn(new Long(~WifiManager.WIFI_FEATURE_WPA3_SUITE_B));
+                .thenReturn(new Long(~WIFI_FEATURE_WPA3_SUITE_B));
         assertFalse(mWifiManager.isWpa3SuiteBSupported());
     }
 
@@ -1490,10 +1574,10 @@
     @Test
     public void testIsEasyConnectSupported() throws Exception {
         when(mWifiService.getSupportedFeatures())
-                .thenReturn(new Long(WifiManager.WIFI_FEATURE_DPP));
+                .thenReturn(new Long(WIFI_FEATURE_DPP));
         assertTrue(mWifiManager.isEasyConnectSupported());
         when(mWifiService.getSupportedFeatures())
-                .thenReturn(new Long(~WifiManager.WIFI_FEATURE_DPP));
+                .thenReturn(new Long(~WIFI_FEATURE_DPP));
         assertFalse(mWifiManager.isEasyConnectSupported());
     }
 
@@ -1602,9 +1686,9 @@
     @Test
     public void testGetSupportedFeatures() throws Exception {
         long supportedFeatures =
-                WifiManager.WIFI_FEATURE_SCANNER
-                        | WifiManager.WIFI_FEATURE_PASSPOINT
-                        | WifiManager.WIFI_FEATURE_P2P;
+                WIFI_FEATURE_SCANNER
+                        | WIFI_FEATURE_PASSPOINT
+                        | WIFI_FEATURE_P2P;
         when(mWifiService.getSupportedFeatures())
                 .thenReturn(Long.valueOf(supportedFeatures));
 
@@ -1624,15 +1708,55 @@
     }
 
     /**
-     * Test behavior of {@link WifiManager#getControllerActivityEnergyInfo()}
+     * Tests that passing a null Executor to {@link WifiManager#getWifiActivityEnergyInfoAsync}
+     * throws an exception.
      */
-    @Test
-    public void testGetControllerActivityEnergyInfo() throws Exception {
-        WifiActivityEnergyInfo activityEnergyInfo =
-                new WifiActivityEnergyInfo(5, 3, 3, new long[]{5L, 5L, 5L}, 5, 5, 5, 5);
-        when(mWifiService.reportActivityInfo()).thenReturn(activityEnergyInfo);
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetWifiActivityInfoNullExecutor() throws Exception {
+        mWifiManager.getWifiActivityEnergyInfoAsync(null, mOnWifiActivityEnergyInfoListener);
+    }
 
-        assertEquals(activityEnergyInfo, mWifiManager.getControllerActivityEnergyInfo());
+    /**
+     * Tests that passing a null listener to {@link WifiManager#getWifiActivityEnergyInfoAsync}
+     * throws an exception.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetWifiActivityInfoNullListener() throws Exception {
+        mWifiManager.getWifiActivityEnergyInfoAsync(mExecutor, null);
+    }
+
+    /** Tests that the listener runs on the correct Executor. */
+    @Test
+    public void testGetWifiActivityInfoRunsOnCorrectExecutor() throws Exception {
+        mWifiManager.getWifiActivityEnergyInfoAsync(mExecutor, mOnWifiActivityEnergyInfoListener);
+        ArgumentCaptor<IOnWifiActivityEnergyInfoListener> listenerCaptor =
+                ArgumentCaptor.forClass(IOnWifiActivityEnergyInfoListener.class);
+        verify(mWifiService).getWifiActivityEnergyInfoAsync(listenerCaptor.capture());
+        IOnWifiActivityEnergyInfoListener listener = listenerCaptor.getValue();
+        listener.onWifiActivityEnergyInfo(mWifiActivityEnergyInfo);
+        verify(mExecutor).execute(any());
+
+        // ensure that the executor is only triggered once
+        listener.onWifiActivityEnergyInfo(mWifiActivityEnergyInfo);
+        verify(mExecutor).execute(any());
+    }
+
+    /** Tests that the correct listener runs. */
+    @Test
+    public void testGetWifiActivityInfoRunsCorrectListener() throws Exception {
+        int[] flag = {0};
+        mWifiManager.getWifiActivityEnergyInfoAsync(
+                new SynchronousExecutor(), info -> flag[0]++);
+        ArgumentCaptor<IOnWifiActivityEnergyInfoListener> listenerCaptor =
+                ArgumentCaptor.forClass(IOnWifiActivityEnergyInfoListener.class);
+        verify(mWifiService).getWifiActivityEnergyInfoAsync(listenerCaptor.capture());
+        IOnWifiActivityEnergyInfoListener listener = listenerCaptor.getValue();
+        listener.onWifiActivityEnergyInfo(mWifiActivityEnergyInfo);
+        assertEquals(1, flag[0]);
+
+        // ensure that the listener is only triggered once
+        listener.onWifiActivityEnergyInfo(mWifiActivityEnergyInfo);
+        assertEquals(1, flag[0]);
     }
 
     /**
@@ -1692,11 +1816,11 @@
     }
 
     /**
-     * Test behavior of {@link WifiManager#connect(int, WifiManager.ActionListener)}
+     * Test behavior of {@link WifiManager#connect(int, ActionListener)}
      */
     @Test
     public void testConnectWithListener() throws Exception {
-        WifiManager.ActionListener externalListener = mock(WifiManager.ActionListener.class);
+        ActionListener externalListener = mock(ActionListener.class);
         mWifiManager.connect(TEST_NETWORK_ID, externalListener);
 
         ArgumentCaptor<IActionListener> binderListenerCaptor =
@@ -1711,43 +1835,43 @@
         verify(externalListener).onSuccess();
 
         // Trigger on failure.
-        binderListenerCaptor.getValue().onFailure(WifiManager.BUSY);
+        binderListenerCaptor.getValue().onFailure(BUSY);
         mLooper.dispatchAll();
-        verify(externalListener).onFailure(WifiManager.BUSY);
+        verify(externalListener).onFailure(BUSY);
     }
 
     /**
-     * Test behavior of {@link WifiManager#connect(int, WifiManager.ActionListener)}
+     * Test behavior of {@link WifiManager#connect(int, ActionListener)}
      */
     @Test
     public void testConnectWithListenerHandleSecurityException() throws Exception {
         doThrow(new SecurityException()).when(mWifiService)
                 .connect(eq(null), anyInt(), any(IBinder.class),
                         any(IActionListener.class), anyInt());
-        WifiManager.ActionListener externalListener = mock(WifiManager.ActionListener.class);
+        ActionListener externalListener = mock(ActionListener.class);
         mWifiManager.connect(TEST_NETWORK_ID, externalListener);
 
         mLooper.dispatchAll();
-        verify(externalListener).onFailure(WifiManager.NOT_AUTHORIZED);
+        verify(externalListener).onFailure(NOT_AUTHORIZED);
     }
 
     /**
-     * Test behavior of {@link WifiManager#connect(int, WifiManager.ActionListener)}
+     * Test behavior of {@link WifiManager#connect(int, ActionListener)}
      */
     @Test
     public void testConnectWithListenerHandleRemoteException() throws Exception {
         doThrow(new RemoteException()).when(mWifiService)
                 .connect(eq(null), anyInt(), any(IBinder.class),
                         any(IActionListener.class), anyInt());
-        WifiManager.ActionListener externalListener = mock(WifiManager.ActionListener.class);
+        ActionListener externalListener = mock(ActionListener.class);
         mWifiManager.connect(TEST_NETWORK_ID, externalListener);
 
         mLooper.dispatchAll();
-        verify(externalListener).onFailure(WifiManager.ERROR);
+        verify(externalListener).onFailure(ERROR);
     }
 
     /**
-     * Test behavior of {@link WifiManager#connect(int, WifiManager.ActionListener)}
+     * Test behavior of {@link WifiManager#connect(int, ActionListener)}
      */
     @Test
     public void testConnectWithoutListener() throws Exception {
@@ -1759,12 +1883,12 @@
     }
 
     /**
-     * Test behavior of {@link WifiManager#getTxPacketCount(WifiManager.TxPacketCountListener)}
+     * Test behavior of {@link WifiManager#getTxPacketCount(TxPacketCountListener)}
      */
     @Test
     public void testGetTxPacketCount() throws Exception {
-        WifiManager.TxPacketCountListener externalListener =
-                mock(WifiManager.TxPacketCountListener.class);
+        TxPacketCountListener externalListener =
+                mock(TxPacketCountListener.class);
         mWifiManager.getTxPacketCount(externalListener);
 
         ArgumentCaptor<ITxPacketCountListener> binderListenerCaptor =
@@ -1779,9 +1903,9 @@
         verify(externalListener).onSuccess(6);
 
         // Trigger on failure.
-        binderListenerCaptor.getValue().onFailure(WifiManager.BUSY);
+        binderListenerCaptor.getValue().onFailure(BUSY);
         mLooper.dispatchAll();
-        verify(externalListener).onFailure(WifiManager.BUSY);
+        verify(externalListener).onFailure(BUSY);
     }
 
     /**
@@ -1883,7 +2007,7 @@
      */
     @Test
     public void testAddSuggestionConnectionStatusListenerAndReceiveEvent() throws Exception {
-        int errorCode = WifiManager.STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION;
+        int errorCode = STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION;
         ArgumentCaptor<ISuggestionConnectionStatusListener.Stub> callbackCaptor =
                 ArgumentCaptor.forClass(ISuggestionConnectionStatusListener.Stub.class);
         Executor executor = new SynchronousExecutor();
@@ -1899,7 +2023,7 @@
      */
     @Test
     public void testAddSuggestionConnectionStatusListenerWithTheTargetExecutor() throws Exception {
-        int errorCode = WifiManager.STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION;
+        int errorCode = STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION;
         ArgumentCaptor<ISuggestionConnectionStatusListener.Stub> callbackCaptor =
                 ArgumentCaptor.forClass(ISuggestionConnectionStatusListener.Stub.class);
         mWifiManager.addSuggestionConnectionStatusListener(mExecutor, mListener);
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
index e6eece8..adc41f0 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
@@ -208,7 +208,7 @@
         PatternMatcher ssidPattern =
                 new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
         Pair<MacAddress, MacAddress> bssidPattern =
-                Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+                Pair.create(WifiManager.ALL_ZEROS_MAC_ADDRESS, WifiManager.ALL_ZEROS_MAC_ADDRESS);
         WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
         wificonfigurationNetworkSpecifier.allowedKeyManagement
                 .set(WifiConfiguration.KeyMgmt.WPA_PSK);
@@ -299,7 +299,7 @@
         PatternMatcher ssidPattern =
                 new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
         Pair<MacAddress, MacAddress> bssidPattern =
-                Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+                Pair.create(WifiManager.ALL_ZEROS_MAC_ADDRESS, WifiManager.ALL_ZEROS_MAC_ADDRESS);
         WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
         wificonfigurationNetworkSpecifier.allowedKeyManagement
                 .set(WifiConfiguration.KeyMgmt.WPA_PSK);
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
index edb43d8..1619744 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
@@ -65,8 +65,10 @@
         assertEquals(Process.myUid(), wifiNetworkSpecifier.requestorUid);
         assertEquals(TEST_SSID, wifiNetworkSpecifier.ssidPatternMatcher.getPath());
         assertEquals(PATTERN_PREFIX, wifiNetworkSpecifier.ssidPatternMatcher.getType());
-        assertEquals(MacAddress.ALL_ZEROS_ADDRESS, wifiNetworkSpecifier.bssidPatternMatcher.first);
-        assertEquals(MacAddress.ALL_ZEROS_ADDRESS, wifiNetworkSpecifier.bssidPatternMatcher.second);
+        assertEquals(WifiManager.ALL_ZEROS_MAC_ADDRESS,
+                wifiNetworkSpecifier.bssidPatternMatcher.first);
+        assertEquals(WifiManager.ALL_ZEROS_MAC_ADDRESS,
+                wifiNetworkSpecifier.bssidPatternMatcher.second);
         assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
                 .get(WifiConfiguration.KeyMgmt.NONE));
     }
@@ -210,7 +212,8 @@
     @Test(expected = IllegalStateException.class)
     public void testWifiNetworkSpecifierBuilderWithMatchAllBssidPattern() {
         new WifiNetworkSpecifier.Builder()
-                .setBssidPattern(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS)
+                .setBssidPattern(WifiManager.ALL_ZEROS_MAC_ADDRESS,
+                        WifiManager.ALL_ZEROS_MAC_ADDRESS)
                 .build();
     }
 
@@ -265,7 +268,7 @@
     @Test(expected = IllegalStateException.class)
     public void testWifiNetworkSpecifierBuilderWithMatchNoneBssidPattern3() {
         new WifiNetworkSpecifier.Builder()
-                .setBssid(MacAddress.ALL_ZEROS_ADDRESS)
+                .setBssid(WifiManager.ALL_ZEROS_MAC_ADDRESS)
                 .build();
     }
 
@@ -513,7 +516,8 @@
 
         WifiNetworkSpecifier specifier2 =
                 new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
-                        Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS),
+                        Pair.create(WifiManager.ALL_ZEROS_MAC_ADDRESS,
+                                WifiManager.ALL_ZEROS_MAC_ADDRESS),
                         wifiConfiguration,
                         TEST_UID, TEST_PACKAGE_NAME);
 
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index 6990089..04aaa0b 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -22,7 +22,6 @@
 import android.net.wifi.hotspot2.PasspointConfiguration;
 import android.net.wifi.hotspot2.PasspointTestUtils;
 import android.os.Parcel;
-import android.os.Process;
 
 import androidx.test.filters.SmallTest;
 
@@ -35,8 +34,6 @@
 public class WifiNetworkSuggestionTest {
     private static final int TEST_UID = 45677;
     private static final int TEST_UID_OTHER = 45673;
-    private static final String TEST_PACKAGE_NAME = "com.test.packagename";
-    private static final String TEST_PACKAGE_NAME_OTHER = "com.test.packagenameother";
     private static final String TEST_SSID = "\"Test123\"";
     private static final String TEST_BSSID = "12:12:12:12:12:12";
     private static final String TEST_SSID_1 = "\"Test1234\"";
@@ -55,7 +52,6 @@
                 .setIsAppInteractionRequired(true)
                 .build();
 
-        assertEquals(Process.myUid(), suggestion.suggestorUid);
         assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
         assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
                 .get(WifiConfiguration.KeyMgmt.NONE));
@@ -64,12 +60,13 @@
         assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE,
                 suggestion.wifiConfiguration.meteredOverride);
         assertEquals(-1, suggestion.wifiConfiguration.priority);
+        assertEquals(false, suggestion.isUserAllowedToManuallyConnect);
     }
 
     /**
      * Validate correctness of WifiNetworkSuggestion object created by
      * {@link WifiNetworkSuggestion.Builder#build()} for WPA_EAP network which requires
-     * app interaction and has a priority of zero set.
+     * app interaction, not share credential and has a priority of zero set.
      */
     @Test
     public void
@@ -78,6 +75,7 @@
                 .setSsid(TEST_SSID)
                 .setWpa2Passphrase(TEST_PRESHARED_KEY)
                 .setIsAppInteractionRequired(true)
+                .setIsUserAllowedToManuallyConnect(false)
                 .setPriority(0)
                 .build();
 
@@ -91,6 +89,7 @@
         assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE,
                 suggestion.wifiConfiguration.meteredOverride);
         assertEquals(0, suggestion.wifiConfiguration.priority);
+        assertEquals(false, suggestion.isUserAllowedToManuallyConnect);
     }
 
     /**
@@ -118,6 +117,7 @@
         assertEquals(WifiConfiguration.METERED_OVERRIDE_METERED,
                 suggestion.wifiConfiguration.meteredOverride);
         assertEquals(-1, suggestion.wifiConfiguration.priority);
+        assertTrue(suggestion.isUserAllowedToManuallyConnect);
     }
 
     /**
@@ -138,6 +138,7 @@
                 .get(WifiConfiguration.KeyMgmt.OWE));
         assertNull(suggestion.wifiConfiguration.preSharedKey);
         assertTrue(suggestion.wifiConfiguration.requirePMF);
+        assertFalse(suggestion.isUserAllowedToManuallyConnect);
     }
 
     /**
@@ -149,6 +150,7 @@
         WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
                 .setSsid(TEST_SSID)
                 .setWpa3Passphrase(TEST_PRESHARED_KEY)
+                .setIsUserAllowedToManuallyConnect(true)
                 .build();
 
         assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
@@ -157,6 +159,7 @@
         assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
                 suggestion.wifiConfiguration.preSharedKey);
         assertTrue(suggestion.wifiConfiguration.requirePMF);
+        assertTrue(suggestion.isUserAllowedToManuallyConnect);
     }
 
 
@@ -186,6 +189,7 @@
         assertNull(suggestion.wifiConfiguration.preSharedKey);
         // allowedSuiteBCiphers are set according to the loaded certificate and cannot be tested
         // here.
+        assertTrue(suggestion.isUserAllowedToManuallyConnect);
     }
 
     /**
@@ -205,6 +209,7 @@
         assertTrue(suggestion.isAppInteractionRequired);
         assertEquals(suggestion.wifiConfiguration.meteredOverride,
                 WifiConfiguration.METERED_OVERRIDE_METERED);
+        assertTrue(suggestion.isUserAllowedToManuallyConnect);
     }
 
     /**
@@ -285,7 +290,7 @@
     public void testWifiNetworkSuggestionBuilderWithInvalidAllZeroBssid() {
         new WifiNetworkSuggestion.Builder()
                 .setSsid(TEST_SSID)
-                .setBssid(MacAddress.ALL_ZEROS_ADDRESS)
+                .setBssid(WifiManager.ALL_ZEROS_MAC_ADDRESS)
                 .build();
     }
 
@@ -439,7 +444,7 @@
         configuration.BSSID = TEST_BSSID;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion(
-                configuration, null, false, true, TEST_UID, TEST_PACKAGE_NAME);
+                configuration, null, false, true, true);
 
         Parcel parcelW = Parcel.obtain();
         suggestion.writeToParcel(parcelW, 0);
@@ -506,16 +511,14 @@
         configuration.BSSID = TEST_BSSID;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
         WifiNetworkSuggestion suggestion =
-                new WifiNetworkSuggestion(configuration, null, true, false, TEST_UID,
-                        TEST_PACKAGE_NAME);
+                new WifiNetworkSuggestion(configuration, null, true, false, true);
 
         WifiConfiguration configuration1 = new WifiConfiguration();
         configuration1.SSID = TEST_SSID;
         configuration1.BSSID = TEST_BSSID;
         configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
         WifiNetworkSuggestion suggestion1 =
-                new WifiNetworkSuggestion(configuration1, null, false, true, TEST_UID,
-                        TEST_PACKAGE_NAME);
+                new WifiNetworkSuggestion(configuration1, null, false, true, true);
 
         assertEquals(suggestion, suggestion1);
         assertEquals(suggestion.hashCode(), suggestion1.hashCode());
@@ -531,15 +534,13 @@
         configuration.SSID = TEST_SSID;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion =
-                new WifiNetworkSuggestion(configuration, null, false, false, TEST_UID,
-                        TEST_PACKAGE_NAME);
+                new WifiNetworkSuggestion(configuration, null, false, false, true);
 
         WifiConfiguration configuration1 = new WifiConfiguration();
         configuration1.SSID = TEST_SSID_1;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion1 =
-                new WifiNetworkSuggestion(configuration1, null, false, false, TEST_UID,
-                        TEST_PACKAGE_NAME);
+                new WifiNetworkSuggestion(configuration1, null, false, false, true);
 
         assertNotEquals(suggestion, suggestion1);
     }
@@ -555,15 +556,13 @@
         configuration.BSSID = TEST_BSSID;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion =
-                new WifiNetworkSuggestion(configuration, null,  false, false, TEST_UID,
-                        TEST_PACKAGE_NAME);
+                new WifiNetworkSuggestion(configuration, null,  false, false, true);
 
         WifiConfiguration configuration1 = new WifiConfiguration();
         configuration1.SSID = TEST_SSID;
         configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion1 =
-                new WifiNetworkSuggestion(configuration1, null, false, false, TEST_UID,
-                        TEST_PACKAGE_NAME);
+                new WifiNetworkSuggestion(configuration1, null, false, false, true);
 
         assertNotEquals(suggestion, suggestion1);
     }
@@ -578,57 +577,18 @@
         configuration.SSID = TEST_SSID;
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
         WifiNetworkSuggestion suggestion =
-                new WifiNetworkSuggestion(configuration, null, false, false, TEST_UID,
-                        TEST_PACKAGE_NAME);
+                new WifiNetworkSuggestion(configuration, null, false, false, true);
 
         WifiConfiguration configuration1 = new WifiConfiguration();
         configuration1.SSID = TEST_SSID;
         configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
         WifiNetworkSuggestion suggestion1 =
-                new WifiNetworkSuggestion(configuration1, null, false, false, TEST_UID,
-                        TEST_PACKAGE_NAME);
+                new WifiNetworkSuggestion(configuration1, null, false, false, true);
 
         assertNotEquals(suggestion, suggestion1);
     }
 
     /**
-     * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same
-     * SSID, BSSID and key mgmt, but different UID.
-     */
-    @Test
-    public void testWifiNetworkSuggestionEqualsFailsWhenUidIsDifferent() {
-        WifiConfiguration configuration = new WifiConfiguration();
-        configuration.SSID = TEST_SSID;
-        configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
-        WifiNetworkSuggestion suggestion =
-                new WifiNetworkSuggestion(configuration, null, false, false, TEST_UID,
-                        TEST_PACKAGE_NAME);
-
-        WifiNetworkSuggestion suggestion1 =
-                new WifiNetworkSuggestion(configuration, null, false, false, TEST_UID_OTHER,
-                        TEST_PACKAGE_NAME);
-
-        assertNotEquals(suggestion, suggestion1);
-    }
-
-    /**
-     * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same
-     * SSID, BSSID and key mgmt, but different package name.
-     */
-    @Test
-    public void testWifiNetworkSuggestionEqualsFailsWhenPackageNameIsDifferent() {
-        WifiConfiguration configuration = new WifiConfiguration();
-        configuration.SSID = TEST_SSID;
-        configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
-        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion(
-                configuration, null, false, false, TEST_UID, TEST_PACKAGE_NAME);
-
-        WifiNetworkSuggestion suggestion1 = new WifiNetworkSuggestion(
-                configuration, null, false, false, TEST_UID, TEST_PACKAGE_NAME_OTHER);
-
-        assertNotEquals(suggestion, suggestion1);
-    }
-    /**
      * Check NetworkSuggestion equals returns {@code true} for 2 Passpoint network suggestions with
      * same FQDN.
      */
@@ -664,4 +624,17 @@
                 .build();
         assertNotEquals(suggestion, suggestion1);
     }
+
+    /**
+     * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
+     * when {@link WifiNetworkSuggestion.Builder#setIsUserAllowedToManuallyConnect(boolean)} to
+     * true on a open network suggestion.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testSetIsUserAllowedToManuallyConnectToWithOpenNetwork() {
+        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+                .setSsid(TEST_SSID)
+                .setIsUserAllowedToManuallyConnect(true)
+                .build();
+    }
 }
diff --git a/wifi/tests/src/android/net/wifi/WifiScannerTest.java b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
index f4fa38b..fa4f711 100644
--- a/wifi/tests/src/android/net/wifi/WifiScannerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
@@ -22,7 +22,9 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.validateMockitoUsage;
@@ -33,6 +35,7 @@
 import android.net.wifi.WifiScanner.PnoSettings;
 import android.net.wifi.WifiScanner.PnoSettings.PnoNetwork;
 import android.net.wifi.WifiScanner.ScanData;
+import android.net.wifi.WifiScanner.ScanListener;
 import android.net.wifi.WifiScanner.ScanSettings;
 import android.os.Bundle;
 import android.os.Handler;
@@ -51,8 +54,10 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
 
 import java.util.Arrays;
+import java.util.concurrent.Executor;
 
 /**
  * Unit tests for {@link android.net.wifi.WifiScanner}.
@@ -63,19 +68,29 @@
     private Context mContext;
     @Mock
     private IWifiScanner mService;
+    @Spy
+    private Executor mExecutor = new SynchronousExecutor();
+    @Mock
+    private ScanListener mScanListener;
+    @Mock
+    private WifiScanner.ParcelableScanData mParcelableScanData;
+    private ScanData[] mScanData = {};
 
     private static final boolean TEST_PNOSETTINGS_IS_CONNECTED = false;
     private static final int TEST_PNOSETTINGS_MIN_5GHZ_RSSI = -60;
     private static final int TEST_PNOSETTINGS_MIN_2GHZ_RSSI = -70;
+    private static final int TEST_PNOSETTINGS_MIN_6GHZ_RSSI = -55;
     private static final int TEST_PNOSETTINGS_INITIAL_SCORE_MAX = 50;
     private static final int TEST_PNOSETTINGS_CURRENT_CONNECTION_BONUS = 10;
     private static final int TEST_PNOSETTINGS_SAME_NETWORK_BONUS = 11;
     private static final int TEST_PNOSETTINGS_SECURE_BONUS = 12;
     private static final int TEST_PNOSETTINGS_BAND_5GHZ_BONUS = 13;
+    private static final int TEST_PNOSETTINGS_BAND_6GHZ_BONUS = 15;
     private static final String TEST_SSID_1 = "TEST1";
     private static final String TEST_SSID_2 = "TEST2";
     private static final int[] TEST_FREQUENCIES_1 = {};
-    private static final int[] TEST_FREQUENCIES_2 = {2500, 5124};
+    private static final int[] TEST_FREQUENCIES_2 = {2500, 5124, 6245};
+    private static final String DESCRIPTION_NOT_AUTHORIZED = "Not authorized";
 
     private WifiScanner mWifiScanner;
     private TestLooper mLooper;
@@ -95,6 +110,7 @@
         when(mService.getMessenger()).thenReturn(mBidirectionalAsyncChannelServer.getMessenger());
         mWifiScanner = new WifiScanner(mContext, mService, mLooper.getLooper());
         mLooper.dispatchAll();
+        when(mParcelableScanData.getResults()).thenReturn(mScanData);
     }
 
     /**
@@ -111,7 +127,7 @@
     @Test
     public void verifyScanSettingsParcelWithBand() throws Exception {
         ScanSettings writeSettings = new ScanSettings();
-        writeSettings.type = WifiScanner.TYPE_LOW_POWER;
+        writeSettings.type = WifiScanner.SCAN_TYPE_LOW_POWER;
         writeSettings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;
 
         ScanSettings readSettings = parcelWriteRead(writeSettings);
@@ -126,7 +142,7 @@
     @Test
     public void verifyScanSettingsParcelWithChannels() throws Exception {
         ScanSettings writeSettings = new ScanSettings();
-        writeSettings.type = WifiScanner.TYPE_HIGH_ACCURACY;
+        writeSettings.type = WifiScanner.SCAN_TYPE_HIGH_ACCURACY;
         writeSettings.band = WifiScanner.WIFI_BAND_UNSPECIFIED;
         writeSettings.channels = new WifiScanner.ChannelSpec[] {
                 new WifiScanner.ChannelSpec(5),
@@ -169,11 +185,13 @@
         pnoSettings.isConnected = TEST_PNOSETTINGS_IS_CONNECTED;
         pnoSettings.min5GHzRssi = TEST_PNOSETTINGS_MIN_5GHZ_RSSI;
         pnoSettings.min24GHzRssi = TEST_PNOSETTINGS_MIN_2GHZ_RSSI;
+        pnoSettings.min6GHzRssi = TEST_PNOSETTINGS_MIN_6GHZ_RSSI;
         pnoSettings.initialScoreMax = TEST_PNOSETTINGS_INITIAL_SCORE_MAX;
         pnoSettings.currentConnectionBonus = TEST_PNOSETTINGS_CURRENT_CONNECTION_BONUS;
         pnoSettings.sameNetworkBonus = TEST_PNOSETTINGS_SAME_NETWORK_BONUS;
         pnoSettings.secureBonus = TEST_PNOSETTINGS_SECURE_BONUS;
         pnoSettings.band5GHzBonus = TEST_PNOSETTINGS_BAND_5GHZ_BONUS;
+        pnoSettings.band6GHzBonus = TEST_PNOSETTINGS_BAND_6GHZ_BONUS;
 
         Parcel parcel = Parcel.obtain();
         pnoSettings.writeToParcel(parcel, 0);
@@ -186,6 +204,7 @@
         assertEquals(TEST_PNOSETTINGS_IS_CONNECTED, pnoSettingsDeserialized.isConnected);
         assertEquals(TEST_PNOSETTINGS_MIN_5GHZ_RSSI, pnoSettingsDeserialized.min5GHzRssi);
         assertEquals(TEST_PNOSETTINGS_MIN_2GHZ_RSSI, pnoSettingsDeserialized.min24GHzRssi);
+        assertEquals(TEST_PNOSETTINGS_MIN_6GHZ_RSSI, pnoSettingsDeserialized.min6GHzRssi);
         assertEquals(TEST_PNOSETTINGS_INITIAL_SCORE_MAX, pnoSettingsDeserialized.initialScoreMax);
         assertEquals(TEST_PNOSETTINGS_CURRENT_CONNECTION_BONUS,
                 pnoSettingsDeserialized.currentConnectionBonus);
@@ -193,6 +212,7 @@
                 pnoSettingsDeserialized.sameNetworkBonus);
         assertEquals(TEST_PNOSETTINGS_SECURE_BONUS, pnoSettingsDeserialized.secureBonus);
         assertEquals(TEST_PNOSETTINGS_BAND_5GHZ_BONUS, pnoSettingsDeserialized.band5GHzBonus);
+        assertEquals(TEST_PNOSETTINGS_BAND_6GHZ_BONUS, pnoSettingsDeserialized.band6GHzBonus);
 
         // Test parsing of PnoNetwork
         assertEquals(pnoSettings.networkList.length, pnoSettingsDeserialized.networkList.length);
@@ -243,13 +263,13 @@
 
 
     /**
-     * Test behavior of {@link WifiScanner#startScan(ScanSettings, WifiScanner.ScanListener)}
+     * Test behavior of {@link WifiScanner#startScan(ScanSettings, ScanListener)}
      * @throws Exception
      */
     @Test
     public void testStartScan() throws Exception {
         ScanSettings scanSettings = new ScanSettings();
-        WifiScanner.ScanListener scanListener = mock(WifiScanner.ScanListener.class);
+        ScanListener scanListener = mock(ScanListener.class);
 
         mWifiScanner.startScan(scanSettings, scanListener);
         mLooper.dispatchAll();
@@ -273,13 +293,13 @@
     }
 
     /**
-     * Test behavior of {@link WifiScanner#stopScan(WifiScanner.ScanListener)}
+     * Test behavior of {@link WifiScanner#stopScan(ScanListener)}
      * @throws Exception
      */
     @Test
     public void testStopScan() throws Exception {
         ScanSettings scanSettings = new ScanSettings();
-        WifiScanner.ScanListener scanListener = mock(WifiScanner.ScanListener.class);
+        ScanListener scanListener = mock(ScanListener.class);
 
         mWifiScanner.startScan(scanSettings, scanListener);
         mLooper.dispatchAll();
@@ -302,13 +322,13 @@
     }
 
     /**
-     * Test behavior of {@link WifiScanner#startScan(ScanSettings, WifiScanner.ScanListener)}
+     * Test behavior of {@link WifiScanner#startScan(ScanSettings, ScanListener)}
      * @throws Exception
      */
     @Test
     public void testStartScanListenerOnSuccess() throws Exception {
         ScanSettings scanSettings = new ScanSettings();
-        WifiScanner.ScanListener scanListener = mock(WifiScanner.ScanListener.class);
+        ScanListener scanListener = mock(ScanListener.class);
 
         mWifiScanner.startScan(scanSettings, scanListener);
         mLooper.dispatchAll();
@@ -332,13 +352,13 @@
     }
 
     /**
-     * Test behavior of {@link WifiScanner#startScan(ScanSettings, WifiScanner.ScanListener)}
+     * Test behavior of {@link WifiScanner#startScan(ScanSettings, ScanListener)}
      * @throws Exception
      */
     @Test
     public void testStartScanListenerOnResults() throws Exception {
         ScanSettings scanSettings = new ScanSettings();
-        WifiScanner.ScanListener scanListener = mock(WifiScanner.ScanListener.class);
+        ScanListener scanListener = mock(ScanListener.class);
 
         mWifiScanner.startScan(scanSettings, scanListener);
         mLooper.dispatchAll();
@@ -425,7 +445,7 @@
     }
 
     /**
-     * Test behavior of {@link WifiScanner#stopPnoScan(WifiScanner.ScanListener)}
+     * Test behavior of {@link WifiScanner#stopPnoScan(ScanListener)}
      * WifiScanner.PnoScanListener)}
      * @throws Exception
      */
@@ -480,4 +500,134 @@
         assertEquals(scanData.getResults().length, readScanData.getResults().length);
         assertEquals(scanData.getResults()[0].SSID, readScanData.getResults()[0].SSID);
     }
+
+    /** Tests that upon registration success, {@link ScanListener#onSuccess()} is called. */
+    @Test
+    public void testRegisterScanListenerSuccess() throws Exception {
+        mWifiScanner.registerScanListener(mExecutor, mScanListener);
+        mLooper.dispatchAll();
+
+        ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
+        verify(mHandler).handleMessage(messageArgumentCaptor.capture());
+        Message sentMessage = messageArgumentCaptor.getValue();
+        assertNotNull(sentMessage);
+
+        assertEquals(1, mBidirectionalAsyncChannelServer.getClientMessengers().size());
+        Messenger scannerMessenger =
+                mBidirectionalAsyncChannelServer.getClientMessengers().iterator().next();
+
+        Message responseMessage = Message.obtain();
+        responseMessage.what = WifiScanner.CMD_OP_SUCCEEDED;
+        responseMessage.arg2 = sentMessage.arg2;
+        scannerMessenger.send(responseMessage);
+        mLooper.dispatchAll();
+
+        verify(mExecutor).execute(any());
+        verify(mScanListener).onSuccess();
+    }
+
+    /**
+     * Tests that upon registration failed, {@link ScanListener#onFailure(int, String)} is called.
+     */
+    @Test
+    public void testRegisterScanListenerFailed() throws Exception {
+        mWifiScanner.registerScanListener(mExecutor, mScanListener);
+        mLooper.dispatchAll();
+
+        ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
+        verify(mHandler).handleMessage(messageArgumentCaptor.capture());
+        Message sentMessage = messageArgumentCaptor.getValue();
+        assertNotNull(sentMessage);
+
+        assertEquals(1, mBidirectionalAsyncChannelServer.getClientMessengers().size());
+        Messenger scannerMessenger =
+                mBidirectionalAsyncChannelServer.getClientMessengers().iterator().next();
+
+        {
+            Message responseMessage = Message.obtain();
+            responseMessage.what = WifiScanner.CMD_OP_FAILED;
+            responseMessage.arg2 = sentMessage.arg2;
+            responseMessage.obj = new WifiScanner.OperationResult(
+                    WifiScanner.REASON_NOT_AUTHORIZED, DESCRIPTION_NOT_AUTHORIZED);
+            scannerMessenger.send(responseMessage);
+            mLooper.dispatchAll();
+        }
+
+        verify(mExecutor).execute(any());
+        verify(mScanListener).onFailure(
+                WifiScanner.REASON_NOT_AUTHORIZED, DESCRIPTION_NOT_AUTHORIZED);
+
+        // CMD_OP_FAILED should have caused the removal of the listener, verify this
+        {
+            Message responseMessage = Message.obtain();
+            responseMessage.what = WifiScanner.CMD_SCAN_RESULT;
+            responseMessage.arg2 = sentMessage.arg2;
+            responseMessage.obj = mParcelableScanData;
+            scannerMessenger.send(responseMessage);
+            mLooper.dispatchAll();
+        }
+        // execute() called once before, not called again
+        verify(mExecutor, times(1)).execute(any());
+        // onResults() never triggered
+        verify(mScanListener, never()).onResults(any());
+    }
+
+    /**
+     * Tests that when the ScanListener is triggered, {@link ScanListener#onResults(ScanData[])}
+     * is called.
+     */
+    @Test
+    public void testRegisterScanListenerReceiveScanResults() throws Exception {
+        mWifiScanner.registerScanListener(mExecutor, mScanListener);
+        mLooper.dispatchAll();
+
+        ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
+        verify(mHandler).handleMessage(messageArgumentCaptor.capture());
+        Message sentMessage = messageArgumentCaptor.getValue();
+        assertNotNull(sentMessage);
+
+        assertEquals(1, mBidirectionalAsyncChannelServer.getClientMessengers().size());
+        Messenger scannerMessenger =
+                mBidirectionalAsyncChannelServer.getClientMessengers().iterator().next();
+
+        Message responseMessage = Message.obtain();
+        responseMessage.what = WifiScanner.CMD_SCAN_RESULT;
+        responseMessage.arg2 = sentMessage.arg2;
+        responseMessage.obj = mParcelableScanData;
+        scannerMessenger.send(responseMessage);
+        mLooper.dispatchAll();
+
+        verify(mExecutor).execute(any());
+        verify(mScanListener).onResults(mScanData);
+    }
+
+    /**
+     * Tests that after unregistering a scan listener, {@link ScanListener#onResults(ScanData[])}
+     * is not called.
+     */
+    @Test
+    public void testUnregisterScanListener() throws Exception {
+        mWifiScanner.registerScanListener(mExecutor, mScanListener);
+        mWifiScanner.unregisterScanListener(mScanListener);
+        mLooper.dispatchAll();
+
+        assertEquals(1, mBidirectionalAsyncChannelServer.getClientMessengers().size());
+        Messenger scannerMessenger =
+                mBidirectionalAsyncChannelServer.getClientMessengers().iterator().next();
+
+        ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
+        verify(mHandler, times(2)).handleMessage(messageArgumentCaptor.capture());
+        Message sentMessage = messageArgumentCaptor.getValue();
+        assertNotNull(sentMessage);
+
+        Message responseMessage = Message.obtain();
+        responseMessage.what = WifiScanner.CMD_SCAN_RESULT;
+        responseMessage.obj = mParcelableScanData;
+        responseMessage.arg2 = sentMessage.arg2;
+        scannerMessenger.send(responseMessage);
+        mLooper.dispatchAll();
+
+        verify(mExecutor, never()).execute(any());
+        verify(mScanListener, never()).onResults(mScanData);
+    }
 }
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index 3483ff8..65fbf5b 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -36,6 +36,7 @@
 import android.content.pm.PackageManager;
 import android.net.MacAddress;
 import android.net.wifi.RttManager;
+import android.net.wifi.util.HexEncoding;
 import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
@@ -44,8 +45,6 @@
 
 import androidx.test.filters.SmallTest;
 
-import libcore.util.HexEncoding;
-
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -579,12 +578,15 @@
         collector.checkThat("mMasterPreference", 0,
                 equalTo(configRequest.mMasterPreference));
         collector.checkThat("mSupport5gBand", true, equalTo(configRequest.mSupport5gBand));
-        collector.checkThat("mDiscoveryWindowInterval.length", 2,
+        collector.checkThat("mSupport6gBand", false, equalTo(configRequest.mSupport6gBand));
+        collector.checkThat("mDiscoveryWindowInterval.length", 3,
                 equalTo(configRequest.mDiscoveryWindowInterval.length));
         collector.checkThat("mDiscoveryWindowInterval[2.4GHz]", ConfigRequest.DW_INTERVAL_NOT_INIT,
                 equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_24GHZ]));
         collector.checkThat("mDiscoveryWindowInterval[5Hz]", ConfigRequest.DW_INTERVAL_NOT_INIT,
                 equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ]));
+        collector.checkThat("mDiscoveryWindowInterval[6Hz]", ConfigRequest.DW_INTERVAL_NOT_INIT,
+                equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_6GHZ]));
     }
 
     @Test
@@ -593,12 +595,16 @@
         final int clusterLow = 5;
         final int masterPreference = 55;
         final boolean supportBand5g = true;
+        final boolean supportBand6g = true;
         final int dwWindow5GHz = 3;
+        final int dwWindow6GHz = 4;
 
         ConfigRequest configRequest = new ConfigRequest.Builder().setClusterHigh(clusterHigh)
                 .setClusterLow(clusterLow).setMasterPreference(masterPreference)
                 .setSupport5gBand(supportBand5g)
+                .setSupport6gBand(supportBand6g)
                 .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ, dwWindow5GHz)
+                .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_6GHZ, dwWindow6GHz)
                 .build();
 
         collector.checkThat("mClusterHigh", clusterHigh, equalTo(configRequest.mClusterHigh));
@@ -606,12 +612,15 @@
         collector.checkThat("mMasterPreference", masterPreference,
                 equalTo(configRequest.mMasterPreference));
         collector.checkThat("mSupport5gBand", supportBand5g, equalTo(configRequest.mSupport5gBand));
-        collector.checkThat("mDiscoveryWindowInterval.length", 2,
+        collector.checkThat("mSupport6gBand", supportBand6g, equalTo(configRequest.mSupport6gBand));
+        collector.checkThat("mDiscoveryWindowInterval.length", 3,
                 equalTo(configRequest.mDiscoveryWindowInterval.length));
         collector.checkThat("mDiscoveryWindowInterval[2.4GHz]", ConfigRequest.DW_INTERVAL_NOT_INIT,
                 equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_24GHZ]));
         collector.checkThat("mDiscoveryWindowInterval[5GHz]", dwWindow5GHz,
                 equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ]));
+        collector.checkThat("mDiscoveryWindowInterval[6GHz]", dwWindow6GHz,
+                equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_6GHZ]));
     }
 
     @Test(expected = IllegalArgumentException.class)
@@ -690,14 +699,18 @@
         final int clusterLow = 25;
         final int masterPreference = 177;
         final boolean supportBand5g = true;
+        final boolean supportBand6g = false;
         final int dwWindow24GHz = 1;
         final int dwWindow5GHz = 5;
+        final int dwWindow6GHz = 4;
 
         ConfigRequest configRequest = new ConfigRequest.Builder().setClusterHigh(clusterHigh)
                 .setClusterLow(clusterLow).setMasterPreference(masterPreference)
                 .setSupport5gBand(supportBand5g)
+                .setSupport6gBand(supportBand6g)
                 .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_24GHZ, dwWindow24GHz)
                 .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ, dwWindow5GHz)
+                .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_6GHZ, dwWindow6GHz)
                 .build();
 
         Parcel parcelW = Parcel.obtain();
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java b/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java
index 43ee249..2ded849 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java
@@ -19,7 +19,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.net.wifi.WifiSsid;
 import android.os.Parcel;
@@ -56,7 +55,6 @@
     private static final String TEST_NAI = "test.access.com";
     private static final List<Integer> TEST_METHOD_LIST =
             Arrays.asList(OsuProvider.METHOD_SOAP_XML_SPP);
-    private static final Icon TEST_ICON = Icon.createWithData(new byte[10], 0, 10);
 
     /**
      * Verify parcel write and read consistency for the given {@link OsuProvider}.
@@ -82,7 +80,7 @@
      */
     @Test
     public void verifyParcelWithEmptyProviderInfo() throws Exception {
-        verifyParcel(new OsuProvider((WifiSsid) null, null, null, null, null, null, null));
+        verifyParcel(new OsuProvider((WifiSsid) null, null, null, null, null, null));
     }
 
     /**
@@ -93,7 +91,7 @@
     @Test
     public void verifyParcelWithFullProviderInfo() throws Exception {
         verifyParcel(new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAMES,
-                TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST, TEST_ICON));
+                TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST));
     }
 
     /**
@@ -102,7 +100,7 @@
      */
     @Test
     public void verifyCopyConstructorWithNullSource() throws Exception {
-        OsuProvider expected = new OsuProvider((WifiSsid) null, null, null, null, null, null, null);
+        OsuProvider expected = new OsuProvider((WifiSsid) null, null, null, null, null, null);
         assertEquals(expected, new OsuProvider(null));
     }
 
@@ -114,7 +112,7 @@
     @Test
     public void verifyCopyConstructorWithValidSource() throws Exception {
         OsuProvider source = new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAMES,
-                TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST, TEST_ICON);
+                TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST);
         assertEquals(source, new OsuProvider(source));
     }
 
@@ -126,7 +124,7 @@
     @Test
     public void verifyGetters() throws Exception {
         OsuProvider provider = new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAMES,
-                TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST, TEST_ICON);
+                TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST);
 
         assertTrue(TEST_SSID.equals(provider.getOsuSsid()));
         assertTrue(TEST_FRIENDLY_NAME.equals(provider.getFriendlyName()));
@@ -135,6 +133,5 @@
         assertTrue(TEST_SERVER_URI.equals(provider.getServerUri()));
         assertTrue(TEST_NAI.equals(provider.getNetworkAccessIdentifier()));
         assertTrue(TEST_METHOD_LIST.equals(provider.getMethodList()));
-        assertTrue(TEST_ICON.sameAs(provider.getIcon()));
     }
 }
diff --git a/wifi/tests/src/android/net/wifi/util/HexEncodingTest.java b/wifi/tests/src/android/net/wifi/util/HexEncodingTest.java
new file mode 100644
index 0000000..0d75138
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/util/HexEncodingTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.util;
+
+import static android.net.wifi.util.HexEncoding.decode;
+import static android.net.wifi.util.HexEncoding.encode;
+import static android.net.wifi.util.HexEncoding.encodeToString;
+
+import junit.framework.TestCase;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Locale;
+
+/** Copied from {@link libcore.libcore.util.HexEncodingTest}. */
+public class HexEncodingTest extends TestCase {
+
+    public void testEncodeByte() {
+        Object[][] testCases = new Object[][]{
+                {0x01, "01"},
+                {0x09, "09"},
+                {0x0A, "0A"},
+                {0x0F, "0F"},
+                {0x10, "10"},
+                {0x1F, "1F"},
+                {0x20, "20"},
+                {0x7F, "7F"},
+                {0x80, "80"},
+                {0xFF, "FF"},
+        };
+        for (Object[] testCase : testCases) {
+            Number toEncode = (Number) testCase[0];
+            String expected = (String) testCase[1];
+
+            String actualUpper = encodeToString(toEncode.byteValue(), true /* upperCase */);
+            assertEquals(upper(expected), actualUpper);
+
+            String actualLower = encodeToString(toEncode.byteValue(), false /* upperCase */);
+            assertEquals(lower(expected), actualLower);
+        }
+    }
+
+    public void testEncodeBytes() {
+        Object[][] testCases = new Object[][]{
+                {"avocados".getBytes(StandardCharsets.UTF_8), "61766F6361646F73"},
+        };
+
+        for (Object[] testCase : testCases) {
+            byte[] bytes = (byte[]) testCase[0];
+            String encodedLower = lower((String) testCase[1]);
+            String encodedUpper = upper((String) testCase[1]);
+
+            assertArraysEqual(encodedUpper.toCharArray(), encode(bytes));
+            assertArraysEqual(encodedUpper.toCharArray(), encode(bytes, true /* upperCase */));
+            assertArraysEqual(encodedLower.toCharArray(), encode(bytes, false /* upperCase */));
+
+            assertArraysEqual(bytes, decode(encode(bytes), false /* allowSingleChar */));
+
+            // Make sure we can handle lower case hex encodings as well.
+            assertArraysEqual(bytes,
+                    decode(encodedLower.toCharArray(), false /* allowSingleChar */));
+        }
+    }
+
+    public void testDecode_allow4Bit() {
+        assertArraysEqual(new byte[]{6}, decode("6".toCharArray(), true));
+        assertArraysEqual(new byte[]{6, 0x76}, decode("676".toCharArray(), true));
+    }
+
+    public void testDecode_disallow4Bit() {
+        try {
+            decode("676".toCharArray(), false /* allowSingleChar */);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    public void testDecode_invalid() {
+        try {
+            decode("DEADBARD".toCharArray(), false /* allowSingleChar */);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+
+        // This demonstrates a difference in behaviour from apache commons : apache
+        // commons uses Character.isDigit and would successfully decode a string with
+        // arabic and devanagari characters.
+        try {
+            decode("६१٧٥٥F6361646F73".toCharArray(), false /* allowSingleChar */);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+
+        try {
+            decode("#%6361646F73".toCharArray(), false /* allowSingleChar */);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    private static void assertArraysEqual(char[] lhs, char[] rhs) {
+        assertEquals(new String(lhs), new String(rhs));
+    }
+
+    private static void assertArraysEqual(byte[] lhs, byte[] rhs) {
+        assertEquals(Arrays.toString(lhs), Arrays.toString(rhs));
+    }
+
+    private static String lower(String string) {
+        return string.toLowerCase(Locale.ROOT);
+    }
+
+    private static String upper(String string) {
+        return string.toUpperCase(Locale.ROOT);
+    }
+}